randexp
Advanced tools
Comparing version 0.4.6 to 0.4.7
@@ -1,245 +0,259 @@ | ||
var ret = require('ret'); | ||
var DRange = require('discontinuous-range'); | ||
var types = ret.types; | ||
'use strict'; | ||
const ret = require('ret'); | ||
const DRange = require('discontinuous-range'); | ||
const types = ret.types; | ||
/** | ||
* If code is alphabetic, converts to other case. | ||
* If not alphabetic, returns back code. | ||
* | ||
* @param {Number} code | ||
* @return {Number} | ||
*/ | ||
function toOtherCase(code) { | ||
return code + (97 <= code && code <= 122 ? -32 : | ||
65 <= code && code <= 90 ? 32 : 0); | ||
} | ||
module.exports = class RandExp { | ||
/** | ||
* @constructor | ||
* @param {RegExp|String} regexp | ||
* @param {String} m | ||
*/ | ||
constructor(regexp, m) { | ||
this._setDefaults(regexp); | ||
if (regexp instanceof RegExp) { | ||
this.ignoreCase = regexp.ignoreCase; | ||
this.multiline = regexp.multiline; | ||
regexp = regexp.source; | ||
/** | ||
* Randomly returns a true or false value. | ||
* | ||
* @return {Boolean} | ||
*/ | ||
function randBool() { | ||
return !this.randInt(0, 1); | ||
} | ||
} else if (typeof regexp === 'string') { | ||
this.ignoreCase = m && m.indexOf('i') !== -1; | ||
this.multiline = m && m.indexOf('m') !== -1; | ||
} else { | ||
throw new Error('Expected a regexp or string'); | ||
} | ||
/** | ||
* Randomly selects and returns a value from the array. | ||
* | ||
* @param {Array.<Object>} arr | ||
* @return {Object} | ||
*/ | ||
function randSelect(arr) { | ||
if (arr instanceof DRange) { | ||
return arr.index(this.randInt(0, arr.length - 1)); | ||
this.tokens = ret(regexp); | ||
} | ||
return arr[this.randInt(0, arr.length - 1)]; | ||
} | ||
/** | ||
* expands a token to a DiscontinuousRange of characters which has a | ||
* length and an index function (for random selecting) | ||
* | ||
* @param {Object} token | ||
* @return {DiscontinuousRange} | ||
*/ | ||
function expand(token) { | ||
if (token.type === ret.types.CHAR) { | ||
return new DRange(token.value); | ||
} else if (token.type === ret.types.RANGE) { | ||
return new DRange(token.from, token.to); | ||
} else { | ||
var drange = new DRange(); | ||
for (var i = 0; i < token.set.length; i++) { | ||
var subrange = expand.call(this, token.set[i]); | ||
drange.add(subrange); | ||
if (this.ignoreCase) { | ||
for (var j = 0; j < subrange.length; j++) { | ||
var code = subrange.index(j); | ||
var otherCaseCode = toOtherCase(code); | ||
if (code !== otherCaseCode) { | ||
drange.add(otherCaseCode); | ||
} | ||
} | ||
} | ||
/** | ||
* Checks if some custom properties have been set for this regexp. | ||
* | ||
* @param {RandExp} randexp | ||
* @param {RegExp} regexp | ||
*/ | ||
_setDefaults(regexp) { | ||
// When a repetitional token has its max set to Infinite, | ||
// randexp won't actually generate a random amount between min and Infinite | ||
// instead it will see Infinite as min + 100. | ||
this.max = regexp.max != null ? regexp.max : | ||
RandExp.prototype.max != null ? RandExp.prototype.max : 100; | ||
// This allows expanding to include additional characters | ||
// for instance: RandExp.defaultRange.add(0, 65535); | ||
this.defaultRange = regexp.defaultRange ? | ||
regexp.defaultRange : this.defaultRange.clone(); | ||
if (regexp.randInt) { | ||
this.randInt = regexp.randInt; | ||
} | ||
if (token.not) { | ||
return this.defaultRange.clone().subtract(drange); | ||
} else { | ||
return drange; | ||
} | ||
} | ||
} | ||
/** | ||
* Checks if some custom properties have been set for this regexp. | ||
* | ||
* @param {RandExp} randexp | ||
* @param {RegExp} regexp | ||
*/ | ||
function checkCustom(randexp, regexp) { | ||
if (typeof regexp.max === 'number') { | ||
randexp.max = regexp.max; | ||
/** | ||
* Generates the random string. | ||
* | ||
* @return {String} | ||
*/ | ||
gen() { | ||
return this._gen(this.tokens, []); | ||
} | ||
if (regexp.defaultRange instanceof DRange) { | ||
randexp.defaultRange = regexp.defaultRange; | ||
} | ||
if (typeof regexp.randInt === 'function') { | ||
randexp.randInt = regexp.randInt; | ||
} | ||
} | ||
/** | ||
* @constructor | ||
* @param {RegExp|String} regexp | ||
* @param {String} m | ||
*/ | ||
var RandExp = module.exports = function(regexp, m) { | ||
this.defaultRange = this.defaultRange.clone(); | ||
if (regexp instanceof RegExp) { | ||
this.ignoreCase = regexp.ignoreCase; | ||
this.multiline = regexp.multiline; | ||
checkCustom(this, regexp); | ||
regexp = regexp.source; | ||
/** | ||
* Generate random string modeled after given tokens. | ||
* | ||
* @param {Object} token | ||
* @param {Array.<String>} groups | ||
* @return {String} | ||
*/ | ||
_gen(token, groups) { | ||
var stack, str, n, i, l; | ||
} else if (typeof regexp === 'string') { | ||
this.ignoreCase = m && m.indexOf('i') !== -1; | ||
this.multiline = m && m.indexOf('m') !== -1; | ||
} else { | ||
throw new Error('Expected a regexp or string'); | ||
} | ||
switch (token.type) { | ||
case types.ROOT: | ||
case types.GROUP: | ||
// Ignore lookaheads for now. | ||
if (token.followedBy || token.notFollowedBy) { return ''; } | ||
this.tokens = ret(regexp); | ||
}; | ||
// Insert placeholder until group string is generated. | ||
if (token.remember && token.groupNumber === undefined) { | ||
token.groupNumber = groups.push(null) - 1; | ||
} | ||
stack = token.options ? | ||
this._randSelect(token.options) : token.stack; | ||
// When a repetitional token has its max set to Infinite, | ||
// randexp won't actually generate a random amount between min and Infinite | ||
// instead it will see Infinite as min + 100. | ||
RandExp.prototype.max = 100; | ||
str = ''; | ||
for (i = 0, l = stack.length; i < l; i++) { | ||
str += this._gen(stack[i], groups); | ||
} | ||
if (token.remember) { | ||
groups[token.groupNumber] = str; | ||
} | ||
return str; | ||
// Generates the random string. | ||
RandExp.prototype.gen = function() { | ||
return gen.call(this, this.tokens, []); | ||
}; | ||
case types.POSITION: | ||
// Do nothing for now. | ||
return ''; | ||
case types.SET: | ||
var expandedSet = this._expand(token); | ||
if (!expandedSet.length) { return ''; } | ||
return String.fromCharCode(this._randSelect(expandedSet)); | ||
// Enables use of randexp with a shorter call. | ||
RandExp.randexp = function(regexp, m) { | ||
var randexp; | ||
if (regexp._randexp === undefined) { | ||
randexp = new RandExp(regexp, m); | ||
regexp._randexp = randexp; | ||
} else { | ||
randexp = regexp._randexp; | ||
} | ||
checkCustom(randexp, regexp); | ||
return randexp.gen(); | ||
}; | ||
case types.REPETITION: | ||
// Randomly generate number between min and max. | ||
n = this.randInt(token.min, | ||
token.max === Infinity ? token.min + this.max : token.max); | ||
str = ''; | ||
for (i = 0; i < n; i++) { | ||
str += this._gen(token.value, groups); | ||
} | ||
// This enables sugary /regexp/.gen syntax. | ||
RandExp.sugar = function() { | ||
/* jshint freeze:false */ | ||
RegExp.prototype.gen = function() { | ||
return RandExp.randexp(this); | ||
}; | ||
}; | ||
return str; | ||
// This allows expanding to include additional characters | ||
// for instance: RandExp.defaultRange.add(0, 65535); | ||
RandExp.prototype.defaultRange = new DRange(32, 126); | ||
case types.REFERENCE: | ||
return groups[token.value - 1] || ''; | ||
case types.CHAR: | ||
var code = this.ignoreCase && this._randBool() ? | ||
this._toOtherCase(token.value) : token.value; | ||
return String.fromCharCode(code); | ||
} | ||
} | ||
/** | ||
* Randomly generates and returns a number between a and b (inclusive). | ||
* | ||
* @param {Number} a | ||
* @param {Number} b | ||
* @return {Number} | ||
*/ | ||
RandExp.prototype.randInt = function(a, b) { | ||
return a + Math.floor(Math.random() * (1 + b - a)); | ||
}; | ||
/** | ||
* If code is alphabetic, converts to other case. | ||
* If not alphabetic, returns back code. | ||
* | ||
* @param {Number} code | ||
* @return {Number} | ||
*/ | ||
_toOtherCase(code) { | ||
return code + (97 <= code && code <= 122 ? -32 : | ||
65 <= code && code <= 90 ? 32 : 0); | ||
} | ||
/** | ||
* Generate random string modeled after given tokens. | ||
* | ||
* @param {Object} token | ||
* @param {Array.<String>} groups | ||
* @return {String} | ||
*/ | ||
function gen(token, groups) { | ||
var stack, str, n, i, l; | ||
switch (token.type) { | ||
/** | ||
* Randomly returns a true or false value. | ||
* | ||
* @return {Boolean} | ||
*/ | ||
_randBool() { | ||
return !this.randInt(0, 1); | ||
} | ||
case types.ROOT: | ||
case types.GROUP: | ||
// Ignore lookaheads for now. | ||
if (token.followedBy || token.notFollowedBy) { return ''; } | ||
/** | ||
* Randomly selects and returns a value from the array. | ||
* | ||
* @param {Array.<Object>} arr | ||
* @return {Object} | ||
*/ | ||
_randSelect(arr) { | ||
if (arr instanceof DRange) { | ||
return arr.index(this.randInt(0, arr.length - 1)); | ||
} | ||
return arr[this.randInt(0, arr.length - 1)]; | ||
} | ||
// Insert placeholder until group string is generated. | ||
if (token.remember && token.groupNumber === undefined) { | ||
token.groupNumber = groups.push(null) - 1; | ||
} | ||
stack = token.options ? | ||
randSelect.call(this, token.options) : token.stack; | ||
str = ''; | ||
for (i = 0, l = stack.length; i < l; i++) { | ||
str += gen.call(this, stack[i], groups); | ||
/** | ||
* expands a token to a DiscontinuousRange of characters which has a | ||
* length and an index function (for random selecting) | ||
* | ||
* @param {Object} token | ||
* @return {DiscontinuousRange} | ||
*/ | ||
_expand(token) { | ||
if (token.type === ret.types.CHAR) { | ||
return new DRange(token.value); | ||
} else if (token.type === ret.types.RANGE) { | ||
return new DRange(token.from, token.to); | ||
} else { | ||
let drange = new DRange(); | ||
for (let i = 0; i < token.set.length; i++) { | ||
let subrange = this._expand(token.set[i]); | ||
drange.add(subrange); | ||
if (this.ignoreCase) { | ||
for (let j = 0; j < subrange.length; j++) { | ||
let code = subrange.index(j); | ||
let otherCaseCode = this._toOtherCase(code); | ||
if (code !== otherCaseCode) { | ||
drange.add(otherCaseCode); | ||
} | ||
} | ||
} | ||
} | ||
if (token.remember) { | ||
groups[token.groupNumber] = str; | ||
if (token.not) { | ||
return this.defaultRange.clone().subtract(drange); | ||
} else { | ||
return this.defaultRange.clone().intersect(drange); | ||
} | ||
return str; | ||
} | ||
} | ||
case types.POSITION: | ||
// Do nothing for now. | ||
return ''; | ||
/** | ||
* Randomly generates and returns a number between a and b (inclusive). | ||
* | ||
* @param {Number} a | ||
* @param {Number} b | ||
* @return {Number} | ||
*/ | ||
randInt(a, b) { | ||
return a + Math.floor(Math.random() * (1 + b - a)); | ||
} | ||
case types.SET: | ||
var expandedSet = expand.call(this, token); | ||
if (!expandedSet.length) { return ''; } | ||
return String.fromCharCode(randSelect.call(this, expandedSet)); | ||
/** | ||
* Default range of characters to generate from. | ||
*/ | ||
get defaultRange() { | ||
return this._range = this._range || new DRange(32, 126); | ||
} | ||
set defaultRange(range) { | ||
this._range = range; | ||
} | ||
case types.REPETITION: | ||
// Randomly generate number between min and max. | ||
n = this.randInt(token.min, | ||
token.max === Infinity ? token.min + this.max : token.max); | ||
str = ''; | ||
for (i = 0; i < n; i++) { | ||
str += gen.call(this, token.value, groups); | ||
} | ||
/** | ||
* | ||
* Enables use of randexp with a shorter call. | ||
* | ||
* @param {RegExp|String| regexp} | ||
* @param {String} m | ||
* @return {String} | ||
*/ | ||
static randexp(regexp, m) { | ||
var randexp; | ||
if (regexp._randexp === undefined) { | ||
randexp = new RandExp(regexp, m); | ||
regexp._randexp = randexp; | ||
} else { | ||
randexp = regexp._randexp; | ||
randexp._setDefaults(regexp); | ||
} | ||
return randexp.gen(); | ||
} | ||
return str; | ||
case types.REFERENCE: | ||
return groups[token.value - 1] || ''; | ||
case types.CHAR: | ||
var code = this.ignoreCase && randBool.call(this) ? | ||
toOtherCase(token.value) : token.value; | ||
return String.fromCharCode(code); | ||
/** | ||
* Enables sugary /regexp/.gen syntax. | ||
*/ | ||
static sugar() { | ||
/* eshint freeze:false */ | ||
RegExp.prototype.gen = function() { | ||
return RandExp.randexp(this); | ||
}; | ||
} | ||
} | ||
}; |
@@ -11,3 +11,3 @@ { | ||
], | ||
"version": "0.4.6", | ||
"version": "0.4.7", | ||
"homepage": "http://fent.github.io/randexp.js/", | ||
@@ -18,3 +18,3 @@ "repository": { | ||
}, | ||
"author": "Roly Fentanes (https://github.com/fent)", | ||
"author": "fent (https://github.com/fent)", | ||
"main": "./lib/randexp.js", | ||
@@ -32,20 +32,20 @@ "files": [ | ||
"dependencies": { | ||
"discontinuous-range": "1.0.0", | ||
"ret": "~0.1.10" | ||
"discontinuous-range": "github:fent/discontinuous-range#feature/intersect", | ||
"ret": "^0.2.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^14.0.0", | ||
"browserify": "^15.2.0", | ||
"gulp": "^3.9.0", | ||
"gulp-header": "^1.7.1", | ||
"gulp-header": "^2.0.1", | ||
"gulp-insert": "^0.5.0", | ||
"gulp-uglify": "^3.0.0", | ||
"istanbul": "*", | ||
"mocha": "*", | ||
"vinyl-buffer": "^1.0.0", | ||
"vinyl-source-stream": "^1.1.0" | ||
"mocha": "^5.0.0", | ||
"vinyl-buffer": "^1.0.1", | ||
"vinyl-source-stream": "^1.1.2" | ||
}, | ||
"engines": { | ||
"node": ">=0.12" | ||
"node": ">=4" | ||
}, | ||
"license": "MIT" | ||
} |
@@ -12,3 +12,3 @@ # randexp.js | ||
```js | ||
var RandExp = require('randexp'); | ||
const RandExp = require('randexp'); | ||
@@ -40,3 +40,3 @@ // supports grouping and piping | ||
```js | ||
var randexp = require('randexp').randexp; | ||
const randexp = require('randexp').randexp; | ||
@@ -63,6 +63,6 @@ randexp(/[1-6]/); // 4 | ||
The default generated character range includes printable ASCII. In order to add or remove characters, | ||
The default generated character range includes printable ASCII. In order to add or remove characters, | ||
a `defaultRange` attribute is exposed. you can `subtract(from, to)` and `add(from, to)` | ||
```js | ||
var randexp = new RandExp(/random stuff: .+/); | ||
const randexp = new RandExp(/random stuff: .+/); | ||
randexp.defaultRange.subtract(32, 126); | ||
@@ -74,7 +74,8 @@ randexp.defaultRange.add(0, 65535); | ||
You can also change the default range by changing `RandExp.prototype.defaultRange`. | ||
# Custom PRNG | ||
The default randomness is provided by `Math.random()`. If you need to use a seedable or cryptographic PRNG, you | ||
can override `RandExp.prototype.randInt` or `randexp.randInt` (where `randexp` is an instance of `RandExp`). `randInt(from, to)` accepts an inclusive range and returns a randomly selected | ||
number within that range. | ||
can override `RandExp.prottoype.randInt` or `randexp.randInt` (where `randexp` is an instance of `RandExp`). `randInt(from, to)` accepts an inclusive range and returns a randomly selected number within that range. | ||
@@ -86,3 +87,3 @@ # Infinite Repetitionals | ||
```js | ||
var randexp = new RandExp(/no{1,}/); | ||
const randexp = new RandExp(/no{1,}/); | ||
randexp.max = 1000000; | ||
@@ -94,3 +95,3 @@ ``` | ||
```js | ||
var regexp = /(hi)*/; | ||
const regexp = /(hi)*/; | ||
regexp.max = 1000000; | ||
@@ -136,6 +137,1 @@ ``` | ||
``` | ||
# License | ||
MIT |
Sorry, the diff of this file is not supported yet
GitHub dependency
Supply chain riskContains a dependency which resolves to a GitHub URL. Dependencies fetched from GitHub specifiers are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
12913
217
131
1
1
+ Addedret@0.2.2(transitive)
- Removeddiscontinuous-range@1.0.0(transitive)
- Removedret@0.1.15(transitive)
Updateddiscontinuous-range@github:fent/discontinuous-range#feature/intersect
Updatedret@^0.2.0