[Pkg-javascript-commits] [node-to-regex-range] 02/07: New upstream version 3.0.0
Julien Puydt
julien.puydt at laposte.net
Sat Nov 25 16:46:26 UTC 2017
This is an automated email from the git hooks/post-receive script.
jpuydt-guest pushed a commit to branch master
in repository node-to-regex-range.
commit f2c1225919e45c16fc8481391d64e26584f1a73e
Author: Julien Puydt <julien.puydt at laposte.net>
Date: Sat Nov 25 17:21:46 2017 +0100
New upstream version 3.0.0
---
.editorconfig | 13 ---
.eslintrc.json | 122 ----------------------
.gitattributes | 10 --
.gitignore | 21 ----
.travis.yml | 12 ---
.verb.md | 41 --------
LICENSE | 2 +-
README.md | 276 ++++++++++++++++++++++++++++++++++++++++++--------
bower.json | 38 -------
example.js | 17 ----
index.js | 258 +++++++++++++++++++++++++++++-----------------
package.json | 36 +++++--
test/support/index.js | 14 ---
test/test.js | 174 -------------------------------
14 files changed, 424 insertions(+), 610 deletions(-)
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 818e072..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-root = true
-
-[*]
-indent_style = space
-end_of_line = lf
-charset = utf-8
-indent_size = 2
-trim_trailing_whitespace = true
-insert_final_newline = true
-
-[{**/{actual,fixtures,expected,templates}/**,*.md}]
-trim_trailing_whitespace = false
-insert_final_newline = false
\ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 948dbdb..0000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,122 +0,0 @@
-{
- "ecmaFeatures": {
- "modules": true,
- "experimentalObjectRestSpread": true
- },
-
- "env": {
- "browser": false,
- "es6": true,
- "node": true,
- "mocha": true
- },
-
- "globals": {
- "document": false,
- "navigator": false,
- "window": false
- },
-
- "rules": {
- "accessor-pairs": 2,
- "arrow-spacing": [2, { "before": true, "after": true }],
- "block-spacing": [2, "always"],
- "brace-style": [2, "1tbs", { "allowSingleLine": true }],
- "comma-dangle": [2, "never"],
- "comma-spacing": [2, { "before": false, "after": true }],
- "comma-style": [2, "last"],
- "constructor-super": 2,
- "curly": [2, "multi-line"],
- "dot-location": [2, "property"],
- "eol-last": 2,
- "eqeqeq": [2, "allow-null"],
- "generator-star-spacing": [2, { "before": true, "after": true }],
- "handle-callback-err": [2, "^(err|error)$" ],
- "indent": [2, 2, { "SwitchCase": 1 }],
- "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
- "keyword-spacing": [2, { "before": true, "after": true }],
- "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
- "new-parens": 2,
- "no-array-constructor": 2,
- "no-caller": 2,
- "no-class-assign": 2,
- "no-cond-assign": 2,
- "no-const-assign": 2,
- "no-control-regex": 2,
- "no-debugger": 2,
- "no-delete-var": 2,
- "no-dupe-args": 2,
- "no-dupe-class-members": 2,
- "no-dupe-keys": 2,
- "no-duplicate-case": 2,
- "no-empty-character-class": 2,
- "no-eval": 2,
- "no-ex-assign": 2,
- "no-extend-native": 2,
- "no-extra-bind": 2,
- "no-extra-boolean-cast": 2,
- "no-extra-parens": [2, "functions"],
- "no-fallthrough": 2,
- "no-floating-decimal": 2,
- "no-func-assign": 2,
- "no-implied-eval": 2,
- "no-inner-declarations": [2, "functions"],
- "no-invalid-regexp": 2,
- "no-irregular-whitespace": 2,
- "no-iterator": 2,
- "no-label-var": 2,
- "no-labels": 2,
- "no-lone-blocks": 2,
- "no-mixed-spaces-and-tabs": 2,
- "no-multi-spaces": 2,
- "no-multi-str": 2,
- "no-multiple-empty-lines": [2, { "max": 1 }],
- "no-native-reassign": 0,
- "no-negated-in-lhs": 2,
- "no-new": 2,
- "no-new-func": 2,
- "no-new-object": 2,
- "no-new-require": 2,
- "no-new-wrappers": 2,
- "no-obj-calls": 2,
- "no-octal": 2,
- "no-octal-escape": 2,
- "no-proto": 0,
- "no-redeclare": 2,
- "no-regex-spaces": 2,
- "no-return-assign": 2,
- "no-self-compare": 2,
- "no-sequences": 2,
- "no-shadow-restricted-names": 2,
- "no-spaced-func": 2,
- "no-sparse-arrays": 2,
- "no-this-before-super": 2,
- "no-throw-literal": 2,
- "no-trailing-spaces": 0,
- "no-undef": 2,
- "no-undef-init": 2,
- "no-unexpected-multiline": 2,
- "no-unneeded-ternary": [2, { "defaultAssignment": false }],
- "no-unreachable": 2,
- "no-unused-vars": [2, { "vars": "all", "args": "none" }],
- "no-useless-call": 0,
- "no-with": 2,
- "one-var": [0, { "initialized": "never" }],
- "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }],
- "padded-blocks": [0, "never"],
- "quotes": [2, "single", "avoid-escape"],
- "radix": 2,
- "semi": [2, "always"],
- "semi-spacing": [2, { "before": false, "after": true }],
- "space-before-blocks": [2, "always"],
- "space-before-function-paren": [2, "never"],
- "space-in-parens": [2, "never"],
- "space-infix-ops": 2,
- "space-unary-ops": [2, { "words": true, "nonwords": false }],
- "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
- "use-isnan": 2,
- "valid-typeof": 2,
- "wrap-iife": [2, "any"],
- "yoda": [2, "never"]
- }
-}
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 660957e..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,10 +0,0 @@
-# Enforce Unix newlines
-* text eol=lf
-
-# binaries
-*.ai binary
-*.psd binary
-*.jpg binary
-*.gif binary
-*.png binary
-*.jpeg binary
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 7988154..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,21 +0,0 @@
-# always ignore files
-*.DS_Store
-*.sublime-*
-
-# test related, or directories generated by tests
-test/actual
-actual
-coverage
-
-# npm
-node_modules
-npm-debug.log
-
-# misc
-_gh_pages
-benchmark
-bower_components
-vendor
-temp
-tmp
-TODO.md
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 04a029e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-sudo: false
-language: node_js
-node_js:
- - node
- - '6'
- - '5'
- - '0.12'
-matrix:
- fast_finish: true
- allow_failures:
- - node_js: '4'
- - node_js: '0.12'
diff --git a/.verb.md b/.verb.md
deleted file mode 100644
index 3bd4294..0000000
--- a/.verb.md
+++ /dev/null
@@ -1,41 +0,0 @@
-## Bower
-
-{%= include("install-bower", {save: true}) %}
-
-## Notes
-
-Inspired by the python lib [range-regex](https://github.com/dimka665/range-regex), it has never been easier to validate numbers and number ranges with regex!
-
-The [unit tests generate 850,000 patterns](./test/test.js) to provide brute-force validation that the generated regex-ranges are correct.
-
-## Usage
-
-```js
-var toRegexRange = require('{%= name %}');
-
-var re = new RegExp(toRegexRange('1', '99'));
-re.test('50');
-//=> true
-```
-
-**Examples**
-
-```js
-toRegexRange('111', '555');
-//=> '11[1-9]|1[2-9]\d|[2-4]\d{2}|5[0-4]\d|55[0-5]'
-toRegexRange('5', '5');
-//=> '5'
-toRegexRange('5', '6');
-//=> '[5-6]'
-toRegexRange('51', '229');
-//=> '5[1-9]|[6-9]\d|1\d{2}|2[0-2]\d'
-```
-
-When the `min` is larger than the `max`, a regex logical `or` is returned:
-
-```js
-toRegexRange('51', '29');
-//=> '51|29'
-```
-
-Currently this does not support steps (increments) or zero-padding.
diff --git a/LICENSE b/LICENSE
index 1e49edf..e33d14b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2015-2016, Jon Schlinkert.
+Copyright (c) 2015-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index a414318..c1de879 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
-# to-regex-range [![NPM version](https://img.shields.io/npm/v/to-regex-range.svg?style=flat)](https://www.npmjs.com/package/to-regex-range) [![NPM downloads](https://img.shields.io/npm/dm/to-regex-range.svg?style=flat)](https://npmjs.org/package/to-regex-range) [![Build Status](https://img.shields.io/travis/jonschlinkert/to-regex-range.svg?style=flat)](https://travis-ci.org/jonschlinkert/to-regex-range)
+# to-regex-range [![NPM version](https://img.shields.io/npm/v/to-regex-range.svg?style=flat)](https://www.npmjs.com/package/to-regex-range) [![NPM monthly downloads](https://img.shields.io/npm/dm/to-regex-range.svg?style=flat)](https://npmjs.org/package/to-regex-range) [![NPM total downloads](https://img.shields.io/npm/dt/to-regex-range.svg?style=flat)](https://npmjs.org/package/to-regex-range) [![Linux Build Status](https://img.shields.io/travis/micromatch/to-regex-range.svg?style=flat& [...]
-> Returns a regex-compatible range from two numbers, min and max, with 855,412 generated unit tests to validate it's accuracy! Useful for creating regular expressions to validate numbers, ranges, years, etc. Returns a string, allowing the returned value to be used in regular expressions generated by other libraries.
+> Pass two numbers, get a regex-compatible source string for matching ranges. Validated against more than 2.78 million test assertions.
+
+Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
## Install
@@ -10,96 +12,284 @@ Install with [npm](https://www.npmjs.com/):
$ npm install --save to-regex-range
```
-## Bower
+<details>
+<summary><strong>What does this do?</strong></summary>
-Install with [bower](http://bower.io/)
+<br>
-```sh
-$ bower install to-regex-range --save
+This libary generates the `source` string to be passed to `new RegExp()` for matching a range of numbers.
+
+**Example**
+
+```js
+var toRegexRange = require('to-regex-range');
+var regex = new RegExp(toRegexRange('15', '95'));
```
-## Notes
+A string is returned so that you can do whatever you need with it before passing it to `new RegExp()` (like adding `^` or `$` boundaries, defining flags, or combining it another string).
+
+<br>
+
+</details>
+
+<details>
+<summary><strong>Why use this library?</strong></summary>
+
+<br>
+
+### Convenience
+
+Creating regular expressions for matching numbers gets deceptively complicated pretty fast.
+
+For example, let's say you need a validation regex for matching part of a user-id, postal code, social security number, tax id, etc:
+
+* regex for matching `1` => `/1/` (easy enough)
+* regex for matching `1` through `5` => `/[1-5]/` (not bad...)
+* regex for matching `1` or `5` => `/(1|5)/` (still easy...)
+* regex for matching `1` through `50` => `/([1-9]|[1-4][0-9]|50)/` (uh-oh...)
+* regex for matching `1` through `55` => `/([1-9]|[1-4][0-9]|5[0-5])/` (no prob, I can do this...)
+* regex for matching `1` through `555` => `/([1-9]|[1-9][0-9]|[1-4][0-9]{2}|5[0-4][0-9]|55[0-5])/` (maybe not...)
+* regex for matching `0001` through `5555` => `/(0{3}[1-9]|0{2}[1-9][0-9]|0[1-9][0-9]{2}|[1-4][0-9]{3}|5[0-4][0-9]{2}|55[0-4][0-9]|555[0-5])/` (okay, I get the point!)
+
+The numbers are contrived, but they're also really basic. In the real world you might need to generate a regex on-the-fly for validation.
+
+**Learn more**
+
+If you're interested in learning more about [character classes](http://www.regular-expressions.info/charclass.html) and other regex features, I personally have always found [regular-expressions.info](http://www.regular-expressions.info/charclass.html) to be pretty useful.
+
+### Heavily tested
+
+As of November 01, 2017, this library runs [2,783,483 test assertions](./test/test.js) against generated regex-ranges to provide brute-force verification that results are indeed correct.
+
+Tests run in ~870ms on my MacBook Pro, 2.5 GHz Intel Core i7.
+
+### Highly optimized
+
+Generated regular expressions are highly optimized:
+
+* duplicate sequences and character classes are reduced using quantifiers
+* smart enough to use `?` conditionals when number(s) or range(s) can be positive or negative
+* uses fragment caching to avoid processing the same exact string more than once
-Inspired by the python lib [range-regex](https://github.com/dimka665/range-regex), it has never been easier to validate numbers and number ranges with regex!
+<br>
-The [unit tests generate 850,000 patterns](./test/test.js) to provide brute-force validation that the generated regex-ranges are correct.
+</details>
## Usage
+Add this library to your javascript application with the following line of code
+
```js
var toRegexRange = require('to-regex-range');
+```
+
+The main export is a function that takes two integers: the `min` value and `max` value (formatted as strings or numbers).
+
+```js
+var source = toRegexRange('15', '95');
+//=> 1[5-9]|[2-8][0-9]|9[0-5]
+
+var re = new RegExp('^' + source + '$');
+console.log(re.test('14')); //=> false
+console.log(re.test('50')); //=> true
+console.log(re.test('94')); //=> true
+console.log(re.test('96')); //=> false
+```
+
+## Options
+
+### options.capture
+
+**Type**: `boolean`
+
+**Deafault**: `undefined`
+
+Wrap the returned value in parentheses when there is more than one regex condition. Useful when you're dynamically generating ranges.
+
+```js
+console.log(toRegexRange('-10', '10'));
+//=> -[1-9]|-?10|[0-9]
+
+console.log(toRegexRange('-10', '10', {capture: true}));
+//=> (-[1-9]|-?10|[0-9])
+```
+
+### options.shorthand
+
+**Type**: `boolean`
+
+**Deafault**: `undefined`
+
+Use the regex shorthand for `[0-9]`:
+
+```js
+console.log(toRegexRange('0', '999999'));
+//=> [0-9]|[1-9][0-9]{1,5}
+
+console.log(toRegexRange('0', '999999', {shorthand: true}));
+//=> \d|[1-9]\d{1,5}
+```
+
+### options.relaxZeros
+
+**Type**: `boolean`
+
+**Default**: `true`
+
+This option only applies to **negative zero-padded ranges**. By default, when a negative zero-padded range is defined, the number of leading zeros is relaxed using `-0*`.
+
+```js
+console.log(toRegexRange('-001', '100'));
+//=> -0*1|0{2}[0-9]|0[1-9][0-9]|100
-var re = new RegExp(toRegexRange('1', '99'));
-re.test('50');
-//=> true
+console.log(toRegexRange('-001', '100', {relaxZeros: false}));
+//=> -0{2}1|0{2}[0-9]|0[1-9][0-9]|100
```
-**Examples**
+<details>
+<summary><strong>Why are zeros relaxed for negative zero-padded ranges by default?</strong></summary>
+
+Consider the following.
```js
-toRegexRange('111', '555');
-//=> '11[1-9]|1[2-9]\d|[2-4]\d{2}|5[0-4]\d|55[0-5]'
-toRegexRange('5', '5');
-//=> '5'
-toRegexRange('5', '6');
-//=> '[5-6]'
-toRegexRange('51', '229');
-//=> '5[1-9]|[6-9]\d|1\d{2}|2[0-2]\d'
+var regex = toRegexRange('-001', '100');
```
-When the `min` is larger than the `max`, a regex logical `or` is returned:
+_Note that `-001` and `100` are both three digits long_.
+
+In most zero-padding implementations, only a single leading zero is enough to indicate that zero-padding should be applied. Thus, the leading zeros would be "corrected" on the negative range in the example to `-01`, instead of `-001`, to make total length of each string no greater than the length of the largest number in the range (in other words, `-001` is 4 digits, but `100` is only three digits).
+
+If zeros were not relaxed by default, you might expect the resulting regex of the above pattern to match `-001` - given that it's defined that way in the arguments - _but it wouldn't_. It would, however, match `-01`. This gets even more ambiguous with large ranges, like `-01` to `1000000`.
+
+Thus, we relax zeros by default to provide a more predictable experience for users.
+
+</details>
+
+## Examples
+
+| **Range** | **Result** | **Compile time** |
+| --- | --- | --- |
+| `toRegexRange('5, 5')` | `5` | _33μs_ |
+| `toRegexRange('5, 6')` | `5\|6` | _53μs_ |
+| `toRegexRange('29, 51')` | `29\|[34][0-9]\|5[01]` | _699μs_ |
+| `toRegexRange('31, 877')` | `3[1-9]\|[4-9][0-9]\|[1-7][0-9]{2}\|8[0-6][0-9]\|87[0-7]` | _711μs_ |
+| `toRegexRange('111, 555')` | `11[1-9]\|1[2-9][0-9]\|[2-4][0-9]{2}\|5[0-4][0-9]\|55[0-5]` | _62μs_ |
+| `toRegexRange('-10, 10')` | `-[1-9]\|-?10\|[0-9]` | _74μs_ |
+| `toRegexRange('-100, -10')` | `-1[0-9]\|-[2-9][0-9]\|-100` | _49μs_ |
+| `toRegexRange('-100, 100')` | `-[1-9]\|-?[1-9][0-9]\|-?100\|[0-9]` | _45μs_ |
+| `toRegexRange('001, 100')` | `0{2}[1-9]\|0[1-9][0-9]\|100` | _158μs_ |
+| `toRegexRange('0010, 1000')` | `0{2}1[0-9]\|0{2}[2-9][0-9]\|0[1-9][0-9]{2}\|1000` | _61μs_ |
+| `toRegexRange('1, 2')` | `1\|2` | _10μs_ |
+| `toRegexRange('1, 5')` | `[1-5]` | _24μs_ |
+| `toRegexRange('1, 10')` | `[1-9]\|10` | _23μs_ |
+| `toRegexRange('1, 100')` | `[1-9]\|[1-9][0-9]\|100` | _30μs_ |
+| `toRegexRange('1, 1000')` | `[1-9]\|[1-9][0-9]{1,2}\|1000` | _52μs_ |
+| `toRegexRange('1, 10000')` | `[1-9]\|[1-9][0-9]{1,3}\|10000` | _47μs_ |
+| `toRegexRange('1, 100000')` | `[1-9]\|[1-9][0-9]{1,4}\|100000` | _44μs_ |
+| `toRegexRange('1, 1000000')` | `[1-9]\|[1-9][0-9]{1,5}\|1000000` | _49μs_ |
+| `toRegexRange('1, 10000000')` | `[1-9]\|[1-9][0-9]{1,6}\|10000000` | _63μs_ |
+
+## Heads up!
+
+**Order of arguments**
+
+When the `min` is larger than the `max`, values will be flipped to create a valid range:
```js
toRegexRange('51', '29');
-//=> '51|29'
```
-Currently this does not support steps (increments) or zero-padding.
+Is effectively flipped to:
-## About
+```js
+toRegexRange('29', '51');
+//=> 29|[3-4][0-9]|5[0-1]
+```
-### Related projects
+**Steps / increments**
-* [expand-range](https://www.npmjs.com/package/expand-range): Fast, bash-like range expansion. Expand a range of numbers or letters, uppercase or lowercase. See… [more](https://github.com/jonschlinkert/expand-range) | [homepage](https://github.com/jonschlinkert/expand-range "Fast, bash-like range expansion. Expand a range of numbers or letters, uppercase or lowercase. See the benchmarks. Used by micromatch.")
-* [fill-range](https://www.npmjs.com/package/fill-range): Fill in a range of numbers or letters, optionally passing an increment or multiplier to… [more](https://github.com/jonschlinkert/fill-range) | [homepage](https://github.com/jonschlinkert/fill-range "Fill in a range of numbers or letters, optionally passing an increment or multiplier to use.")
-* [micromatch](https://www.npmjs.com/package/micromatch): Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. | [homepage](https://github.com/jonschlinkert/micromatch "Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch.")
-* [repeat-element](https://www.npmjs.com/package/repeat-element): Create an array by repeating the given value n times. | [homepage](https://github.com/jonschlinkert/repeat-element "Create an array by repeating the given value n times.")
-* [repeat-string](https://www.npmjs.com/package/repeat-string): Repeat the given string n times. Fastest implementation for repeating a string. | [homepage](https://github.com/jonschlinkert/repeat-string "Repeat the given string n times. Fastest implementation for repeating a string.")
+This library does not support steps (increments). A pr to add support would be welcome.
-### Contributing
+## History
+
+### v2.0.0 - 2017-04-21
+
+**New features**
+
+Adds support for zero-padding!
+
+### v1.0.0
+
+**Optimizations**
+
+Repeating ranges are now grouped using quantifiers. rocessing time is roughly the same, but the generated regex is much smaller, which should result in faster matching.
+
+## Attribution
+
+Inspired by the python library [range-regex](https://github.com/dimka665/range-regex).
+
+## About
+
+<details>
+<summary><strong>Contributing</strong></summary>
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
-### Building docs
+</details>
-_(This document was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme) (a [verb](https://github.com/verbose/verb) generator), please don't edit the readme directly. Any changes to the readme must be made in [.verb.md](.verb.md).)_
+<details>
+<summary><strong>Running Tests</strong></summary>
-To generate the readme and API documentation with [verb](https://github.com/verbose/verb):
+Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
```sh
-$ npm install -g verb verb-generate-readme && verb
+$ npm install && npm test
```
-### Running tests
+</details>
-Install dev dependencies:
+<details>
+<summary><strong>Building docs</strong></summary>
+
+_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
+
+To generate the readme, run the following command:
```sh
-$ npm install -d && npm test
+$ npm install -g verbose/verb#dev verb-generate-readme && verb
```
+</details>
+
+### Related projects
+
+You might also be interested in these projects:
+
+* [expand-range](https://www.npmjs.com/package/expand-range): Fast, bash-like range expansion. Expand a range of numbers or letters, uppercase or lowercase. Used… [more](https://github.com/jonschlinkert/expand-range) | [homepage](https://github.com/jonschlinkert/expand-range "Fast, bash-like range expansion. Expand a range of numbers or letters, uppercase or lowercase. Used by [micromatch].")
+* [fill-range](https://www.npmjs.com/package/fill-range): Fill in a range of numbers or letters, optionally passing an increment or `step` to… [more](https://github.com/jonschlinkert/fill-range) | [homepage](https://github.com/jonschlinkert/fill-range "Fill in a range of numbers or letters, optionally passing an increment or `step` to use, or create a regex-compatible range with `options.toRegex`")
+* [micromatch](https://www.npmjs.com/package/micromatch): Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. | [homepage](https://github.com/micromatch/micromatch "Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch.")
+* [repeat-element](https://www.npmjs.com/package/repeat-element): Create an array by repeating the given value n times. | [homepage](https://github.com/jonschlinkert/repeat-element "Create an array by repeating the given value n times.")
+* [repeat-string](https://www.npmjs.com/package/repeat-string): Repeat the given string n times. Fastest implementation for repeating a string. | [homepage](https://github.com/jonschlinkert/repeat-string "Repeat the given string n times. Fastest implementation for repeating a string.")
+
+### Contributors
+
+| **Commits** | **Contributor** |
+| --- | --- |
+| 51 | [jonschlinkert](https://github.com/jonschlinkert) |
+| 2 | [realityking](https://github.com/realityking) |
+
### Author
**Jon Schlinkert**
* [github/jonschlinkert](https://github.com/jonschlinkert)
-* [twitter/jonschlinkert](http://twitter.com/jonschlinkert)
+* [twitter/jonschlinkert](https://twitter.com/jonschlinkert)
### License
-Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert).
-Released under the [MIT license](https://github.com/jonschlinkert/to-regex-range/blob/master/LICENSE).
+Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert).
+Released under the [MIT License](LICENSE).
***
-_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.1.30, on September 14, 2016._
\ No newline at end of file
+_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on November 01, 2017._
\ No newline at end of file
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 28ae064..0000000
--- a/bower.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "name": "to-regex-range",
- "description": "Returns a regex-compatible range from two numbers, min and max. Useful for creating regular expressions to validate numbers, ranges, years, etc.",
- "repository": "jonschlinkert/to-regex-range",
- "license": "MIT",
- "homepage": "https://github.com/jonschlinkert/to-regex-range",
- "authors": [
- "Jon Schlinkert (https://github.com/jonschlinkert)"
- ],
- "main": [
- "index.js"
- ],
- "dependencies": {
- "is-number": "^2.0.2",
- "repeat-string": "^1.5.2"
- },
- "devDependencies": {
- "mocha": "*",
- "should": "*"
- },
- "keywords": [
- "alpha",
- "alphabetical",
- "bash",
- "brace",
- "expand",
- "expansion",
- "glob",
- "match",
- "matches",
- "matching",
- "number",
- "numerical",
- "range",
- "ranges",
- "sh"
- ]
-}
diff --git a/example.js b/example.js
deleted file mode 100644
index c927ace..0000000
--- a/example.js
+++ /dev/null
@@ -1,17 +0,0 @@
-var toRegexRange = require('./');
-
-console.log(toRegexRange('111', '555'));
-//=> '11[1-9]|1[2-9]\d|[2-4]\d{2}|5[0-4]\d|55[0-5]'
-console.log(toRegexRange('5', '5'));
-//=> '5'
-console.log(toRegexRange('5', '6'));
-//=> '[5-6]'
-console.log(toRegexRange('51', '229'));
-//=> '5[1-9]|[6-9]\d|1\d{2}|2[0-2]\d'
-console.log(toRegexRange('51', '29'));
-//=> '51|29'
-
-console.log(toRegexRange('1991', '2015'));
-var re = new RegExp(toRegexRange('1', '99'));
-console.log(re.test('50'));
-// => true
diff --git a/index.js b/index.js
index d7487c6..1754f4c 100644
--- a/index.js
+++ b/index.js
@@ -1,92 +1,100 @@
/*!
- * to-regex-range <https://github.com/jonschlinkert/to-regex-range>
+ * to-regex-range <https://github.com/micromatch/to-regex-range>
*
- * Copyright (c) 2015, Jon Schlinkert.
- * Licensed under the MIT License.
+ * Copyright (c) 2015-2017, Jon Schlinkert.
+ * Released under the MIT License.
*/
'use strict';
var repeat = require('repeat-string');
var isNumber = require('is-number');
-var cache = {range: {}, rangeToPattern: {}};
+var cache = {};
-function toRegexRange(min, max) {
+function toRegexRange(min, max, options) {
if (isNumber(min) === false) {
throw new RangeError('toRegexRange: first argument is invalid.');
}
- if (typeof max === 'undefined') {
- return '' + min;
+ if (typeof max === 'undefined' || min === max) {
+ return String(min);
}
if (isNumber(max) === false) {
throw new RangeError('toRegexRange: second argument is invalid.');
}
- var key = min + ':' + max;
- if (cache.range.hasOwnProperty(key)) {
- return cache.range[key];
+ options = options || {};
+ var relax = String(options.relaxZeros);
+ var shorthand = String(options.shorthand);
+ var capture = String(options.capture);
+ var key = min + ':' + max + '=' + relax + shorthand + capture;
+ if (cache.hasOwnProperty(key)) {
+ return cache[key].result;
}
- var a = min;
- var b = max;
+ var a = Math.min(min, max);
+ var b = Math.max(min, max);
- if (min > 0 && max > 0) {
- a = Math.min(min, max);
- b = Math.max(min, max);
- }
-
- if (a === b) {
- return a;
- }
-
- if (a > b) {
- return a + '|' + b;
+ if (Math.abs(a - b) === 1) {
+ var result = min + '|' + max;
+ if (options.capture) {
+ return '(' + result + ')';
+ }
+ return result;
}
- a = String(a);
- b = String(b);
+ var isPadded = padding(min) || padding(max);
var positives = [];
var negatives = [];
- if (a < 0) {
- var newMin = 1;
- if (b < 0) {
- newMin = Math.abs(b);
- }
+ var tok = {min: min, max: max, a: a, b: b};
+ if (isPadded) {
+ tok.isPadded = isPadded;
+ tok.maxLen = String(tok.max).length;
+ }
+ if (a < 0) {
+ var newMin = b < 0 ? Math.abs(b) : 1;
var newMax = Math.abs(a);
- negatives = splitToPatterns(newMin, newMax);
- a = 0;
+ negatives = splitToPatterns(newMin, newMax, tok, options);
+ a = tok.a = 0;
}
+
if (b >= 0) {
- positives = splitToPatterns(a, b);
+ positives = splitToPatterns(a, b, tok, options);
}
- var res = siftPatterns(negatives, positives);
- cache.range[key] = res;
- return res;
+ tok.negatives = negatives;
+ tok.positives = positives;
+ tok.result = siftPatterns(negatives, positives, options);
+
+ if (options.capture && (positives.length + negatives.length) > 1) {
+ tok.result = '(' + tok.result + ')';
+ }
+
+ cache[key] = tok;
+ return tok.result;
}
-function siftPatterns(negatives, positives) {
- var onlyNegative = filterPatterns(negatives, positives, '-');
- var onlyPositive = filterPatterns(positives, negatives, '');
- var intersected = filterPatterns(negatives, positives, '-?', true);
- var subpatterns = onlyNegative.concat(intersected || []).concat(onlyPositive || []);
+function siftPatterns(neg, pos, options) {
+ var onlyNegative = filterPatterns(neg, pos, '-', false, options) || [];
+ var onlyPositive = filterPatterns(pos, neg, '', false, options) || [];
+ var intersected = filterPatterns(neg, pos, '-?', true, options) || [];
+ var subpatterns = onlyNegative.concat(intersected).concat(onlyPositive);
return subpatterns.join('|');
}
function splitToRanges(min, max) {
- min = +min;
- max = +max;
+ min = Number(min);
+ max = Number(max);
var nines = 1;
var stops = [max];
var stop = +countNines(min, nines);
while (min <= stop && stop <= max) {
- stops = add(stops, stop);
+ stops = push(stops, stop);
nines += 1;
stop = +countNines(min, nines);
}
@@ -95,7 +103,7 @@ function splitToRanges(min, max) {
stop = countZeros(max + 1, zeros) - 1;
while (min < stop && stop <= max) {
- stops = add(stops, stop);
+ stops = push(stops, stop);
zeros += 1;
stop = countZeros(max + 1, zeros) - 1;
}
@@ -104,11 +112,16 @@ function splitToRanges(min, max) {
return stops;
}
-function rangeToPattern(start, stop) {
- var key = start + ':' + stop;
+/**
+ * Convert a range to a regex pattern
+ * @param {Number} `start`
+ * @param {Number} `stop`
+ * @return {String}
+ */
- if (cache.rangeToPattern.hasOwnProperty(key)) {
- return cache.rangeToPattern[key];
+function rangeToPattern(start, stop, options) {
+ if (start === stop) {
+ return {pattern: String(start), digits: []};
}
var zipped = zip(String(start), String(stop));
@@ -118,9 +131,9 @@ function rangeToPattern(start, stop) {
var digits = 0;
while (++i < len) {
- var current = zipped[i];
- var startDigit = current[0];
- var stopDigit = current[1];
+ var numbers = zipped[i];
+ var startDigit = numbers[0];
+ var stopDigit = numbers[1];
if (startDigit === stopDigit) {
pattern += startDigit;
@@ -134,85 +147,144 @@ function rangeToPattern(start, stop) {
}
if (digits) {
- pattern += '[0-9]';
+ pattern += options.shorthand ? '\\d' : '[0-9]';
}
- if (digits > 1) {
- pattern += limit(digits);
- }
-
- cache.rangeToPattern[key] = pattern;
- return pattern;
-}
-
-/**
- * Zip strings (`for in` can be used on string characters)
- */
-
-function zip(a, b) {
- var arr = [];
- for (var ch in a) arr.push([a[ch], b[ch]]);
- return arr;
+ return { pattern: pattern, digits: [digits] };
}
-function splitToPatterns(min, max) {
+function splitToPatterns(min, max, tok, options) {
var ranges = splitToRanges(min, max);
var len = ranges.length;
var idx = -1;
+ var tokens = [];
var start = min;
- var subpatterns = new Array(len);
+ var prev;
while (++idx < len) {
var range = ranges[idx];
- subpatterns[idx] = rangeToPattern(start, range);
+ var obj = rangeToPattern(start, range, options);
+ var zeros = '';
+
+ if (!tok.isPadded && prev && prev.pattern === obj.pattern) {
+ if (prev.digits.length > 1) {
+ prev.digits.pop();
+ }
+ prev.digits.push(obj.digits[0]);
+ prev.string = prev.pattern + toQuantifier(prev.digits);
+ start = range + 1;
+ continue;
+ }
+
+ if (tok.isPadded) {
+ zeros = padZeros(range, tok);
+ }
+
+ obj.string = zeros + obj.pattern + toQuantifier(obj.digits);
+ tokens.push(obj);
start = range + 1;
+ prev = obj;
}
- return subpatterns;
+
+ return tokens;
}
-function filterPatterns(arr, comparison, prefix, intersection) {
- var len = arr.length, i = -1;
- var intersected = [];
+function filterPatterns(arr, comparison, prefix, intersection, options) {
var res = [];
- while (++i < len) {
- var ele = arr[i];
- if (!intersection && comparison.indexOf(ele) === -1) {
+ for (var i = 0; i < arr.length; i++) {
+ var tok = arr[i];
+ var ele = tok.string;
+
+ if (options.relaxZeros !== false) {
+ if (prefix === '-' && ele.charAt(0) === '0') {
+ if (ele.charAt(1) === '{') {
+ ele = '0*' + ele.replace(/^0\{\d+\}/, '');
+ } else {
+ ele = '0*' + ele.slice(1);
+ }
+ }
+ }
+
+ if (!intersection && !contains(comparison, 'string', ele)) {
res.push(prefix + ele);
}
- if (intersection && comparison.indexOf(ele) !== -1) {
- intersected.push(prefix + ele);
+
+ if (intersection && contains(comparison, 'string', ele)) {
+ res.push(prefix + ele);
}
}
- return intersection ? intersected : res;
+ return res;
}
-function countNines(num, len) {
- return String(num).slice(0, -len) + repeat('9', len);
+/**
+ * Zip strings (`for in` can be used on string characters)
+ */
+
+function zip(a, b) {
+ var arr = [];
+ for (var ch in a) arr.push([a[ch], b[ch]]);
+ return arr;
+}
+
+function compare(a, b) {
+ return a > b ? 1 : b > a ? -1 : 0;
+}
+
+function push(arr, ele) {
+ if (arr.indexOf(ele) === -1) arr.push(ele);
+ return arr;
+}
+
+function contains(arr, key, val) {
+ for (var i = 0; i < arr.length; i++) {
+ if (arr[i][key] === val) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function countNines(min, len) {
+ return String(min).slice(0, -len) + repeat('9', len);
}
function countZeros(integer, zeros) {
return integer - (integer % Math.pow(10, zeros));
}
-function limit(str) {
- return '{' + str + '}';
+function toQuantifier(digits) {
+ var start = digits[0];
+ var stop = digits[1] ? (',' + digits[1]) : '';
+ if (!stop && (!start || start === 1)) {
+ return '';
+ }
+ return '{' + start + stop + '}';
}
function toCharacterClass(a, b) {
- return '[' + a + '-' + b + ']';
+ return '[' + a + ((b - a === 1) ? '' : '-') + b + ']';
}
-function compare(a, b) {
- return a - b;
+function padding(str) {
+ return /^-?(0+)\d/.exec(str);
}
-function add(arr, ele) {
- if (arr.indexOf(ele) === -1) {
- arr.push(ele);
+function padZeros(val, tok) {
+ if (tok.isPadded) {
+ var diff = Math.abs(tok.maxLen - String(val).length);
+ switch (diff) {
+ case 0:
+ return '';
+ case 1:
+ return '0';
+ default: {
+ return '0{' + diff + '}';
+ }
+ }
}
- return arr;
+ return val;
}
/**
diff --git a/package.json b/package.json
index 9c1bd1f..2a2f239 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,16 @@
{
"name": "to-regex-range",
- "description": "Returns a regex-compatible range from two numbers, min and max, with 855,412 generated unit tests to validate it's accuracy! Useful for creating regular expressions to validate numbers, ranges, years, etc. Returns a string, allowing the returned value to be used in regular expressions generated by other libraries.",
- "version": "0.2.0",
- "homepage": "https://github.com/jonschlinkert/to-regex-range",
+ "description": "Pass two numbers, get a regex-compatible source string for matching ranges. Validated against more than 2.78 million test assertions.",
+ "version": "3.0.0",
+ "homepage": "https://github.com/micromatch/to-regex-range",
"author": "Jon Schlinkert (https://github.com/jonschlinkert)",
- "repository": "jonschlinkert/to-regex-range",
+ "contributors": [
+ "Jon Schlinkert (http://twitter.com/jonschlinkert)",
+ "Rouven Weßling (www.rouvenwessling.de)"
+ ],
+ "repository": "micromatch/to-regex-range",
"bugs": {
- "url": "https://github.com/jonschlinkert/to-regex-range/issues"
+ "url": "https://github.com/micromatch/to-regex-range/issues"
},
"license": "MIT",
"files": [
@@ -20,18 +24,22 @@
"test": "mocha"
},
"dependencies": {
- "is-number": "^2.1.0",
- "repeat-string": "^1.5.4"
+ "is-number": "^4.0.0",
+ "repeat-string": "^1.6.1"
},
"devDependencies": {
- "gulp-format-md": "^0.1.9",
- "mocha": "^2.4.5"
+ "fill-range": "^5.0.0",
+ "gulp-format-md": "^1.0.0",
+ "mocha": "^3.5.0",
+ "text-table": "^0.2.0",
+ "time-diff": "^0.3.1"
},
"keywords": [
"alpha",
"alphabetical",
"bash",
"brace",
+ "date",
"expand",
"expansion",
"glob",
@@ -43,7 +51,10 @@
"range",
"ranges",
"regex",
- "sh"
+ "sequence",
+ "sh",
+ "to",
+ "year"
],
"verb": {
"related": {
@@ -66,8 +77,11 @@
"lint": {
"reflinks": true
},
+ "helpers": [
+ "./examples.js"
+ ],
"reflinks": [
- "verb"
+ "micromatch"
]
}
}
diff --git a/test/support/index.js b/test/support/index.js
deleted file mode 100644
index 619e13d..0000000
--- a/test/support/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-
-var utils = module.exports;
-
-// TODO: publish as lib
-utils.toRange = function toRange(start, stop, step) {
- step = step || 1;
- var arr = new Array((stop - start) / step);
- var num = 0;
-
- for (var i = start; i <= stop; i += step) {
- arr[num++] = i;
- }
- return arr;
-};
diff --git a/test/test.js b/test/test.js
deleted file mode 100644
index b7dcdff..0000000
--- a/test/test.js
+++ /dev/null
@@ -1,174 +0,0 @@
-'use strict';
-
-require('mocha');
-var assert = require('assert');
-var utils = require('./support');
-var toRange = require('..');
-var count = 0;
-
-function toRegex(min, max) {
- return new RegExp('^(' + toRange(min, max) + ')$');
-}
-
-function match(min, max) {
- var regex = toRegex(min, max);
- return function(num) {
- return regex.test(String(num));
- };
-}
-
-function verifyRange(min, max, from, to) {
- var isMatch = match(min, max);
- var range = utils.toRange(from, to);
- var len = range.length, i = -1;
-
- while (++i < len) {
- var num = range[i];
- if (min <= num && num <= max) {
- assert(isMatch(num));
- } else {
- assert(!isMatch(num));
- }
- count++;
- }
-}
-
-describe('range', function() {
- it('should throw an error when the first arg is invalid:', function() {
- assert.throws(function() {
- toRange();
- }, /toRegexRange: first argument is invalid/);
- });
-
- it('should throw an error when the second arg is invalid:', function() {
- assert.throws(function() {
- toRange(1, {});
- }, /toRegexRange: second argument is invalid/);
- });
-});
-
-describe('minimum / maximum', function() {
- it('should reverse `min/max` when the min is larger than the max:', function() {
- assert.equal(toRange(55, 10), '1[0-9]|[2-4][0-9]|5[0-5]');
- });
-});
-
-describe('ranges', function() {
- it('should return the number when only one argument is passed:', function() {
- assert.equal(toRange(5), '5');
- });
-
- it('should not return a range when both numbers are the same:', function() {
- assert.equal(toRange(5, 5), '5');
- });
-
- it('should support ranges than 10:', function() {
- assert.equal(toRange(1, 5), '[1-5]');
- });
-
- it('should support strings:', function() {
- assert.equal(toRange('1', '5'), '[1-5]');
- assert.equal(toRange('10', '50'), '1[0-9]|[2-4][0-9]|50');
- });
-
- it('should generate regular expressions from the given pattern', function() {
- assert.equal(toRange(1, 1), '1');
- assert.equal(toRange(0, 1), '[0-1]');
- assert.equal(toRange(-1, -1), '-1');
- assert.equal(toRange(-1, -10), '-1|-10');
- assert.equal(toRange(-1, 0), '-1|0');
- assert.equal(toRange(-1, 1), '-1|[0-1]');
- assert.equal(toRange(-4, -2), '-[2-4]');
- assert.equal(toRange(-3, 1), '-[1-3]|[0-1]');
- assert.equal(toRange(-2, 0), '-[1-2]|0');
- assert.equal(toRange(0, 2), '[0-2]');
- assert.equal(toRange(-1, 3), '-1|[0-3]');
- assert.equal(toRange(65666, 65667), '6566[6-7]');
- assert.equal(toRange(12, 3456), '1[2-9]|[2-9][0-9]|[1-9][0-9]{2}|[1-2][0-9]{3}|3[0-3][0-9]{2}|34[0-4][0-9]|345[0-6]');
- assert.equal(toRange(1, 3456), '[1-9]|[1-9][0-9]|[1-9][0-9]{2}|[1-2][0-9]{3}|3[0-3][0-9]{2}|34[0-4][0-9]|345[0-6]');
- assert.equal(toRange(1, 10), '[1-9]|10');
- assert.equal(toRange(1, 19), '[1-9]|1[0-9]');
- assert.equal(toRange(1, 99), '[1-9]|[1-9][0-9]');
- });
-
- it('should optimize regexes', function() {
- assert.equal(toRange(-9, 9), '-[1-9]|[0-9]');
- assert.equal(toRange(-19, 19), '-[1-9]|-?1[0-9]|[0-9]');
- assert.equal(toRange(-29, 29), '-[1-9]|-?[1-2][0-9]|[0-9]');
- assert.equal(toRange(-99, 99), '-[1-9]|-?[1-9][0-9]|[0-9]');
- assert.equal(toRange(-999, 999), '-[1-9]|-?[1-9][0-9]|-?[1-9][0-9]{2}|[0-9]');
- assert.equal(toRange(-9999, 9999), '-[1-9]|-?[1-9][0-9]|-?[1-9][0-9]{2}|-?[1-9][0-9]{3}|[0-9]');
- });
-});
-
-describe('validate ranges', function() {
- after(function() {
- var num = (+(+(count).toFixed(2))).toLocaleString();
- console.log();
- console.log(' ', num, 'patterns tested');
- });
-
- it('should support equal numbers:', function() {
- verifyRange(1, 1, 0, 100);
- verifyRange(65443, 65443, 65000, 66000);
- verifyRange(192, 1000, 0, 1000);
- });
-
- it('should support large numbers:', function() {
- verifyRange(100019999300000, 100020000300000, 100019999999999, 100020000100000);
- });
-
- it('should support repeated digits:', function() {
- verifyRange(10331, 20381, 0, 99999);
- });
-
- it('should support repeated zeros:', function() {
- verifyRange(10031, 20081, 0, 59999);
- verifyRange(10000, 20000, 0, 59999);
- });
-
- it('should support zero one:', function() {
- verifyRange(10301, 20101, 0, 99999);
- });
-
- it('should support repetead ones:', function() {
- verifyRange(102, 111, 0, 1000);
- });
-
- it('should support small diffs:', function() {
- verifyRange(102, 110, 0, 1000);
- verifyRange(102, 130, 0, 1000);
- });
-
- it('should support random ranges:', function() {
- verifyRange(4173, 7981, 0, 99999);
- });
-
- it('should support one digit numbers:', function() {
- verifyRange(3, 7, 0, 99);
- });
-
- it('should support one digit at bounds:', function() {
- verifyRange(1, 9, 0, 1000);
- });
-
- it('should support power of ten:', function() {
- verifyRange(1000, 8632, 0, 99999);
- });
-
- it('should work with numbers of varying lengths:', function() {
- verifyRange(1030, 20101, 0, 99999);
- verifyRange(13, 8632, 0, 10000);
- });
-
- it('should support small ranges:', function() {
- verifyRange(9, 11, 0, 100);
- verifyRange(19, 21, 0, 100);
- });
-
- it('should support big ranges:', function() {
- verifyRange(90, 98009, 0, 98999);
- verifyRange(999, 10000, 1, 20000);
- });
-});
-
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-to-regex-range.git
More information about the Pkg-javascript-commits
mailing list