feat(complex-matcher): support numbers (#32)

This commit is contained in:
Julien Fontanet 2018-01-17 12:06:44 +01:00 committed by GitHub
parent be4ca0eede
commit bdddea2e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 10 deletions

View File

@ -1,6 +1,7 @@
import * as CM from './' import * as CM from './'
export const pattern = 'foo !"\\\\ \\"" name:|(wonderwoman batman) hasCape?' export const pattern =
'foo !"\\\\ \\"" name:|(wonderwoman batman) hasCape? age:32'
export const ast = new CM.And([ export const ast = new CM.And([
new CM.String('foo'), new CM.String('foo'),
@ -10,4 +11,5 @@ export const ast = new CM.And([
new CM.Or([new CM.String('wonderwoman'), new CM.String('batman')]) new CM.Or([new CM.String('wonderwoman'), new CM.String('batman')])
), ),
new CM.TruthyProperty('hasCape'), new CM.TruthyProperty('hasCape'),
new CM.Property('age', new CM.Number(32)),
]) ])

View File

@ -141,6 +141,23 @@ export class Not extends Node {
} }
} }
export class NumberNode extends Node {
constructor (value) {
super()
this.value = value
}
match (value) {
return value === this.value
}
toString () {
return String(this.value)
}
}
export { NumberNode as Number }
export class Property extends Node { export class Property extends Node {
constructor (name, child) { constructor (name, child) {
super() super()
@ -159,9 +176,10 @@ export class Property extends Node {
} }
const escapeChar = char => '\\' + char const escapeChar = char => '\\' + char
const formatString = value => isRawString(value) const formatString = value =>
? value Number.isNaN(+value)
: `"${value.replace(/\\|"/g, escapeChar)}"` ? isRawString(value) ? value : `"${value.replace(/\\|"/g, escapeChar)}"`
: `"${value}"`
export class StringNode extends Node { export class StringNode extends Node {
constructor (value) { constructor (value) {
@ -214,14 +232,15 @@ export class TruthyProperty extends Node {
// terms = null || term+ // terms = null || term+
// *null = /$/ // *null = /$/
// term = ws (and | or | not | property | truthyProperty | string) ws // term = ws (and | or | not | property | truthyProperty | numberOrString) ws
// ws = ' '* // ws = ' '*
// *and = "(" terms ")" // *and = "(" terms ")"
// *or = "|" ws "(" terms ")" // *or = "|" ws "(" terms ")"
// *not = "!" term // *not = "!" term
// *property = string ws ":" term // *property = string ws ":" term
// *truthyProperty = string ws "?" // *truthyProperty = string ws "?"
// *string = quotedString | rawString // numberOrString = string
// string = quotedString | rawString
// quotedString = "\"" ( /[^"\]/ | "\\\\" | "\\\"" )+ // quotedString = "\"" ( /[^"\]/ | "\\\\" | "\\\"" )+
// rawString = /[a-z0-9-_.]+/i // rawString = /[a-z0-9-_.]+/i
export const parse = invoke(() => { export const parse = invoke(() => {
@ -263,7 +282,7 @@ export const parse = invoke(() => {
parseNot() || parseNot() ||
parseProperty() || parseProperty() ||
parseTruthyProperty() || parseTruthyProperty() ||
parseString() parseNumberOrString()
if (child) { if (child) {
parseWs() parseWs()
return child return child
@ -308,16 +327,27 @@ export const parse = invoke(() => {
input[i++] === ':' && input[i++] === ':' &&
(child = parseTerm()) (child = parseTerm())
) { ) {
return new Property(name.value, child) return new Property(name, child)
} }
}) })
const parseNumberOrString = () => {
let str = parseQuotedString()
if (str !== undefined) {
return new StringNode(str)
}
str = parseRawString()
if (str !== undefined) {
const asNum = +str
return Number.isNaN(asNum) ? new StringNode(str) : new NumberNode(asNum)
}
}
const parseString = () => { const parseString = () => {
let value let value
if ( if (
(value = parseQuotedString()) !== undefined || (value = parseQuotedString()) !== undefined ||
(value = parseRawString()) !== undefined (value = parseRawString()) !== undefined
) { ) {
return new StringNode(value) return value
} }
} }
const parseQuotedString = backtrace(() => { const parseQuotedString = backtrace(() => {
@ -350,7 +380,7 @@ export const parse = invoke(() => {
const parseTruthyProperty = backtrace(() => { const parseTruthyProperty = backtrace(() => {
let name let name
if ((name = parseString()) && parseWs() && input[i++] === '?') { if ((name = parseString()) && parseWs() && input[i++] === '?') {
return new TruthyProperty(name.value) return new TruthyProperty(name)
} }
}) })

View File

@ -24,6 +24,20 @@ describe('parse', () => {
it('supports an empty string', () => { it('supports an empty string', () => {
expect(parse('')).toEqual(new Null()) expect(parse('')).toEqual(new Null())
}) })
it('differentiate between numbers and numbers in strings', () => {
let node
node = parse('32')
expect(node.match(32)).toBe(true)
expect(node.match('32')).toBe(false)
expect(node.toString()).toBe('32')
node = parse('"32"')
expect(node.match(32)).toBe(false)
expect(node.match('32')).toBe(true)
expect(node.toString()).toBe('"32"')
})
}) })
describe('setPropertyClause', () => { describe('setPropertyClause', () => {