Skip to content
This repository was archived by the owner on Jun 9, 2025. It is now read-only.

Release 0.2.0 to follow SRL standard #5

Merged
merged 3 commits into from
Sep 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ JavaScript implementation of [Simple Regex](https://simple-regex.com/) :tada::ta
> Because of the JavaScript regex engine, there is something different from [Simple Regex](https://simple-regex.com/)
- NOT support `as` to assign capture name.
- NOT support `if already had/if not already had`
- NO `firstMatch`, since in JavaScript `lazy` means non-greedy (matching the fewest possible characters).
- NO `first match` and NO `all lazy`, since in JavaScript `lazy` means non-greedy (matching the fewest possible characters).

## Installation

Expand All @@ -26,21 +26,29 @@ The builder can agent `test/exec` method to the generated regex object. Or you c
```js
const SRL = require('srl')
const query = new SRL('letter exactly 3 times')
const regex = query.get() // /[a-z]{3}/

query.test('aaa') // true
query.exec('aaa') // [ 'aaa', index: 0, input: 'aaa' ]
query.isMatching('aaa') // true
query.getMatch('aaa') // [ 'aaa', index: 0, input: 'aaa' ]

query
.digit()
.neverOrMore()
.mustEnd()
.get() // /[a-z]{3}[0-9]*$/
.get() // /[a-z]{3}[0-9]*$/g
```

Required Node 6.0+ for the ES6 support, Or you can use [Babel](http://babeljs.io/) to support Node below 6.0.

Using [Webpack](http://webpack.github.io) and [babel-loader](https://github.com/babel/babel-loader) to pack it if want to use in browsers.
Using [Webpack](http://webpack.github.io) and [babel-loader](https://github.com/babel/babel-loader) to pack it if want to use in browsers.

## Additional

In SRL-JavaScript we apply `g` flag as default to follow the [Simple Regex](https://simple-regex.com/) "standard", so we provide more API to use regex conveniently.

- `isMatching` - Validate if the expression matches the given string.
- `getMatch` - Get first match of the given string, like run `regex.exec` once.
- `getMatches` - Get all matches of the given string, like a loop to run `regex.exec`.
- `removeModifier` - Remove specific flag.

## Development

Expand Down
68 changes: 63 additions & 5 deletions lib/Builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class Builder {
this._regEx = []

/** @var {string} _modifiers Raw modifier to apply on. */
this._modifiers = ''
this._modifiers = 'g'

/** @var {number} _lastMethodType Type of last method, to avoid invalid builds. */
this._lastMethodType = METHOD_TYPE_BEGIN
Expand Down Expand Up @@ -379,10 +379,6 @@ class Builder {
/* MODIFIER MAPPER */
/**********************************************************/

all() {
return this._addUniqueModifier('g')
}

multiLine() {
return this._addUniqueModifier('m')
}
Expand Down Expand Up @@ -486,6 +482,7 @@ class Builder {
this._regEx.push(condition)
return this
}

/**
* Validate method call. This will throw an exception if the called method makes no sense at this point.
* Will add the current type as the last method type.
Expand Down Expand Up @@ -619,6 +616,8 @@ class Builder {
}

/**
* Clone a new builder object.
*
* @return {Builder}
*/
clone() {
Expand All @@ -633,6 +632,19 @@ class Builder {
return clone
}

/**
* Remote specific flag.
*
* @param {string} flag
* @return {Builder}
*/
removeModifier(flag) {
this._modifiers = this._modifiers.replace(flag, '')
this._result = null

return this
}

/**********************************************************/
/* REGEX METHODS */
/**********************************************************/
Expand All @@ -645,6 +657,52 @@ class Builder {
const regexp = this.get()
return regexp.test.apply(regexp, arguments)
}

/**********************************************************/
/* ADDITIONAL METHODS */
/**********************************************************/

/**
* Just like test in RegExp, but reset lastIndex.
*
* @param {string} target
* @return {boolean}
*/
isMatching(target) {
const result = this.test(target)
this.get().lastIndex = 0
return result
}

/**
* Just like match in String, but reset lastIndex.
*
* @param {string} target
* @return {array|null}
*/
getMatch(target) {
const regex = this.get()
const result = regex.exec(target)
regex.lastIndex = 0
return result
}

/**
* Get all matches, just like loop for RegExp.exec.
* @param {string} target
*/
getMatches(target) {
const result = []
const regex = this.get()
let temp = null

while (temp = regex.exec(target)) {
result.push(temp)
}
regex.lastIndex = 0

return result
}
}

module.exports = Builder
1 change: 0 additions & 1 deletion lib/Language/Helpers/methodMatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const mapper = {
'new line': { 'class': SimpleMethod, 'method': 'newLine' },
'whitespace': { 'class': SimpleMethod, 'method': 'whitespace' },
'no whitespace': { 'class': SimpleMethod, 'method': 'noWhitespace' },
'all': { 'class': SimpleMethod, 'method': 'all' },
'anything': { 'class': SimpleMethod, 'method': 'any' },
'tab': { 'class': SimpleMethod, 'method': 'atb' },
'digit': { 'class': SimpleMethod, 'method': 'digit' },
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "srl",
"version": "0.1.0",
"version": "0.2.0",
"description": "Simple Regex Language",
"main": "lib/SRL.js",
"scripts": {
Expand Down
76 changes: 40 additions & 36 deletions test/builder-test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict'

const assert = require('assert')
const SRL = require('../lib/Builder')
const SRL = require('../')

describe('Builder Test', () => {
describe('Builder isMatching', () => {
it('Simple Phone Number Format', () => {
const regex = new SRL()
.startsWith()
Expand All @@ -15,12 +15,12 @@ describe('Builder Test', () => {
.digit().onceOrMore()
.mustEnd()

assert.ok(regex.test('+49 123-45'))
assert.ok(regex.exec('+492 1235-4'))
assert.ok(!regex.test('+49 123 45'))
assert.ok(!regex.exec('49 123-45'))
assert.ok(!regex.test('a+49 123-45'))
assert.ok(!regex.test('+49 123-45b'))
assert.ok(regex.isMatching('+49 123-45'))
assert.ok(regex.isMatching('+492 1235-4'))
assert.ok(!regex.isMatching('+49 123 45'))
assert.ok(!regex.isMatching('49 123-45'))
assert.ok(!regex.isMatching('a+49 123-45'))
assert.ok(!regex.isMatching('+49 123-45b'))
})

it('Simple Email Format', () => {
Expand All @@ -39,15 +39,14 @@ describe('Builder Test', () => {
.letter().atLeast(2)
.mustEnd()
.caseInsensitive()
.get() // Use get() to test resulting RegExp object.

assert.equal('sample@example.com'.match(regex)[0], 'sample@example.com')
assert.equal(regex.exec('super-He4vy.add+ress@top-Le.ve1.domains'), 'super-He4vy.add+ress@top-Le.ve1.domains')
assert.ok(!regex.test('sample.example.com'))
assert.ok(!regex.test('missing@tld'))
assert.ok(!regex.test('hav ing@spac.es'))
assert.ok(!regex.test('no@pe.123'))
assert.ok(!regex.test('invalid@email.com123'))

assert.equal(regex.getMatch('sample@example.com')[0], 'sample@example.com')
assert.equal(regex.getMatch('super-He4vy.add+ress@top-Le.ve1.domains')[0], 'super-He4vy.add+ress@top-Le.ve1.domains')
assert.ok(!regex.isMatching('sample.example.com'))
assert.ok(!regex.isMatching('missing@tld'))
assert.ok(!regex.isMatching('hav ing@spac.es'))
assert.ok(!regex.isMatching('no@pe.123'))
assert.ok(!regex.isMatching('invalid@email.com123'))
})

it('Capture Group', () => {
Expand All @@ -65,14 +64,13 @@ describe('Builder Test', () => {
query.letter().onceOrMore()
})
.literally('.')
.get()

assert.ok(regex.test('my favorite color: blue.'))
assert.ok(regex.test('my favorite colour is green.'))
assert.ok(!regex.test('my favorite colour is green!'))
assert.ok(regex.isMatching('my favorite color: blue.'))
assert.ok(regex.isMatching('my favorite colour is green.'))
assert.ok(!regex.isMatching('my favorite colour is green!'))

const testcase = 'my favorite colour is green. And my favorite color: yellow.'
const matches = testcase.match(regex)
const matches = regex.getMatch(testcase)
assert.equal(matches[1], 'green')
})

Expand All @@ -86,12 +84,12 @@ describe('Builder Test', () => {
.tab()
.mustEnd()
.multiLine()
.get()

const target = `
ba\t
aaabbb
`
assert.ok(regex.test(target))
assert.ok(regex.isMatching(target))

const regex2 = new SRL()
.startsWith()
Expand All @@ -101,10 +99,10 @@ describe('Builder Test', () => {
.onceOrMore()
.literally('b')
.mustEnd()
.get()

const target2 = `a
b`
assert.ok(regex2.test(target2))
assert.ok(regex2.isMatching(target2))
})

it('Replace', () => {
Expand Down Expand Up @@ -133,28 +131,25 @@ describe('Builder Test', () => {
.whitespace().optional()
.lazy()
})
.get()

const matches = ',, '.match(regex)
const matches = regex.getMatch(',, ')
assert.equal(matches[1], ',,')
assert.notEqual(matches[1], ',, ')

const regex2 = new SRL()
.literally(',')
.atLeast(1)
.lazy()
.get()

const matches2 = regex2.exec(',,,,,')
const matches2 = regex2.getMatch(',,,,,')
assert.equal(matches2[0], ',')
assert.notEqual(matches2[0], ',,,,,')

})

it('Global', () => {
it('Global as Default', () => {
const regex = new SRL()
.literally('a')
.all()
.get()

let count = 0
Expand All @@ -169,9 +164,18 @@ describe('Builder Test', () => {
.raw('b[a-z]r')
.raw(/\d+/)

assert.ok(regex.test('foobzr123'))
assert.ok(regex.test('foobar1'))
assert.ok(!regex.test('fooa'))
assert.ok(!regex.test('foobar'))
assert.ok(regex.isMatching('foobzr123'))
assert.ok(regex.isMatching('foobar1'))
assert.ok(!regex.isMatching('fooa'))
assert.ok(!regex.isMatching('foobar'))
})

it('Remove modifier', () => {
const regex = new SRL()
.literally('foo')
.removeModifier('g')
.get()

assert.deepEqual(regex, /(?:foo)/)
})
})
2 changes: 1 addition & 1 deletion test/cache-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('Cache', () => {
})

it('In interpreter', () => {
const RE = /(?:a)/
const RE = /(?:a)/g
const query = new Interpreter('Literally "a"')
assert.deepEqual(query.get(), RE)

Expand Down
Loading