regjsgen
Advanced tools
Comparing version 0.2.0 to 0.3.0
{ | ||
"name": "regjsgen", | ||
"version": "0.2.0", | ||
"description": "Generate `RegExp`s from RegJSParser’s AST", | ||
"homepage": "https://github.com/d10/regjsgen", | ||
"license": "MIT", | ||
"version": "0.3.0", | ||
"description": "Generate regular expressions from regjsparser’s AST.", | ||
"homepage": "https://github.com/demoneaux/regjsgen", | ||
"main": "regjsgen.js", | ||
@@ -15,20 +14,27 @@ "keywords": [ | ||
], | ||
"author": "Benjamin Tan <demoneaux@gmail.com> (https://d10.github.io/)", | ||
"contributors": [ | ||
"Benjamin Tan <demoneaux@gmail.com> (https://d10.github.io/)", | ||
"Mathias Bynens <mathias@qiwi.be> (https://mathiasbynens.be/)" | ||
"license": "MIT", | ||
"author": { | ||
"name": "Benjamin Tan", | ||
"url": "https://demoneaux.github.io/" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/demoneaux/regjsgen.git" | ||
}, | ||
"bugs": "https://github.com/demoneaux/regjsgen/issues", | ||
"files": [ | ||
"LICENSE", | ||
"regjsgen.js" | ||
], | ||
"repository": "d10/regjsgen", | ||
"scripts": { | ||
"test": "node test/test.js" | ||
"test": "node tests/tests.js", | ||
"coverage": "istanbul cover --report html tests/tests.js", | ||
"update-fixtures": "node tests/update-fixtures.js" | ||
}, | ||
"files": [ | ||
"LICENSE.txt", | ||
"regjsgen.js", | ||
"README.md" | ||
], | ||
"devDependencies": { | ||
"got": "~1.2.0", | ||
"jsesc": "~0.5.0" | ||
"coveralls": "^2.11.8", | ||
"istanbul": "~0.4.2", | ||
"regjsparser": "~0.2.0", | ||
"request": "^2.69.0" | ||
} | ||
} |
@@ -1,4 +0,4 @@ | ||
# RegJSGen | ||
# regjsgen [![Build status](https://travis-ci.org/demoneaux/regjsgen.svg?branch=master)](https://travis-ci.org/demoneaux/regjsgen) [![Code coverage status](https://coveralls.io/repos/github/demoneaux/regjsgen/badge.svg)](https://coveralls.io/github/demoneaux/regjsgen?branch=master) | ||
Generate `RegExp`s from [RegJSParser](https://github.com/jviereck/regjsparser)’s AST. | ||
Generate regular expressions from [regjsparser](https://github.com/jviereck/regjsparser)’s AST. | ||
@@ -11,51 +11,36 @@ ## Installation | ||
## Usage | ||
## API | ||
### `regjsgen.generate(ast)` | ||
This function accepts an abstract syntax tree representing a regular expression, and returns the generated regular expression string. | ||
```js | ||
var regjsparser = require('regjsparser'); | ||
var regjsgen = require('regjsgen'); | ||
// With `regjsparser` | ||
var regjsparser = require('regjsparser'); | ||
var regex = '^a$'; | ||
// Generate an AST with `regjsparser`. | ||
var ast = regjsparser.parse(regex); | ||
// Modify AST | ||
// ... | ||
// Regenerate `RegExp` | ||
// … | ||
// Generate `RegExp` string with `regjsgen`. | ||
regex = regjsgen.generate(ast); | ||
``` | ||
## See Also | ||
* [RegJSParser](https://github.com/jviereck/regjsparser) | ||
* [RegExp.js](https://github.com/jviereck/regexp.js) | ||
## Testing | ||
Run the command | ||
```bash | ||
npm test | ||
``` | ||
To create a new reference file, execute | ||
```bash | ||
node test/update-fixture.js | ||
``` | ||
from the repo top directory. | ||
## Support | ||
Tested in Node.js 0.8.26~0.10.30. | ||
Tested in Node.js 0.10.x, 0.12.x, 4.x and 5.x. | ||
## Author | ||
| [![twitter/demoneaux](http://gravatar.com/avatar/029b19dba521584d83398ada3ecf6131?s=70)](https://twitter.com/demoneaux "Follow @demoneaux on Twitter") | | ||
| [![twitter/demoneaux](https://gravatar.com/avatar/029b19dba521584d83398ada3ecf6131?s=70)](https://twitter.com/demoneaux "Follow @demoneaux on Twitter") | | ||
|---| | ||
| [Benjamin Tan](http://d10.github.io/) | | ||
| [Benjamin Tan](https://demoneaux.github.io/) | | ||
## Contributors | ||
| [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | | ||
| [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | | ||
|---| | ||
| [Mathias Bynens](http://mathiasbynens.be/) | | ||
| [Mathias Bynens](https://mathiasbynens.be/) | |
214
regjsgen.js
/*! | ||
* RegJSGen | ||
* Copyright 2014 Benjamin Tan <https://d10.github.io/> | ||
* Available under MIT license <http://d10.mit-license.org/> | ||
* regjsgen 0.3.0 | ||
* Copyright 2014-2016 Benjamin Tan <https://demoneaux.github.io/> | ||
* Available under MIT license <https://github.com/demoneaux/regjsgen/blob/master/LICENSE> | ||
*/ | ||
@@ -9,3 +9,3 @@ ;(function() { | ||
/** Used to determine if values are of the language type `Object` */ | ||
// Used to determine if values are of the language type `Object`. | ||
var objectTypes = { | ||
@@ -16,15 +16,12 @@ 'function': true, | ||
/** Used as a reference to the global object */ | ||
// Used as a reference to the global object. | ||
var root = (objectTypes[typeof window] && window) || this; | ||
/** Backup possible global object */ | ||
var oldRoot = root; | ||
/** Detect free variable `exports` */ | ||
// Detect free variable `exports`. | ||
var freeExports = objectTypes[typeof exports] && exports; | ||
/** Detect free variable `module` */ | ||
// Detect free variable `module`. | ||
var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; | ||
/** Detect free variable `global` from Node.js or Browserified code and use it as `root` */ | ||
// Detect free variable `global` from Node.js or Browserified code and use it as `root`. | ||
var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; | ||
@@ -35,6 +32,9 @@ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) { | ||
// Used to check objects for own properties. | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
/*--------------------------------------------------------------------------*/ | ||
/*! Based on https://mths.be/fromcodepoint v0.2.0 by @mathias */ | ||
// Generates strings based on the given code points. | ||
// Based on https://mths.be/fromcodepoint v0.2.0 by @mathias. | ||
var stringFromCharCode = String.fromCharCode; | ||
@@ -82,2 +82,6 @@ var floor = Math.floor; | ||
/*--------------------------------------------------------------------------*/ | ||
// Ensures that nodes have the correct types. | ||
var assertTypeRegexMap = {}; | ||
function assertType(type, expected) { | ||
@@ -89,8 +93,8 @@ if (expected.indexOf('|') == -1) { | ||
throw Error('Invalid node type: ' + type); | ||
throw Error('Invalid node type: ' + type + '; expected type: ' + expected); | ||
} | ||
expected = assertType.hasOwnProperty(expected) | ||
? assertType[expected] | ||
: (assertType[expected] = RegExp('^(?:' + expected + ')$')); | ||
expected = hasOwnProperty.call(assertTypeRegexMap, expected) | ||
? assertTypeRegexMap[expected] | ||
: (assertTypeRegexMap[expected] = RegExp('^(?:' + expected + ')$')); | ||
@@ -101,3 +105,3 @@ if (expected.test(type)) { | ||
throw Error('Invalid node type: ' + type); | ||
throw Error('Invalid node type: ' + type + '; expected types: ' + expected); | ||
} | ||
@@ -107,7 +111,8 @@ | ||
// Generates a regular expression string based on an AST. | ||
function generate(node) { | ||
var type = node.type; | ||
if (generate.hasOwnProperty(type) && typeof generate[type] == 'function') { | ||
return generate[type](node); | ||
if (hasOwnProperty.call(generators, type)) { | ||
return generators[type](node); | ||
} | ||
@@ -124,16 +129,11 @@ | ||
var terms = node.body, | ||
length = terms ? terms.length : 0; | ||
i = -1, | ||
length = terms.length, | ||
result = ''; | ||
if (length == 1) { | ||
return generateTerm(terms[0]); | ||
} else { | ||
var i = -1, | ||
result = ''; | ||
while (++i < length) { | ||
result += generateTerm(terms[i]); | ||
} | ||
while (++i < length) { | ||
result += generateTerm(terms[i]); | ||
} | ||
return result; | ||
} | ||
return result; | ||
} | ||
@@ -168,7 +168,6 @@ | ||
var classRanges = node.body, | ||
length = classRanges ? classRanges.length : 0; | ||
i = -1, | ||
length = classRanges.length, | ||
result = ''; | ||
var i = -1, | ||
result = '['; | ||
if (node.negative) { | ||
@@ -182,5 +181,3 @@ result += '^'; | ||
result += ']'; | ||
return result; | ||
return '[' + result + ']'; | ||
} | ||
@@ -194,2 +191,8 @@ | ||
function generateUnicodePropertyEscape(node) { | ||
assertType(node.type, 'unicodePropertyEscape'); | ||
return '\\' + (node.negative ? 'P' : 'p') + '{' + node.value + '}'; | ||
} | ||
function generateCharacterClassRange(node) { | ||
@@ -218,21 +221,14 @@ assertType(node.type, 'characterClassRange'); | ||
var body = node.body, | ||
length = body ? body.length : 0; | ||
i = -1, | ||
length = body.length, | ||
result = ''; | ||
if (length == 0) { | ||
throw Error('No body'); | ||
} else if (length == 1) { | ||
return generate(body[0]); | ||
} else { | ||
var i = -1, | ||
result = ''; | ||
while (++i < length) { | ||
if (i != 0) { | ||
result += '|'; | ||
} | ||
result += generate(body[i]); | ||
while (++i < length) { | ||
if (i != 0) { | ||
result += '|'; | ||
} | ||
result += generate(body[i]); | ||
} | ||
return result; | ||
} | ||
return result; | ||
} | ||
@@ -249,3 +245,3 @@ | ||
var result = '('; | ||
var result = ''; | ||
@@ -269,17 +265,10 @@ switch (node.behavior) { | ||
var body = node.body, | ||
length = body ? body.length : 0; | ||
i = -1, | ||
length = body.length; | ||
if (length == 1) { | ||
result += generate(body[0]); | ||
} else { | ||
var i = -1; | ||
while (++i < length) { | ||
result += generate(body[i]); | ||
} | ||
while (++i < length) { | ||
result += generate(body[i]); | ||
} | ||
result += ')'; | ||
return result; | ||
return '(' + result + ')'; | ||
} | ||
@@ -294,27 +283,16 @@ | ||
switch (max) { | ||
case undefined: | ||
case null: | ||
switch (min) { | ||
case 0: | ||
quantifier = '*' | ||
break; | ||
case 1: | ||
quantifier = '+'; | ||
break; | ||
default: | ||
quantifier = '{' + min + ',}'; | ||
break; | ||
} | ||
break; | ||
default: | ||
if (min == max) { | ||
quantifier = '{' + min + '}'; | ||
} | ||
else if (min == 0 && max == 1) { | ||
quantifier = '?'; | ||
} else { | ||
quantifier = '{' + min + ',' + max + '}'; | ||
} | ||
break; | ||
if (max == null) { | ||
if (min == 0) { | ||
quantifier = '*'; | ||
} else if (min == 1) { | ||
quantifier = '+'; | ||
} else { | ||
quantifier = '{' + min + ',}'; | ||
} | ||
} else if (min == max) { | ||
quantifier = '{' + min + '}'; | ||
} else if (min == 0 && max == 1) { | ||
quantifier = '?'; | ||
} else { | ||
quantifier = '{' + min + ',' + max + '}'; | ||
} | ||
@@ -336,3 +314,3 @@ | ||
function generateTerm(node) { | ||
assertType(node.type, 'anchor|characterClass|characterClassEscape|empty|group|quantifier|reference|value'); | ||
assertType(node.type, 'anchor|characterClass|characterClassEscape|empty|group|quantifier|reference|unicodePropertyEscape|value'); | ||
@@ -363,11 +341,11 @@ return generate(node); | ||
return '\\b'; | ||
case 0x009: | ||
case 0x0009: | ||
return '\\t'; | ||
case 0x00A: | ||
case 0x000A: | ||
return '\\n'; | ||
case 0x00B: | ||
case 0x000B: | ||
return '\\v'; | ||
case 0x00C: | ||
case 0x000C: | ||
return '\\f'; | ||
case 0x00D: | ||
case 0x000D: | ||
return '\\r'; | ||
@@ -390,20 +368,24 @@ default: | ||
generate.alternative = generateAlternative; | ||
generate.anchor = generateAnchor; | ||
generate.characterClass = generateCharacterClass; | ||
generate.characterClassEscape = generateCharacterClassEscape; | ||
generate.characterClassRange = generateCharacterClassRange; | ||
generate.disjunction = generateDisjunction; | ||
generate.dot = generateDot; | ||
generate.group = generateGroup; | ||
generate.quantifier = generateQuantifier; | ||
generate.reference = generateReference; | ||
generate.value = generateValue; | ||
// Used to generate strings for each node type. | ||
var generators = { | ||
'alternative': generateAlternative, | ||
'anchor': generateAnchor, | ||
'characterClass': generateCharacterClass, | ||
'characterClassEscape': generateCharacterClassEscape, | ||
'characterClassRange': generateCharacterClassRange, | ||
'unicodePropertyEscape': generateUnicodePropertyEscape, | ||
'disjunction': generateDisjunction, | ||
'dot': generateDot, | ||
'group': generateGroup, | ||
'quantifier': generateQuantifier, | ||
'reference': generateReference, | ||
'value': generateValue | ||
}; | ||
/*--------------------------------------------------------------------------*/ | ||
// export regjsgen | ||
// some AMD build optimizers, like r.js, check for condition patterns like the following: | ||
// Export regjsgen. | ||
// Some AMD build optimizers, like r.js, check for condition patterns like the following: | ||
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { | ||
// define as an anonymous module so, through path mapping, it can be aliased | ||
// Define as an anonymous module so it can be aliased through path mapping. | ||
define(function() { | ||
@@ -415,9 +397,9 @@ return { | ||
} | ||
// check for `exports` after `define` in case a build optimizer adds an `exports` object | ||
// Check for `exports` after `define` in case a build optimizer adds an `exports` object. | ||
else if (freeExports && freeModule) { | ||
// in Narwhal, Node.js, Rhino -require, or RingoJS | ||
// Export for CommonJS support. | ||
freeExports.generate = generate; | ||
} | ||
// in a browser or Rhino | ||
else { | ||
// Export to the global object. | ||
root.regjsgen = { | ||
@@ -424,0 +406,0 @@ 'generate': generate |
14453
4
320
46