diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62f414832e508b..d3ca53699f9d03 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -151,6 +151,9 @@ $ ./configure && make -j8 test Make sure the linter is happy and that all tests pass. Please, do not submit patches that fail either check. +Running `make test` will run the linter as well unless one or more tests fail. +If you want to run the linter without running tests, use `make lint`. + If you are updating tests and just want to run a single test to check it, you can use this syntax to run it exactly as the test harness would: diff --git a/Makefile b/Makefile index a13d7388179dab..f316b21ec18b8b 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,7 @@ cctest: all v8: tools/make-v8.sh v8 - $(MAKE) -C deps/v8 $(V8_ARCH) $(V8_BUILD_OPTIONS) + $(MAKE) -C deps/v8 $(V8_ARCH).$(BUILDTYPE_LOWER) $(V8_BUILD_OPTIONS) test: | cctest # Depends on 'all'. $(PYTHON) tools/test.py --mode=release doctool message pseudo-tty parallel sequential -J @@ -227,7 +227,7 @@ test-timers: test-timers-clean: $(MAKE) --directory=tools clean -test-v8: +test-v8: v8 # note: performs full test unless QUICKCHECK is specified deps/v8/tools/run-tests.py --arch=$(V8_ARCH) \ --mode=$(BUILDTYPE_LOWER) $(V8_TEST_NO_I18N) $(QUICKCHECK_ARG) \ @@ -235,14 +235,14 @@ test-v8: --shell-dir=$(PWD)/deps/v8/out/$(V8_ARCH).$(BUILDTYPE_LOWER) \ $(TAP_V8) -test-v8-intl: +test-v8-intl: v8 # note: performs full test unless QUICKCHECK is specified deps/v8/tools/run-tests.py --arch=$(V8_ARCH) \ --mode=$(BUILDTYPE_LOWER) --no-presubmit $(QUICKCHECK_ARG) \ --shell-dir=deps/v8/out/$(V8_ARCH).$(BUILDTYPE_LOWER) intl \ $(TAP_V8_INTL) -test-v8-benchmarks: +test-v8-benchmarks: v8 deps/v8/tools/run-tests.py --arch=$(V8_ARCH) --mode=$(BUILDTYPE_LOWER) \ --download-data $(QUICKCHECK_ARG) --no-presubmit \ --shell-dir=deps/v8/out/$(V8_ARCH).$(BUILDTYPE_LOWER) benchmarks \ diff --git a/README.md b/README.md index 50e84e0e7fc37c..10aadde17ba7d5 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,7 @@ information about the governance of the Node.js project, see * [benjamingr](https://github.com/benjamingr) - **Benjamin Gruenbaum** <benjamingr@gmail.com> * [bmeck](https://github.com/bmeck) - **Bradley Farias** <bradley.meck@gmail.com> * [brendanashworth](https://github.com/brendanashworth) - **Brendan Ashworth** <brendan.ashworth@me.com> +* [bzoz](https://github.com/bzoz) - **Bartosz Sosnowski** <bartosz@janeasystems.com> * [calvinmetcalf](https://github.com/calvinmetcalf) - **Calvin Metcalf** <calvin.metcalf@gmail.com> * [claudiorodriguez](https://github.com/claudiorodriguez) - **Claudio Rodriguez** <cjrodr@yahoo.com> * [domenic](https://github.com/domenic) - **Domenic Denicola** <d@domenic.me> @@ -186,6 +187,7 @@ information about the governance of the Node.js project, see * [joaocgreis](https://github.com/joaocgreis) - **João Reis** <reis@janeasystems.com> * [julianduque](https://github.com/julianduque) - **Julian Duque** <julianduquej@gmail.com> * [JungMinu](https://github.com/JungMinu) - **Minwoo Jung** <jmwsoft@gmail.com> +* [lance](https://github.com/lance) - **Lance Ball** <lball@redhat.com> * [lxe](https://github.com/lxe) - **Aleksey Smolenchuk** <lxe@lxe.co> * [matthewloring](https://github.com/matthewloring) - **Matthew Loring** <mattloring@google.com> * [mcollina](https://github.com/mcollina) - **Matteo Collina** <matteo.collina@gmail.com> diff --git a/benchmark/http/_chunky_http_client.js b/benchmark/http/_chunky_http_client.js index 158be5a0eb6424..bde4eed7444e6f 100644 --- a/benchmark/http/_chunky_http_client.js +++ b/benchmark/http/_chunky_http_client.js @@ -50,8 +50,6 @@ function main(conf) { } } - var success = 0; - var failure = 0; var min = 10; var size = 0; var mod = 317; @@ -69,14 +67,12 @@ function main(conf) { if ((d.length === pattern.length && d === pattern) || (d.length > pattern.length && d.slice(0, pattern.length) === pattern)) { - success += 1; did = true; } else { pattern = 'HTTP/1.1 '; if ((d.length === pattern.length && d === pattern) || (d.length > pattern.length && d.slice(0, pattern.length) === pattern)) { - failure += 1; did = true; } } diff --git a/benchmark/static_http_server.js b/benchmark/static_http_server.js index 43c493675933e7..13067d7b3eb890 100644 --- a/benchmark/static_http_server.js +++ b/benchmark/static_http_server.js @@ -6,7 +6,6 @@ var port = 12346; var n = 700; var bytes = 1024 * 5; -var requests = 0; var responses = 0; var body = 'C'.repeat(bytes); @@ -37,6 +36,5 @@ server.listen(port, function() { }); }); req.id = i; - requests++; } }); diff --git a/doc/api/child_process.md b/doc/api/child_process.md index cc8b8ce8c67b97..db70d06644e500 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -160,8 +160,8 @@ The `stdout` and `stderr` arguments passed to the callback will contain the stdout and stderr output of the child process. By default, Node.js will decode the output as UTF-8 and pass strings to the callback. The `encoding` option can be used to specify the character encoding used to decode the stdout and -stderr output. If `encoding` is `'buffer'`, `Buffer` objects will be passed to -the callback instead. +stderr output. If `encoding` is `'buffer'`, or an unrecognized character +encoding, `Buffer` objects will be passed to the callback instead. The `options` argument may be passed as the second argument to customize how the process is spawned. The default options are: @@ -230,8 +230,8 @@ The `stdout` and `stderr` arguments passed to the callback will contain the stdout and stderr output of the child process. By default, Node.js will decode the output as UTF-8 and pass strings to the callback. The `encoding` option can be used to specify the character encoding used to decode the stdout and -stderr output. If `encoding` is `'buffer'`, `Buffer` objects will be passed to -the callback instead. +stderr output. If `encoding` is `'buffer'`, or an unrecognized character +encoding, `Buffer` objects will be passed to the callback instead. ### child_process.fork(modulePath[, args][, options]) @@ -414,7 +414,7 @@ const spawn = require('child_process').spawn; const child = spawn(process.argv[0], ['child_program.js'], { detached: true, - stdio: ['ignore'] + stdio: 'ignore' }); child.unref(); diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 104897660f7107..d3fb499b89f45b 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -167,12 +167,12 @@ It is not emitted in the worker. ### Event: 'message' * `message` {Object} +* `handle` {undefined|Object} -Similar to the `cluster.on('message')` event, but specific to this worker. - -This event is the same as the one provided by [`child_process.fork()`][]. +Similar to the `cluster.on('message')` event, but specific to this worker. In a +worker you can also use `process.on('message')`. -In a worker you can also use `process.on('message')`. +See [`process` event: `'message'`][]. As an example, here is a cluster that keeps count of the number of requests in the master process using the message system: @@ -689,3 +689,4 @@ socket.on('data', (id) => { [Child Process module]: child_process.html#child_process_child_process_fork_modulepath_args_options [child_process event: 'exit']: child_process.html#child_process_event_exit [child_process event: 'message']: child_process.html#child_process_event_message +[`process` event: `'message'`]: process.html#process_event_message diff --git a/doc/api/crypto.md b/doc/api/crypto.md index f0d21238be3670..43e6167d2ef520 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -794,7 +794,7 @@ verify.end(); const public_key = getPublicKeySomehow(); const signature = getSignatureToVerify(); -console.log(sign.verify(public_key, signature)); +console.log(verify.verify(public_key, signature)); // Prints true or false ``` diff --git a/doc/api/dns.md b/doc/api/dns.md index 3a1535359a091d..699198fa3b9967 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -158,7 +158,9 @@ Valid values for `rrtype` are: * `'NAPTR'` - name authority pointer record The `callback` function has arguments `(err, addresses)`. When successful, -`addresses` will be an array. The type of each item in `addresses` is +`addresses` will be an array, except when resolving an SOA record which returns +an object structured in the same manner as one returned by the +[`dns.resolveSoa()`][] method. The type of each item in `addresses` is determined by the record type, and described in the documentation for the corresponding lookup methods. @@ -379,6 +381,7 @@ uses. For instance, _they do not use the configuration from `/etc/hosts`_. [`dns.lookup()`]: #dns_dns_lookup_hostname_options_callback [`dns.resolve()`]: #dns_dns_resolve_hostname_rrtype_callback [`dns.resolve4()`]: #dns_dns_resolve4_hostname_callback +[`dns.resolveSoa()`]: #dns_dns_resolvesoa_hostname_callback [`Error`]: errors.html#errors_class_error [Implementation considerations section]: #dns_implementation_considerations [supported `getaddrinfo` flags]: #dns_supported_getaddrinfo_flags diff --git a/doc/api/http.md b/doc/api/http.md index b06886f09d2738..4723ebfcd1c12d 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -207,6 +207,13 @@ The request implements the [Writable Stream][] interface. This is an Emitted when the request has been aborted by the client. This event is only emitted on the first call to `abort()`. +### Event: 'aborted' + +`function () { }` + +Emitted when the request has been aborted by the server and the network +socket has closed. + ### Event: 'connect' `function (response, socket, head) { }` @@ -516,8 +523,8 @@ already been bound to a port or domain socket. Listening on a file descriptor is not supported on Windows. -This function is asynchronous. The last parameter `callback` will be added as -a listener for the `'listening'` event. See also [`net.Server.listen()`][]. +This function is asynchronous. `callback` will be added as a listener for the +`'listening'` event. See also [`net.Server.listen()`][]. Returns `server`. @@ -525,15 +532,15 @@ Returns `server`. Start a UNIX socket server listening for connections on the given `path`. -This function is asynchronous. The last parameter `callback` will be added as -a listener for the `'listening'` event. See also [`net.Server.listen(path)`][]. +This function is asynchronous. `callback` will be added as a listener for the +`'listening'` event. See also [`net.Server.listen(path)`][]. ### server.listen(port[, hostname][, backlog][, callback]) Begin accepting connections on the specified `port` and `hostname`. If the `hostname` is omitted, the server will accept connections on any IPv6 address (`::`) when IPv6 is available, or any IPv4 address (`0.0.0.0`) otherwise. Use a -port value of zero to have the operating system assign an available port. +port value of `0` to have the operating system assign an available port. To listen to a unix socket, supply a filename instead of port and hostname. @@ -542,8 +549,8 @@ The actual length will be determined by your OS through sysctl settings such as `tcp_max_syn_backlog` and `somaxconn` on linux. The default value of this parameter is 511 (not 512). -This function is asynchronous. The last parameter `callback` will be added as -a listener for the `'listening'` event. See also [`net.Server.listen(port)`][]. +This function is asynchronous. `callback` will be added as a listener for the +`'listening'` event. See also [`net.Server.listen(port)`][]. ### server.maxHeadersCount @@ -776,8 +783,8 @@ be called multiple times to provide successive parts of the body. `chunk` can be a string or a buffer. If `chunk` is a string, the second parameter specifies how to encode it into a byte stream. -By default the `encoding` is `'utf8'`. The last parameter `callback` -will be called when this chunk of data is flushed. +By default the `encoding` is `'utf8'`. `callback` will be called when this chunk +of data is flushed. **Note**: This is the raw HTTP body and has nothing to do with higher-level multi-part body encodings that may be used. @@ -853,6 +860,13 @@ headers and data. It implements the [Readable Stream][] interface, as well as the following additional events, methods, and properties. +### Event: 'aborted' + +`function () { }` + +Emitted when the request has been aborted by the client and the network +socket has closed. + ### Event: 'close' `function () { }` @@ -996,7 +1010,7 @@ $ node } ``` -If you would like to extract the params from the query string, +If you would like to extract the parameters from the query string, you can use the `require('querystring').parse` function, or pass `true` as the second argument to `require('url').parse`. Example: diff --git a/doc/api/process.md b/doc/api/process.md index eb14cc7158e019..f4a31a85806e1c 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -123,7 +123,7 @@ code without properly recovering from the exception can cause additional unforeseen and unpredictable issues. Exceptions thrown from within the event handler will not be caught. Instead the -process will exit with a non zero exit code and the stack trace will be printed. +process will exit with a non-zero exit code and the stack trace will be printed. This is to avoid infinite recursion. Attempting to resume normally after an uncaught exception can be similar to diff --git a/doc/ctc-meetings/2016-06-15.md b/doc/ctc-meetings/2016-06-15.md new file mode 100644 index 00000000000000..87fc0dc243d3a2 --- /dev/null +++ b/doc/ctc-meetings/2016-06-15.md @@ -0,0 +1,174 @@ +# Node Foundation CTC Meeting 2016-06-15 + +## Links + +* **Audio Recording**: https://www.youtube.com/watch?v=qWX8i9SKatQ +* **GitHub Issue**: https://github.com/nodejs/node/issues/7307 +* **Minutes Google Doc**: +* _Previous Minutes Google Doc: _ + +## Present + +* Bradley Meck @bmeck (observer/GoDaddy) +* Сковорода Никита Андреевич @ChALkeR (CTC) +* Chris Dickinson @chrisdickinson (CTC) +* Evan Lucas @evanlucas (CTC) +* Jeremiah Senkpiel @Fishrock123 (CTC) +* John-David Dalton @jdalton (observer/Microsoft) +* Josh Gavant @joshgav (observer/Microsoft) +* Michael Dawson @mhdawson (CTC) +* Brian White @mscdex (CTC) +* Ali Ijaz Sheikh @ofrobots (CTC) +* Alexis Campailla @orangemocha (CTC) +* Rod Vagg @rvagg (CTC) +* Rich Trott @Trott (CTC) +* Trevor Norris @trevnorris (CTC) + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* url: return valid file: urls fom url.format() [#7234](https://github.com/nodejs/node/pull/7234) +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +### Standup + +* Bradley Meck @bmeck + * fleshing out a proposal for if we could disambiguate the grammars for Script and Module. + +* Сковорода Никита Андреевич @ChALkeR (CTC) + * some issue/PRs reviews + +* Chris Dickinson @chrisdickinson (CTC) + * NodeConf + * modules.guide + +* Evan Lucas @evanlucas (CTC) + * Preparing for security release + +* Jeremiah Senkpiel @Fishrock123 (CTC) + * (Previous week: fixed the primary OS X stdio bug) + * NodeConf + +* Fedor Indutny @indutny (CTC) + * fixing bugs, reviewing PRs, working on llnode + +* Josh Gavant @joshgav + * debug protocol stuff + +* Michael Dawson @mhdawson (CTC) + * Still chasing PPC machine issues + * AIX/malloc(0) issue + * ABI stable module API work with Stefan/Ian, filling in Nan examples + * Input on some benchmarking related PRs + * Other misc reviews/lands + * Keeping up with issues + +* Brian White @mscdex (CTC) + * Landed some old PRs + * Submitting PRs to fix some regressions + * Reviewed PRs and issues + +* Ali Ijaz Sheikh @ofrobots (CTC) + * More work on v8_inspector + * Starting to look at backporting some V8 fixes for LTS + +* Alexis Campailla @orangemocha (CTC) + * Landed a fix for node-gyp, broke with VS update 3 + +* Rod Vagg @rvagg (CTC) + * Alpine Linux in CI + * Security release hoo haa + * Reviews & discussions + * Electron / Node relationship + * New CTC repo + * Jenkins upkeep + +* Rich Trott @Trott (CTC) + * Setting up the next onboarding + * Facilitated a session on releases at NodeConf. Will share notes with Build WG, LTS WG, and people who can sign releases. + +* Trevor Norris @trevnorris (CTC) + * Finished updating AsyncWrap EP and now investigating proposed implementation. + * Helping identify old issue in Atom editor in regards to writing to disk. + + +### Review of last meeting +* Tracking issue: stdio problems [#6980](https://github.com/nodejs/node/issues/6980) +* module: expose `Module._runInThisContext` [#6288](https://github.com/nodejs/node/pull/6288) + + +## Minutes + + +### url: return valid file: urls from url.format() [#7234](https://github.com/nodejs/node/pull/7234) + +@trott: semver-major change, needs approval from CTC. +Real fix will be @jasnell’s HTTP compliance work. + +In browsers `file:/home/joshgav/myfile.txt` is auto-corrected to `file:///home/joshgav/myfile.txt` (i.e. slashes are prepended to the path and hostname is an empty string). This change institutes the same in Node.js. + +Are there other protocols which require additional slashes (`//`) if hostname isn’t specified? Yes, but hard to heuristically determine if needed. + + +### http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +Replace headers object ({}) in req/res with StorageObject, which doesn’t delegate to Object.prototype. But this will break anyone using regular `Object` methods on header props. + +@trevnorris: Why don’t we intercept calls to properties with checks to an internal dictionary of actual headers? If the key isn’t there, then try to call Object.prototype. + +How would that effect perf? + +It’s the right decision because otherwise can’t use headers with certain names like `__proto__`. + +Better to do a deprecation cycle. How? Insert something (proxy) between actual call to property, would issue deprecation warning first. This would be temporary, eventually this interceptor/proxy would go away. + + +### ES6 Modules [node-eps/002-es6-modules.md](https://github.com/nodejs/node-eps/blob/master/002-es6-modules.md) + +Need to disambiguate ES6 modules and regular scripts (which include CJS modules). Cannot determine if file is module, script, etc. from code itself. For this reason Node decided to use `.mjs` extension for ES6 modules. + +New proposal: If `import` or `export` keywords are in module code, then use module goal. So no need for extra metadata or file extension. But would have to parse file to check for presence of these keywords. + +https://github.com/bmeck/UnambiguousJavaScriptGrammar +replaces https://github.com/nodejs/node-eps/blob/master/002-es6-modules.md#51-determining-if-source-is-an-es-module + +This would be part of ECMA262 so browsers would do the same, but needs to be ironed out in TC39. On [agenda][TC39 Agenda] for 7/26 TC39 meeting. + +[TC39 Agenda]: https://github.com/tc39/agendas/blob/master/2016/07.md + +What if nothing is imported or exported? Could do `export default null` to export nothing. + +Starting off, preferred goal when preparing code would be CommonJS/script, later on could change to ES6/module. + +Caching is more feasible. + +Provides more seamless flow from CJS to ES6 in the future. + +Will packaging tools need to implement parsing logic too to package properly? Yes, but there are possibilities listed in the repo. + +What other differences between scripts and modules? +- `await` keyword only in modules according to ECMA262 +- `modules.root` in package.json is intended to allow mirrored directory structure for use with ES6; but technically all it does is redirect file system calls and it could be used for other purposes, so it’s not reliable. + +Purpose of modules.root - allows redirection within a module, e.g. `module/file.js` doesn’t necessarily resolve to `./file.js` within the directory, could be redirected to `${module.root}/file.js`. This allows side-by-side CJS and ES6 among other things. + +What about for human reading? How can people differentiate at a glance between CJS and ES6? +- `import`’s are generally at the top, `export`s at the bottom. If you see `import` it’s an ES6 module. + +How are browsers dealing with this? Older browsers which encounter ` - - - -``` +If not using `xregexp-all.js`, first include the Unicode Base script and then one or more of the addons for Unicode blocks, categories, properties, or scripts. Then you can do this: @@ -118,14 +120,7 @@ XRegExp uses Unicode 8.0.0. ### XRegExp.build -In browsers, first include the script: - -```html - - -``` - -You can then build regular expressions using named subpatterns, for readability and pattern reuse: +Build regular expressions using named subpatterns, for readability and pattern reuse: ```js var time = XRegExp.build('(?x)^ {{hours}} ({{minutes}}) $', { @@ -146,14 +141,7 @@ See also: *[Creating Grammatical Regexes Using XRegExp.build](http://blog.steven ### XRegExp.matchRecursive -In browsers, first include the script: - -```html - - -``` - -You can then match recursive constructs using XRegExp pattern strings as left and right delimiters: +Match recursive constructs using XRegExp pattern strings as left and right delimiters: ```js var str = '(t((e))s)t()(ing)'; @@ -196,13 +184,7 @@ XRegExp.matchRecursive(str, '<', '>', 'gy'); ## Installation and usage -In browsers: - -```html - -``` - -Or, to bundle XRegExp with all of its addons: +In browsers (bundle XRegExp with all of its addons): ```html @@ -232,12 +214,8 @@ require({paths: {xregexp: 'xregexp-all'}}, ['xregexp'], function(XRegExp) { XRegExp copyright 2007-2016 by [Steven Levithan](http://stevenlevithan.com/). -Tools: Unicode range generators by [Mathias Bynens](http://mathiasbynens.be/), and adapted from his [unicode-data](https://github.com/mathiasbynens/unicode-data) project. - -Tests: Uses [Jasmine](http://jasmine.github.io/) for unit tests, and [Benchmark.js](http://benchmarkjs.com) for performance tests. - -Prior art: `XRegExp.build` inspired by [Lea Verou](http://lea.verou.me/)'s [RegExp.create](http://lea.verou.me/2011/03/create-complex-regexps-more-easily/). `XRegExp.union` inspired by [Ruby](http://www.ruby-lang.org/). XRegExp's syntax extensions and flags come from [Perl](http://www.perl.org/), [.NET](http://www.microsoft.com/net), etc. +Unicode range generators by [Mathias Bynens](http://mathiasbynens.be/), and adapted from his [unicode-data](https://github.com/mathiasbynens/unicode-data) project. Uses [Jasmine](http://jasmine.github.io/) for unit tests, and [Benchmark.js](http://benchmarkjs.com) for performance tests. `XRegExp.build` inspired by [RegExp.create](http://lea.verou.me/2011/03/create-complex-regexps-more-easily/) by [Lea Verou](http://lea.verou.me/). `XRegExp.union` inspired by [Ruby](http://www.ruby-lang.org/). XRegExp's syntax extensions and flags come from [Perl](http://www.perl.org/), [.NET](http://www.microsoft.com/net), etc. -All code, including addons, tools, and tests, is released under the terms of the [MIT](http://mit-license.org/) license. +All code, including addons, tools, and tests, is released under the terms of the [MIT License](http://mit-license.org/). Fork me to show support, fix, and extend. diff --git a/tools/eslint/node_modules/xregexp/package.json b/tools/eslint/node_modules/xregexp/package.json index 76cb517195c525..8fe0d7f5027066 100644 --- a/tools/eslint/node_modules/xregexp/package.json +++ b/tools/eslint/node_modules/xregexp/package.json @@ -6,14 +6,14 @@ ] ], "_from": "xregexp@>=3.0.0 <4.0.0", - "_id": "xregexp@3.1.0", + "_id": "xregexp@3.1.1", "_inCache": true, "_installable": true, "_location": "/xregexp", "_nodeVersion": "3.3.1", "_npmOperationalInternal": { - "host": "packages-9-west.internal.npmjs.com", - "tmp": "tmp/xregexp-3.1.0.tgz_1456271836601_0.7557942552957684" + "host": "packages-16-east.internal.npmjs.com", + "tmp": "tmp/xregexp-3.1.1.tgz_1463265906533_0.49629145418293774" }, "_npmUser": { "email": "steves_list@hotmail.com", @@ -32,8 +32,8 @@ "_requiredBy": [ "/table" ], - "_resolved": "https://registry.npmjs.org/xregexp/-/xregexp-3.1.0.tgz", - "_shasum": "14d8461e0bdd38224bfee5039a0898fc42fcd336", + "_resolved": "https://registry.npmjs.org/xregexp/-/xregexp-3.1.1.tgz", + "_shasum": "8ee18d75ef5c7cb3f9967f8d29414a6ca5b1a184", "_shrinkwrap": null, "_spec": "xregexp@^3.0.0", "_where": "/Users/trott/io.js/tools/node_modules/table", @@ -51,17 +51,19 @@ }, "directories": {}, "dist": { - "shasum": "14d8461e0bdd38224bfee5039a0898fc42fcd336", - "tarball": "https://registry.npmjs.org/xregexp/-/xregexp-3.1.0.tgz" + "shasum": "8ee18d75ef5c7cb3f9967f8d29414a6ca5b1a184", + "tarball": "https://registry.npmjs.org/xregexp/-/xregexp-3.1.1.tgz" }, "files": [ "src" ], - "gitHead": "bbd5b1c2f759bdf278192be5df70af16342ffa4d", + "gitHead": "37413619ea9f03638bfa92e038e4b4c15645d446", "homepage": "http://xregexp.com/", "keywords": [ "regex", - "regexp" + "regexp", + "regular expression", + "unicode" ], "license": "MIT", "main": "./src/index.js", @@ -81,5 +83,5 @@ "scripts": { "build": "browserify src/index.js --standalone XRegExp > xregexp-all.js" }, - "version": "3.1.0" + "version": "3.1.1" } diff --git a/tools/eslint/node_modules/xregexp/src/addons/build.js b/tools/eslint/node_modules/xregexp/src/addons/build.js index 221cb26fa940cf..843d4a9c962612 100644 --- a/tools/eslint/node_modules/xregexp/src/addons/build.js +++ b/tools/eslint/node_modules/xregexp/src/addons/build.js @@ -1,5 +1,5 @@ /*! - * XRegExp.build 3.1.0 + * XRegExp.build 3.1.1 * * Steven Levithan (c) 2012-2016 MIT License * Inspired by Lea Verou's RegExp.create @@ -8,17 +8,16 @@ module.exports = function(XRegExp) { 'use strict'; - var REGEX_DATA = 'xregexp', - subParts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g, - parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subParts], 'g'); + var REGEX_DATA = 'xregexp'; + var subParts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g; + var parts = XRegExp.union([/\({{([\w$]+)}}\)|{{([\w$]+)}}/, subParts], 'g'); -/** - * Strips a leading `^` and trailing unescaped `$`, if both are present. - * - * @private - * @param {String} pattern Pattern to process. - * @returns {String} Pattern with edge anchors removed. - */ + /** + * Strips a leading `^` and trailing unescaped `$`, if both are present. + * + * @param {String} pattern Pattern to process. + * @returns {String} Pattern with edge anchors removed. + */ function deanchor(pattern) { // Allow any number of empty noncapturing groups before/after anchors, because regexes // built/generated by XRegExp sometimes include them @@ -37,13 +36,12 @@ module.exports = function(XRegExp) { return pattern; } -/** - * Converts the provided value to an XRegExp. Native RegExp flags are not preserved. - * - * @private - * @param {String|RegExp} value Value to convert. - * @returns {RegExp} XRegExp object with XRegExp syntax applied. - */ + /** + * Converts the provided value to an XRegExp. Native RegExp flags are not preserved. + * + * @param {String|RegExp} value Value to convert. + * @returns {RegExp} XRegExp object with XRegExp syntax applied. + */ function asXRegExp(value) { return XRegExp.isRegExp(value) ? (value[REGEX_DATA] && value[REGEX_DATA].captureNames ? @@ -56,31 +54,30 @@ module.exports = function(XRegExp) { XRegExp(value); } -/** - * Builds regexes using named subpatterns, for readability and pattern reuse. Backreferences in the - * outer pattern and provided subpatterns are automatically renumbered to work correctly. Native - * flags used by provided subpatterns are ignored in favor of the `flags` argument. - * - * @memberOf XRegExp - * @param {String} pattern XRegExp pattern using `{{name}}` for embedded subpatterns. Allows - * `({{name}})` as shorthand for `(?{{name}})`. Patterns cannot be embedded within - * character classes. - * @param {Object} subs Lookup object for named subpatterns. Values can be strings or regexes. A - * leading `^` and trailing unescaped `$` are stripped from subpatterns, if both are present. - * @param {String} [flags] Any combination of XRegExp flags. - * @returns {RegExp} Regex with interpolated subpatterns. - * @example - * - * var time = XRegExp.build('(?x)^ {{hours}} ({{minutes}}) $', { - * hours: XRegExp.build('{{h12}} : | {{h24}}', { - * h12: /1[0-2]|0?[1-9]/, - * h24: /2[0-3]|[01][0-9]/ - * }, 'x'), - * minutes: /^[0-5][0-9]$/ - * }); - * time.test('10:59'); // -> true - * XRegExp.exec('10:59', time).minutes; // -> '59' - */ + /** + * Builds regexes using named subpatterns, for readability and pattern reuse. Backreferences in + * the outer pattern and provided subpatterns are automatically renumbered to work correctly. + * Native flags used by provided subpatterns are ignored in favor of the `flags` argument. + * + * @param {String} pattern XRegExp pattern using `{{name}}` for embedded subpatterns. Allows + * `({{name}})` as shorthand for `(?{{name}})`. Patterns cannot be embedded within + * character classes. + * @param {Object} subs Lookup object for named subpatterns. Values can be strings or regexes. A + * leading `^` and trailing unescaped `$` are stripped from subpatterns, if both are present. + * @param {String} [flags] Any combination of XRegExp flags. + * @returns {RegExp} Regex with interpolated subpatterns. + * @example + * + * var time = XRegExp.build('(?x)^ {{hours}} ({{minutes}}) $', { + * hours: XRegExp.build('{{h12}} : | {{h24}}', { + * h12: /1[0-2]|0?[1-9]/, + * h24: /2[0-3]|[01][0-9]/ + * }, 'x'), + * minutes: /^[0-5][0-9]$/ + * }); + * time.test('10:59'); // -> true + * XRegExp.exec('10:59', time).minutes; // -> '59' + */ XRegExp.build = function(pattern, subs, flags) { var inlineFlags = /^\(\?([\w$]+)\)/.exec(pattern), data = {}, diff --git a/tools/eslint/node_modules/xregexp/src/addons/matchrecursive.js b/tools/eslint/node_modules/xregexp/src/addons/matchrecursive.js index 1de3bdc5579cea..6a51b56b732614 100644 --- a/tools/eslint/node_modules/xregexp/src/addons/matchrecursive.js +++ b/tools/eslint/node_modules/xregexp/src/addons/matchrecursive.js @@ -1,5 +1,5 @@ /*! - * XRegExp.matchRecursive 3.1.0 + * XRegExp.matchRecursive 3.1.1 * * Steven Levithan (c) 2009-2016 MIT License */ @@ -7,11 +7,9 @@ module.exports = function(XRegExp) { 'use strict'; -/** - * Returns a match detail object composed of the provided values. - * - * @private - */ + /** + * Returns a match detail object composed of the provided values. + */ function row(name, value, start, end) { return { name: name, @@ -21,56 +19,55 @@ module.exports = function(XRegExp) { }; } -/** - * Returns an array of match strings between outermost left and right delimiters, or an array of - * objects with detailed match parts and position data. An error is thrown if delimiters are - * unbalanced within the data. - * - * @memberOf XRegExp - * @param {String} str String to search. - * @param {String} left Left delimiter as an XRegExp pattern. - * @param {String} right Right delimiter as an XRegExp pattern. - * @param {String} [flags] Any native or XRegExp flags, used for the left and right delimiters. - * @param {Object} [options] Lets you specify `valueNames` and `escapeChar` options. - * @returns {Array} Array of matches, or an empty array. - * @example - * - * // Basic usage - * var str = '(t((e))s)t()(ing)'; - * XRegExp.matchRecursive(str, '\\(', '\\)', 'g'); - * // -> ['t((e))s', '', 'ing'] - * - * // Extended information mode with valueNames - * str = 'Here is
an
example'; - * XRegExp.matchRecursive(str, '', '', 'gi', { - * valueNames: ['between', 'left', 'match', 'right'] - * }); - * // -> [ - * // {name: 'between', value: 'Here is ', start: 0, end: 8}, - * // {name: 'left', value: '
', start: 8, end: 13}, - * // {name: 'match', value: '
an
', start: 13, end: 27}, - * // {name: 'right', value: '
', start: 27, end: 33}, - * // {name: 'between', value: ' example', start: 33, end: 41} - * // ] - * - * // Omitting unneeded parts with null valueNames, and using escapeChar - * str = '...{1}.\\{{function(x,y){return {y:x}}}'; - * XRegExp.matchRecursive(str, '{', '}', 'g', { - * valueNames: ['literal', null, 'value', null], - * escapeChar: '\\' - * }); - * // -> [ - * // {name: 'literal', value: '...', start: 0, end: 3}, - * // {name: 'value', value: '1', start: 4, end: 5}, - * // {name: 'literal', value: '.\\{', start: 6, end: 9}, - * // {name: 'value', value: 'function(x,y){return {y:x}}', start: 10, end: 37} - * // ] - * - * // Sticky mode via flag y - * str = '<1><<<2>>><3>4<5>'; - * XRegExp.matchRecursive(str, '<', '>', 'gy'); - * // -> ['1', '<<2>>', '3'] - */ + /** + * Returns an array of match strings between outermost left and right delimiters, or an array of + * objects with detailed match parts and position data. An error is thrown if delimiters are + * unbalanced within the data. + * + * @param {String} str String to search. + * @param {String} left Left delimiter as an XRegExp pattern. + * @param {String} right Right delimiter as an XRegExp pattern. + * @param {String} [flags] Any native or XRegExp flags, used for the left and right delimiters. + * @param {Object} [options] Lets you specify `valueNames` and `escapeChar` options. + * @returns {Array} Array of matches, or an empty array. + * @example + * + * // Basic usage + * var str = '(t((e))s)t()(ing)'; + * XRegExp.matchRecursive(str, '\\(', '\\)', 'g'); + * // -> ['t((e))s', '', 'ing'] + * + * // Extended information mode with valueNames + * str = 'Here is
an
example'; + * XRegExp.matchRecursive(str, '', '', 'gi', { + * valueNames: ['between', 'left', 'match', 'right'] + * }); + * // -> [ + * // {name: 'between', value: 'Here is ', start: 0, end: 8}, + * // {name: 'left', value: '
', start: 8, end: 13}, + * // {name: 'match', value: '
an
', start: 13, end: 27}, + * // {name: 'right', value: '
', start: 27, end: 33}, + * // {name: 'between', value: ' example', start: 33, end: 41} + * // ] + * + * // Omitting unneeded parts with null valueNames, and using escapeChar + * str = '...{1}.\\{{function(x,y){return {y:x}}}'; + * XRegExp.matchRecursive(str, '{', '}', 'g', { + * valueNames: ['literal', null, 'value', null], + * escapeChar: '\\' + * }); + * // -> [ + * // {name: 'literal', value: '...', start: 0, end: 3}, + * // {name: 'value', value: '1', start: 4, end: 5}, + * // {name: 'literal', value: '.\\{', start: 6, end: 9}, + * // {name: 'value', value: 'function(x,y){return {y:x}}', start: 10, end: 37} + * // ] + * + * // Sticky mode via flag y + * str = '<1><<<2>>><3>4<5>'; + * XRegExp.matchRecursive(str, '<', '>', 'gy'); + * // -> ['1', '<<2>>', '3'] + */ XRegExp.matchRecursive = function(str, left, right, flags, options) { flags = flags || ''; options = options || {}; diff --git a/tools/eslint/node_modules/xregexp/src/addons/unicode-base.js b/tools/eslint/node_modules/xregexp/src/addons/unicode-base.js index 2a323041b60e3e..011a384405e149 100644 --- a/tools/eslint/node_modules/xregexp/src/addons/unicode-base.js +++ b/tools/eslint/node_modules/xregexp/src/addons/unicode-base.js @@ -1,56 +1,44 @@ /*! - * XRegExp Unicode Base 3.1.0 + * XRegExp Unicode Base 3.1.1 * * Steven Levithan (c) 2008-2016 MIT License */ -/** - * Adds base support for Unicode matching: - * - Adds syntax `\p{..}` for matching Unicode tokens. Tokens can be inverted using `\P{..}` or - * `\p{^..}`. Token names ignore case, spaces, hyphens, and underscores. You can omit the braces - * for token names that are a single letter (e.g. `\pL` or `PL`). - * - Adds flag A (astral), which enables 21-bit Unicode support. - * - Adds the `XRegExp.addUnicodeData` method used by other addons to provide character data. - * - * Unicode Base relies on externally provided Unicode character data. Official addons are available - * to provide data for Unicode categories, scripts, blocks, and properties. - * - * @requires XRegExp - */ module.exports = function(XRegExp) { 'use strict'; -// Storage for Unicode data + /** + * Adds base support for Unicode matching: + * - Adds syntax `\p{..}` for matching Unicode tokens. Tokens can be inverted using `\P{..}` or + * `\p{^..}`. Token names ignore case, spaces, hyphens, and underscores. You can omit the + * braces for token names that are a single letter (e.g. `\pL` or `PL`). + * - Adds flag A (astral), which enables 21-bit Unicode support. + * - Adds the `XRegExp.addUnicodeData` method used by other addons to provide character data. + * + * Unicode Base relies on externally provided Unicode character data. Official addons are + * available to provide data for Unicode categories, scripts, blocks, and properties. + * + * @requires XRegExp + */ + + // ==--------------------------== + // Private stuff + // ==--------------------------== + + // Storage for Unicode data var unicode = {}; -/* ============================== - * Private functions - * ============================== */ + // Reuse utils + var dec = XRegExp._dec; + var hex = XRegExp._hex; + var pad4 = XRegExp._pad4; -// Generates a token lookup name: lowercase, with hyphens, spaces, and underscores removed + // Generates a token lookup name: lowercase, with hyphens, spaces, and underscores removed function normalize(name) { return name.replace(/[- _]+/g, '').toLowerCase(); } -// Adds leading zeros if shorter than four characters - function pad4(str) { - while (str.length < 4) { - str = '0' + str; - } - return str; - } - -// Converts a hexadecimal number to decimal - function dec(hex) { - return parseInt(hex, 16); - } - -// Converts a decimal number to hexadecimal - function hex(dec) { - return parseInt(dec, 10).toString(16); - } - -// Gets the decimal code of a literal code unit, \xHH, \uHHHH, or a backslash-escaped literal + // Gets the decimal code of a literal code unit, \xHH, \uHHHH, or a backslash-escaped literal function charCode(chr) { var esc = /^\\[xu](.+)/.exec(chr); return esc ? @@ -58,21 +46,24 @@ module.exports = function(XRegExp) { chr.charCodeAt(chr.charAt(0) === '\\' ? 1 : 0); } -// Inverts a list of ordered BMP characters and ranges + // Inverts a list of ordered BMP characters and ranges function invertBmp(range) { - var output = '', - lastEnd = -1, - start; - XRegExp.forEach(range, /(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/, function(m) { - start = charCode(m[1]); - if (start > (lastEnd + 1)) { - output += '\\u' + pad4(hex(lastEnd + 1)); - if (start > (lastEnd + 2)) { - output += '-\\u' + pad4(hex(start - 1)); + var output = ''; + var lastEnd = -1; + XRegExp.forEach( + range, + /(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/, + function(m) { + var start = charCode(m[1]); + if (start > (lastEnd + 1)) { + output += '\\u' + pad4(hex(lastEnd + 1)); + if (start > (lastEnd + 2)) { + output += '-\\u' + pad4(hex(start - 1)); + } } + lastEnd = charCode(m[2] || m[1]); } - lastEnd = charCode(m[2] || m[1]); - }); + ); if (lastEnd < 0xFFFF) { output += '\\u' + pad4(hex(lastEnd + 1)); if (lastEnd < 0xFFFE) { @@ -82,7 +73,7 @@ module.exports = function(XRegExp) { return output; } -// Generates an inverted BMP range on first use + // Generates an inverted BMP range on first use function cacheInvertedBmp(slug) { var prop = 'b!'; return unicode[slug][prop] || ( @@ -90,7 +81,7 @@ module.exports = function(XRegExp) { ); } -// Combines and optionally negates BMP and astral data + // Combines and optionally negates BMP and astral data function buildAstral(slug, isNegated) { var item = unicode[slug], combined = ''; @@ -109,7 +100,7 @@ module.exports = function(XRegExp) { '(?:' + combined + ')'; } -// Builds a complete astral pattern on first use + // Builds a complete astral pattern on first use function cacheAstral(slug, isNegated) { var prop = isNegated ? 'a!' : 'a='; return unicode[slug][prop] || ( @@ -117,13 +108,13 @@ module.exports = function(XRegExp) { ); } -/* ============================== - * Core functionality - * ============================== */ + // ==--------------------------== + // Core functionality + // ==--------------------------== -/* - * Add Unicode token syntax: \p{..}, \P{..}, \p{^..}. Also add astral mode (flag A). - */ + /* + * Add Unicode token syntax: \p{..}, \P{..}, \p{^..}. Also add astral mode (flag A). + */ XRegExp.addToken( // Use `*` instead of `+` to avoid capturing `^` as the token name in `\p{^}` /\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/, @@ -181,33 +172,33 @@ module.exports = function(XRegExp) { } ); -/** - * Adds to the list of Unicode tokens that XRegExp regexes can match via `\p` or `\P`. - * - * @memberOf XRegExp - * @param {Array} data Objects with named character ranges. Each object may have properties `name`, - * `alias`, `isBmpLast`, `inverseOf`, `bmp`, and `astral`. All but `name` are optional, although - * one of `bmp` or `astral` is required (unless `inverseOf` is set). If `astral` is absent, the - * `bmp` data is used for BMP and astral modes. If `bmp` is absent, the name errors in BMP mode - * but works in astral mode. If both `bmp` and `astral` are provided, the `bmp` data only is used - * in BMP mode, and the combination of `bmp` and `astral` data is used in astral mode. - * `isBmpLast` is needed when a token matches orphan high surrogates *and* uses surrogate pairs - * to match astral code points. The `bmp` and `astral` data should be a combination of literal - * characters and `\xHH` or `\uHHHH` escape sequences, with hyphens to create ranges. Any regex - * metacharacters in the data should be escaped, apart from range-creating hyphens. The `astral` - * data can additionally use character classes and alternation, and should use surrogate pairs to - * represent astral code points. `inverseOf` can be used to avoid duplicating character data if a - * Unicode token is defined as the exact inverse of another token. - * @example - * - * // Basic use - * XRegExp.addUnicodeData([{ - * name: 'XDigit', - * alias: 'Hexadecimal', - * bmp: '0-9A-Fa-f' - * }]); - * XRegExp('\\p{XDigit}:\\p{Hexadecimal}+').test('0:3D'); // -> true - */ + /** + * Adds to the list of Unicode tokens that XRegExp regexes can match via `\p` or `\P`. + * + * @param {Array} data Objects with named character ranges. Each object may have properties + * `name`, `alias`, `isBmpLast`, `inverseOf`, `bmp`, and `astral`. All but `name` are + * optional, although one of `bmp` or `astral` is required (unless `inverseOf` is set). If + * `astral` is absent, the `bmp` data is used for BMP and astral modes. If `bmp` is absent, + * the name errors in BMP mode but works in astral mode. If both `bmp` and `astral` are + * provided, the `bmp` data only is used in BMP mode, and the combination of `bmp` and + * `astral` data is used in astral mode. `isBmpLast` is needed when a token matches orphan + * high surrogates *and* uses surrogate pairs to match astral code points. The `bmp` and + * `astral` data should be a combination of literal characters and `\xHH` or `\uHHHH` escape + * sequences, with hyphens to create ranges. Any regex metacharacters in the data should be + * escaped, apart from range-creating hyphens. The `astral` data can additionally use + * character classes and alternation, and should use surrogate pairs to represent astral code + * points. `inverseOf` can be used to avoid duplicating character data if a Unicode token is + * defined as the exact inverse of another token. + * @example + * + * // Basic use + * XRegExp.addUnicodeData([{ + * name: 'XDigit', + * alias: 'Hexadecimal', + * bmp: '0-9A-Fa-f' + * }]); + * XRegExp('\\p{XDigit}:\\p{Hexadecimal}+').test('0:3D'); // -> true + */ XRegExp.addUnicodeData = function(data) { var ERR_NO_NAME = 'Unicode token requires name', ERR_NO_DATA = 'Unicode token has no character data ', diff --git a/tools/eslint/node_modules/xregexp/src/addons/unicode-blocks.js b/tools/eslint/node_modules/xregexp/src/addons/unicode-blocks.js index 918dc9d5c45742..97cc71fbb1a6d8 100644 --- a/tools/eslint/node_modules/xregexp/src/addons/unicode-blocks.js +++ b/tools/eslint/node_modules/xregexp/src/addons/unicode-blocks.js @@ -1,21 +1,23 @@ /*! - * XRegExp Unicode Blocks 3.1.0 + * XRegExp Unicode Blocks 3.1.1 * * Steven Levithan (c) 2010-2016 MIT License * Unicode data by Mathias Bynens */ -/** - * Adds support for all Unicode blocks. Block names use the prefix 'In'. E.g., `\p{InBasicLatin}`. - * Token names are case insensitive, and any spaces, hyphens, and underscores are ignored. - * - * Uses Unicode 8.0.0. - * - * @requires XRegExp, Unicode Base - */ module.exports = function(XRegExp) { 'use strict'; + /** + * Adds support for all Unicode blocks. Block names use the prefix 'In'. E.g., + * `\p{InBasicLatin}`. Token names are case insensitive, and any spaces, hyphens, and + * underscores are ignored. + * + * Uses Unicode 8.0.0. + * + * @requires XRegExp, Unicode Base + */ + if (!XRegExp.addUnicodeData) { throw new ReferenceError('Unicode Base must be loaded before Unicode Blocks'); } diff --git a/tools/eslint/node_modules/xregexp/src/addons/unicode-categories.js b/tools/eslint/node_modules/xregexp/src/addons/unicode-categories.js index 6da732f505abcc..4e201cb95c5050 100644 --- a/tools/eslint/node_modules/xregexp/src/addons/unicode-categories.js +++ b/tools/eslint/node_modules/xregexp/src/addons/unicode-categories.js @@ -1,22 +1,23 @@ /*! - * XRegExp Unicode Categories 3.1.0 + * XRegExp Unicode Categories 3.1.1 * * Steven Levithan (c) 2010-2016 MIT License * Unicode data by Mathias Bynens */ -/** - * Adds support for Unicode's general categories. E.g., `\p{Lu}` or `\p{Uppercase Letter}`. See - * category descriptions in UAX #44 . Token names - * are case insensitive, and any spaces, hyphens, and underscores are ignored. - * - * Uses Unicode 8.0.0. - * - * @requires XRegExp, Unicode Base - */ module.exports = function(XRegExp) { 'use strict'; + /** + * Adds support for Unicode's general categories. E.g., `\p{Lu}` or `\p{Uppercase Letter}`. See + * category descriptions in UAX #44 . Token + * names are case insensitive, and any spaces, hyphens, and underscores are ignored. + * + * Uses Unicode 8.0.0. + * + * @requires XRegExp, Unicode Base + */ + if (!XRegExp.addUnicodeData) { throw new ReferenceError('Unicode Base must be loaded before Unicode Categories'); } diff --git a/tools/eslint/node_modules/xregexp/src/addons/unicode-properties.js b/tools/eslint/node_modules/xregexp/src/addons/unicode-properties.js index 92a041b4f85839..725a77050ea781 100644 --- a/tools/eslint/node_modules/xregexp/src/addons/unicode-properties.js +++ b/tools/eslint/node_modules/xregexp/src/addons/unicode-properties.js @@ -1,51 +1,52 @@ /*! - * XRegExp Unicode Properties 3.1.0 + * XRegExp Unicode Properties 3.1.1 * * Steven Levithan (c) 2012-2016 MIT License * Unicode data by Mathias Bynens */ -/** - * Adds properties to meet the UTS #18 Level 1 RL1.2 requirements for Unicode regex support. See - * . Following are definitions of these properties from UAX - * #44 : - * - * - Alphabetic - * Characters with the Alphabetic property. Generated from: Lowercase + Uppercase + Lt + Lm + Lo + - * Nl + Other_Alphabetic. - * - * - Default_Ignorable_Code_Point - * For programmatic determination of default ignorable code points. New characters that should be - * ignored in rendering (unless explicitly supported) will be assigned in these ranges, permitting - * programs to correctly handle the default rendering of such characters when not otherwise - * supported. - * - * - Lowercase - * Characters with the Lowercase property. Generated from: Ll + Other_Lowercase. - * - * - Noncharacter_Code_Point - * Code points permanently reserved for internal use. - * - * - Uppercase - * Characters with the Uppercase property. Generated from: Lu + Other_Uppercase. - * - * - White_Space - * Spaces, separator characters and other control characters which should be treated by - * programming languages as "white space" for the purpose of parsing elements. - * - * The properties ASCII, Any, and Assigned are also included but are not defined in UAX #44. UTS #18 - * RL1.2 additionally requires support for Unicode scripts and general categories. These are - * included in XRegExp's Unicode Categories and Unicode Scripts addons. - * - * Token names are case insensitive, and any spaces, hyphens, and underscores are ignored. - * - * Uses Unicode 8.0.0. - * - * @requires XRegExp, Unicode Base - */ module.exports = function(XRegExp) { 'use strict'; + /** + * Adds properties to meet the UTS #18 Level 1 RL1.2 requirements for Unicode regex support. See + * . Following are definitions of these properties from + * UAX #44 : + * + * - Alphabetic + * Characters with the Alphabetic property. Generated from: Lowercase + Uppercase + Lt + Lm + + * Lo + Nl + Other_Alphabetic. + * + * - Default_Ignorable_Code_Point + * For programmatic determination of default ignorable code points. New characters that should + * be ignored in rendering (unless explicitly supported) will be assigned in these ranges, + * permitting programs to correctly handle the default rendering of such characters when not + * otherwise supported. + * + * - Lowercase + * Characters with the Lowercase property. Generated from: Ll + Other_Lowercase. + * + * - Noncharacter_Code_Point + * Code points permanently reserved for internal use. + * + * - Uppercase + * Characters with the Uppercase property. Generated from: Lu + Other_Uppercase. + * + * - White_Space + * Spaces, separator characters and other control characters which should be treated by + * programming languages as "white space" for the purpose of parsing elements. + * + * The properties ASCII, Any, and Assigned are also included but are not defined in UAX #44. UTS + * #18 RL1.2 additionally requires support for Unicode scripts and general categories. These are + * included in XRegExp's Unicode Categories and Unicode Scripts addons. + * + * Token names are case insensitive, and any spaces, hyphens, and underscores are ignored. + * + * Uses Unicode 8.0.0. + * + * @requires XRegExp, Unicode Base + */ + if (!XRegExp.addUnicodeData) { throw new ReferenceError('Unicode Base must be loaded before Unicode Properties'); } diff --git a/tools/eslint/node_modules/xregexp/src/addons/unicode-scripts.js b/tools/eslint/node_modules/xregexp/src/addons/unicode-scripts.js index bb28ec36a09b31..06983d6a821baf 100644 --- a/tools/eslint/node_modules/xregexp/src/addons/unicode-scripts.js +++ b/tools/eslint/node_modules/xregexp/src/addons/unicode-scripts.js @@ -1,21 +1,22 @@ /*! - * XRegExp Unicode Scripts 3.1.0 + * XRegExp Unicode Scripts 3.1.1 * * Steven Levithan (c) 2010-2016 MIT License * Unicode data by Mathias Bynens */ -/** - * Adds support for all Unicode scripts. E.g., `\p{Latin}`. Token names are case insensitive, and - * any spaces, hyphens, and underscores are ignored. - * - * Uses Unicode 8.0.0. - * - * @requires XRegExp, Unicode Base - */ module.exports = function(XRegExp) { 'use strict'; + /** + * Adds support for all Unicode scripts. E.g., `\p{Latin}`. Token names are case insensitive, + * and any spaces, hyphens, and underscores are ignored. + * + * Uses Unicode 8.0.0. + * + * @requires XRegExp, Unicode Base + */ + if (!XRegExp.addUnicodeData) { throw new ReferenceError('Unicode Base must be loaded before Unicode Scripts'); } diff --git a/tools/eslint/node_modules/xregexp/src/xregexp.js b/tools/eslint/node_modules/xregexp/src/xregexp.js index 91c60b640660f6..4cedd851778466 100644 --- a/tools/eslint/node_modules/xregexp/src/xregexp.js +++ b/tools/eslint/node_modules/xregexp/src/xregexp.js @@ -1,9 +1,11 @@ /*! - * XRegExp 3.1.0 + * XRegExp 3.1.1 * * Steven Levithan (c) 2007-2016 MIT License */ +'use strict'; + /** * XRegExp provides augmented, extensible regular expressions. You get additional regex syntax and * flags, beyond what browsers support natively. XRegExp is also a regex utility belt with tools to @@ -11,85 +13,87 @@ * cross-browser inconsistencies. */ - 'use strict'; - -/* ============================== - * Private stuff - * ============================== */ - - // Property name used for extended regex instance data - var REGEX_DATA = 'xregexp'; - // Optional features that can be installed and uninstalled - var features = { - astral: false, - natives: false - }; - // Native methods to use and restore ('native' is an ES3 reserved keyword) - var nativ = { - exec: RegExp.prototype.exec, - test: RegExp.prototype.test, - match: String.prototype.match, - replace: String.prototype.replace, - split: String.prototype.split - }; - // Storage for fixed/extended native methods - var fixed = {}; - // Storage for regexes cached by `XRegExp.cache` - var regexCache = {}; - // Storage for pattern details cached by the `XRegExp` constructor - var patternCache = {}; - // Storage for regex syntax tokens added internally or by `XRegExp.addToken` - var tokens = []; - // Token scopes - var defaultScope = 'default'; - var classScope = 'class'; - // Regexes that match native regex syntax, including octals - var nativeTokens = { - // Any native multicharacter token in default scope, or any single character - 'default': /\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/, - // Any native multicharacter token in character class scope, or any single character - 'class': /\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/ - }; - // Any backreference or dollar-prefixed character in replacement strings - var replacementToken = /\$(?:{([\w$]+)}|(\d\d?|[\s\S]))/g; - // Check for correct `exec` handling of nonparticipating capturing groups - var correctExecNpcg = nativ.exec.call(/()??/, '')[1] === undefined; - // Check for ES6 `flags` prop support - var hasFlagsProp = /x/.flags !== undefined; - // Shortcut to `Object.prototype.toString` - var toString = {}.toString; - - function hasNativeFlag(flag) { - // Can't check based on the presense of properties/getters since - // browsers might support such properties even when don't support the - // corresponding flag in regex construction (tested in Chrome 48, where - // `'unicode' in /x/` is true but trying to construct a regex with flag - // `u` throws an error). - var isSupported = true; - try { - new RegExp('', flag); - } catch (exception) { - isSupported = false; - } - return isSupported; +// ==--------------------------== +// Private stuff +// ==--------------------------== + +// Property name used for extended regex instance data +var REGEX_DATA = 'xregexp'; +// Optional features that can be installed and uninstalled +var features = { + astral: false, + natives: false +}; +// Native methods to use and restore ('native' is an ES3 reserved keyword) +var nativ = { + exec: RegExp.prototype.exec, + test: RegExp.prototype.test, + match: String.prototype.match, + replace: String.prototype.replace, + split: String.prototype.split +}; +// Storage for fixed/extended native methods +var fixed = {}; +// Storage for regexes cached by `XRegExp.cache` +var regexCache = {}; +// Storage for pattern details cached by the `XRegExp` constructor +var patternCache = {}; +// Storage for regex syntax tokens added internally or by `XRegExp.addToken` +var tokens = []; +// Token scopes +var defaultScope = 'default'; +var classScope = 'class'; +// Regexes that match native regex syntax, including octals +var nativeTokens = { + // Any native multicharacter token in default scope, or any single character + 'default': /\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?(?:[:=!]|<[=!])|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/, + // Any native multicharacter token in character class scope, or any single character + 'class': /\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/ +}; +// Any backreference or dollar-prefixed character in replacement strings +var replacementToken = /\$(?:{([\w$]+)}|(\d\d?|[\s\S]))/g; +// Check for correct `exec` handling of nonparticipating capturing groups +var correctExecNpcg = nativ.exec.call(/()??/, '')[1] === undefined; +// Check for ES6 `flags` prop support +var hasFlagsProp = /x/.flags !== undefined; +// Shortcut to `Object.prototype.toString` +var toString = {}.toString; + +function hasNativeFlag(flag) { + // Can't check based on the presense of properties/getters since browsers might support such + // properties even when they don't support the corresponding flag in regex construction (tested + // in Chrome 48, where `'unicode' in /x/` is true but trying to construct a regex with flag `u` + // throws an error) + var isSupported = true; + try { + // Can't use regex literals for testing even in a `try` because regex literals with + // unsupported flags cause a compilation error in IE + new RegExp('', flag); + } catch (exception) { + isSupported = false; } - // Check for ES6 `u` flag support - var hasNativeU = hasNativeFlag('u'); - // Check for ES6 `y` flag support - var hasNativeY = hasNativeFlag('y'); - // Tracker for known flags, including addon flags - var registeredFlags = { - g: true, - i: true, - m: true, - u: hasNativeU, - y: hasNativeY - }; + if (isSupported && flag === 'y') { + // Work around Safari 9.1.1 bug + return new RegExp('aa|.', 'y').test('b'); + } + return isSupported; +} +// Check for ES6 `u` flag support +var hasNativeU = hasNativeFlag('u'); +// Check for ES6 `y` flag support +var hasNativeY = hasNativeFlag('y'); +// Tracker for known flags, including addon flags +var registeredFlags = { + g: true, + i: true, + m: true, + u: hasNativeU, + y: hasNativeY +}; /** * Attaches extended data and `XRegExp.prototype` properties to a regex object. * - * @private * @param {RegExp} regex Regex to augment. * @param {Array} captureNames Array with capture names, or `null`. * @param {String} xSource XRegExp pattern used to generate `regex`, or `null` if N/A. @@ -99,53 +103,51 @@ * skipping some operations like attaching `XRegExp.prototype` properties. * @returns {RegExp} Augmented regex. */ - function augment(regex, captureNames, xSource, xFlags, isInternalOnly) { - var p; +function augment(regex, captureNames, xSource, xFlags, isInternalOnly) { + var p; - regex[REGEX_DATA] = { - captureNames: captureNames - }; + regex[REGEX_DATA] = { + captureNames: captureNames + }; - if (isInternalOnly) { - return regex; - } + if (isInternalOnly) { + return regex; + } - // Can't auto-inherit these since the XRegExp constructor returns a nonprimitive value - if (regex.__proto__) { - regex.__proto__ = XRegExp.prototype; - } else { - for (p in XRegExp.prototype) { - // An `XRegExp.prototype.hasOwnProperty(p)` check wouldn't be worth it here, since - // this is performance sensitive, and enumerable `Object.prototype` or - // `RegExp.prototype` extensions exist on `regex.prototype` anyway - regex[p] = XRegExp.prototype[p]; - } + // Can't auto-inherit these since the XRegExp constructor returns a nonprimitive value + if (regex.__proto__) { + regex.__proto__ = XRegExp.prototype; + } else { + for (p in XRegExp.prototype) { + // An `XRegExp.prototype.hasOwnProperty(p)` check wouldn't be worth it here, since this + // is performance sensitive, and enumerable `Object.prototype` or `RegExp.prototype` + // extensions exist on `regex.prototype` anyway + regex[p] = XRegExp.prototype[p]; } + } - regex[REGEX_DATA].source = xSource; - // Emulate the ES6 `flags` prop by ensuring flags are in alphabetical order - regex[REGEX_DATA].flags = xFlags ? xFlags.split('').sort().join('') : xFlags; + regex[REGEX_DATA].source = xSource; + // Emulate the ES6 `flags` prop by ensuring flags are in alphabetical order + regex[REGEX_DATA].flags = xFlags ? xFlags.split('').sort().join('') : xFlags; - return regex; - } + return regex; +} /** * Removes any duplicate characters from the provided string. * - * @private * @param {String} str String to remove duplicate characters from. * @returns {String} String with any duplicate characters removed. */ - function clipDuplicates(str) { - return nativ.replace.call(str, /([\s\S])(?=[\s\S]*\1)/g, ''); - } +function clipDuplicates(str) { + return nativ.replace.call(str, /([\s\S])(?=[\s\S]*\1)/g, ''); +} /** * Copies a regex object while preserving extended data and augmenting with `XRegExp.prototype` * properties. The copy has a fresh `lastIndex` property (set to zero). Allows adding and removing * flags g and y while copying the regex. * - * @private * @param {RegExp} regex Regex to copy. * @param {Object} [options] Options object with optional properties: *
  • `addG` {Boolean} Add flag g while copying the regex. @@ -157,256 +159,243 @@ * skipping some operations like attaching `XRegExp.prototype` properties. * @returns {RegExp} Copy of the provided regex, possibly with modified flags. */ - function copyRegex(regex, options) { - if (!XRegExp.isRegExp(regex)) { - throw new TypeError('Type RegExp expected'); - } +function copyRegex(regex, options) { + if (!XRegExp.isRegExp(regex)) { + throw new TypeError('Type RegExp expected'); + } - var xData = regex[REGEX_DATA] || {}, - flags = getNativeFlags(regex), - flagsToAdd = '', - flagsToRemove = '', - xregexpSource = null, - xregexpFlags = null; + var xData = regex[REGEX_DATA] || {}, + flags = getNativeFlags(regex), + flagsToAdd = '', + flagsToRemove = '', + xregexpSource = null, + xregexpFlags = null; - options = options || {}; + options = options || {}; - if (options.removeG) {flagsToRemove += 'g';} - if (options.removeY) {flagsToRemove += 'y';} - if (flagsToRemove) { - flags = nativ.replace.call(flags, new RegExp('[' + flagsToRemove + ']+', 'g'), ''); - } + if (options.removeG) {flagsToRemove += 'g';} + if (options.removeY) {flagsToRemove += 'y';} + if (flagsToRemove) { + flags = nativ.replace.call(flags, new RegExp('[' + flagsToRemove + ']+', 'g'), ''); + } - if (options.addG) {flagsToAdd += 'g';} - if (options.addY) {flagsToAdd += 'y';} - if (flagsToAdd) { - flags = clipDuplicates(flags + flagsToAdd); - } + if (options.addG) {flagsToAdd += 'g';} + if (options.addY) {flagsToAdd += 'y';} + if (flagsToAdd) { + flags = clipDuplicates(flags + flagsToAdd); + } - if (!options.isInternalOnly) { - if (xData.source !== undefined) { - xregexpSource = xData.source; - } - // null or undefined; don't want to add to `flags` if the previous value was null, since - // that indicates we're not tracking original precompilation flags - if (xData.flags != null) { - // Flags are only added for non-internal regexes by `XRegExp.globalize`. Flags are - // never removed for non-internal regexes, so don't need to handle it - xregexpFlags = flagsToAdd ? clipDuplicates(xData.flags + flagsToAdd) : xData.flags; - } + if (!options.isInternalOnly) { + if (xData.source !== undefined) { + xregexpSource = xData.source; + } + // null or undefined; don't want to add to `flags` if the previous value was null, since + // that indicates we're not tracking original precompilation flags + if (xData.flags != null) { + // Flags are only added for non-internal regexes by `XRegExp.globalize`. Flags are never + // removed for non-internal regexes, so don't need to handle it + xregexpFlags = flagsToAdd ? clipDuplicates(xData.flags + flagsToAdd) : xData.flags; } + } - // Augment with `XRegExp.prototype` properties, but use the native `RegExp` constructor to - // avoid searching for special tokens. That would be wrong for regexes constructed by - // `RegExp`, and unnecessary for regexes constructed by `XRegExp` because the regex has - // already undergone the translation to native regex syntax - regex = augment( - new RegExp(regex.source, flags), - hasNamedCapture(regex) ? xData.captureNames.slice(0) : null, - xregexpSource, - xregexpFlags, - options.isInternalOnly - ); + // Augment with `XRegExp.prototype` properties, but use the native `RegExp` constructor to avoid + // searching for special tokens. That would be wrong for regexes constructed by `RegExp`, and + // unnecessary for regexes constructed by `XRegExp` because the regex has already undergone the + // translation to native regex syntax + regex = augment( + new RegExp(regex.source, flags), + hasNamedCapture(regex) ? xData.captureNames.slice(0) : null, + xregexpSource, + xregexpFlags, + options.isInternalOnly + ); - return regex; - } + return regex; +} /** * Converts hexadecimal to decimal. * - * @private * @param {String} hex * @returns {Number} */ - function dec(hex) { - return parseInt(hex, 16); - } +function dec(hex) { + return parseInt(hex, 16); +} /** * Returns native `RegExp` flags used by a regex object. * - * @private * @param {RegExp} regex Regex to check. * @returns {String} Native flags in use. */ - function getNativeFlags(regex) { - return hasFlagsProp ? - regex.flags : - // Explicitly using `RegExp.prototype.toString` (rather than e.g. `String` or - // concatenation with an empty string) allows this to continue working predictably when - // `XRegExp.proptotype.toString` is overriden - nativ.exec.call(/\/([a-z]*)$/i, RegExp.prototype.toString.call(regex))[1]; - } +function getNativeFlags(regex) { + return hasFlagsProp ? + regex.flags : + // Explicitly using `RegExp.prototype.toString` (rather than e.g. `String` or concatenation + // with an empty string) allows this to continue working predictably when + // `XRegExp.proptotype.toString` is overriden + nativ.exec.call(/\/([a-z]*)$/i, RegExp.prototype.toString.call(regex))[1]; +} /** * Determines whether a regex has extended instance data used to track capture names. * - * @private * @param {RegExp} regex Regex to check. * @returns {Boolean} Whether the regex uses named capture. */ - function hasNamedCapture(regex) { - return !!(regex[REGEX_DATA] && regex[REGEX_DATA].captureNames); - } +function hasNamedCapture(regex) { + return !!(regex[REGEX_DATA] && regex[REGEX_DATA].captureNames); +} /** * Converts decimal to hexadecimal. * - * @private * @param {Number|String} dec * @returns {String} */ - function hex(dec) { - return parseInt(dec, 10).toString(16); - } +function hex(dec) { + return parseInt(dec, 10).toString(16); +} /** * Returns the first index at which a given value can be found in an array. * - * @private * @param {Array} array Array to search. * @param {*} value Value to locate in the array. * @returns {Number} Zero-based index at which the item is found, or -1. */ - function indexOf(array, value) { - var len = array.length, i; +function indexOf(array, value) { + var len = array.length, i; - for (i = 0; i < len; ++i) { - if (array[i] === value) { - return i; - } + for (i = 0; i < len; ++i) { + if (array[i] === value) { + return i; } - - return -1; } + return -1; +} + /** * Determines whether a value is of the specified type, by resolving its internal [[Class]]. * - * @private * @param {*} value Object to check. * @param {String} type Type to check for, in TitleCase. * @returns {Boolean} Whether the object matches the type. */ - function isType(value, type) { - return toString.call(value) === '[object ' + type + ']'; - } +function isType(value, type) { + return toString.call(value) === '[object ' + type + ']'; +} /** * Checks whether the next nonignorable token after the specified position is a quantifier. * - * @private * @param {String} pattern Pattern to search within. * @param {Number} pos Index in `pattern` to search at. * @param {String} flags Flags used by the pattern. * @returns {Boolean} Whether the next token is a quantifier. */ - function isQuantifierNext(pattern, pos, flags) { - return nativ.test.call( - flags.indexOf('x') > -1 ? - // Ignore any leading whitespace, line comments, and inline comments - /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ : - // Ignore any leading inline comments - /^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/, - pattern.slice(pos) - ); - } +function isQuantifierNext(pattern, pos, flags) { + return nativ.test.call( + flags.indexOf('x') > -1 ? + // Ignore any leading whitespace, line comments, and inline comments + /^(?:\s|#[^#\n]*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ : + // Ignore any leading inline comments + /^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/, + pattern.slice(pos) + ); +} /** - * Pads the provided string with as many leading zeros as needed to get to length 4. Used to produce - * fixed-length hexadecimal values. + * Adds leading zeros if shorter than four characters. Used for fixed-length hexadecimal values. * - * @private * @param {String} str * @returns {String} */ - function pad4(str) { - while (str.length < 4) { - str = '0' + str; - } - return str; +function pad4(str) { + while (str.length < 4) { + str = '0' + str; } + return str; +} /** * Checks for flag-related errors, and strips/applies flags in a leading mode modifier. Offloads * the flag preparation logic from the `XRegExp` constructor. * - * @private * @param {String} pattern Regex pattern, possibly with a leading mode modifier. * @param {String} flags Any combination of flags. * @returns {Object} Object with properties `pattern` and `flags`. */ - function prepareFlags(pattern, flags) { - var i; - - // Recent browsers throw on duplicate flags, so copy this behavior for nonnative flags - if (clipDuplicates(flags) !== flags) { - throw new SyntaxError('Invalid duplicate regex flag ' + flags); - } +function prepareFlags(pattern, flags) { + var i; - // Strip and apply a leading mode modifier with any combination of flags except g or y - pattern = nativ.replace.call(pattern, /^\(\?([\w$]+)\)/, function($0, $1) { - if (nativ.test.call(/[gy]/, $1)) { - throw new SyntaxError('Cannot use flag g or y in mode modifier ' + $0); - } - // Allow duplicate flags within the mode modifier - flags = clipDuplicates(flags + $1); - return ''; - }); + // Recent browsers throw on duplicate flags, so copy this behavior for nonnative flags + if (clipDuplicates(flags) !== flags) { + throw new SyntaxError('Invalid duplicate regex flag ' + flags); + } - // Throw on unknown native or nonnative flags - for (i = 0; i < flags.length; ++i) { - if (!registeredFlags[flags.charAt(i)]) { - throw new SyntaxError('Unknown regex flag ' + flags.charAt(i)); - } + // Strip and apply a leading mode modifier with any combination of flags except g or y + pattern = nativ.replace.call(pattern, /^\(\?([\w$]+)\)/, function($0, $1) { + if (nativ.test.call(/[gy]/, $1)) { + throw new SyntaxError('Cannot use flag g or y in mode modifier ' + $0); + } + // Allow duplicate flags within the mode modifier + flags = clipDuplicates(flags + $1); + return ''; + }); + + // Throw on unknown native or nonnative flags + for (i = 0; i < flags.length; ++i) { + if (!registeredFlags[flags.charAt(i)]) { + throw new SyntaxError('Unknown regex flag ' + flags.charAt(i)); } - - return { - pattern: pattern, - flags: flags - }; } + return { + pattern: pattern, + flags: flags + }; +} + /** * Prepares an options object from the given value. * - * @private * @param {String|Object} value Value to convert to an options object. * @returns {Object} Options object. */ - function prepareOptions(value) { - var options = {}; +function prepareOptions(value) { + var options = {}; - if (isType(value, 'String')) { - XRegExp.forEach(value, /[^\s,]+/, function(match) { - options[match] = true; - }); - - return options; - } + if (isType(value, 'String')) { + XRegExp.forEach(value, /[^\s,]+/, function(match) { + options[match] = true; + }); - return value; + return options; } + return value; +} + /** * Registers a flag so it doesn't throw an 'unknown flag' error. * - * @private * @param {String} flag Single-character flag to register. */ - function registerFlag(flag) { - if (!/^[\w$]$/.test(flag)) { - throw new Error('Flag must be a single character A-Za-z0-9_$'); - } - - registeredFlags[flag] = true; +function registerFlag(flag) { + if (!/^[\w$]$/.test(flag)) { + throw new Error('Flag must be a single character A-Za-z0-9_$'); } + registeredFlags[flag] = true; +} + /** * Runs built-in and custom regex syntax tokens in reverse insertion order at the specified * position, until a match is found. * - * @private * @param {String} pattern Original pattern from which an XRegExp object is being built. * @param {String} flags Flags being used to construct the regex. * @param {Number} pos Position to search for tokens within `pattern`. @@ -414,87 +403,84 @@ * @param {Object} context Context object to use for token handler functions. * @returns {Object} Object with properties `matchLength`, `output`, and `reparse`; or `null`. */ - function runTokens(pattern, flags, pos, scope, context) { - var i = tokens.length, - leadChar = pattern.charAt(pos), - result = null, - match, - t; - - // Run in reverse insertion order - while (i--) { - t = tokens[i]; - if ( - (t.leadChar && t.leadChar !== leadChar) || - (t.scope !== scope && t.scope !== 'all') || - (t.flag && flags.indexOf(t.flag) === -1) - ) { - continue; - } - - match = XRegExp.exec(pattern, t.regex, pos, 'sticky'); - if (match) { - result = { - matchLength: match[0].length, - output: t.handler.call(context, match, scope, flags), - reparse: t.reparse - }; - // Finished with token tests - break; - } +function runTokens(pattern, flags, pos, scope, context) { + var i = tokens.length, + leadChar = pattern.charAt(pos), + result = null, + match, + t; + + // Run in reverse insertion order + while (i--) { + t = tokens[i]; + if ( + (t.leadChar && t.leadChar !== leadChar) || + (t.scope !== scope && t.scope !== 'all') || + (t.flag && flags.indexOf(t.flag) === -1) + ) { + continue; } - return result; + match = XRegExp.exec(pattern, t.regex, pos, 'sticky'); + if (match) { + result = { + matchLength: match[0].length, + output: t.handler.call(context, match, scope, flags), + reparse: t.reparse + }; + // Finished with token tests + break; + } } + return result; +} + /** * Enables or disables implicit astral mode opt-in. When enabled, flag A is automatically added to * all new regexes created by XRegExp. This causes an error to be thrown when creating regexes if * the Unicode Base addon is not available, since flag A is registered by that addon. * - * @private * @param {Boolean} on `true` to enable; `false` to disable. */ - function setAstral(on) { - features.astral = on; - } +function setAstral(on) { + features.astral = on; +} /** * Enables or disables native method overrides. * - * @private * @param {Boolean} on `true` to enable; `false` to disable. */ - function setNatives(on) { - RegExp.prototype.exec = (on ? fixed : nativ).exec; - RegExp.prototype.test = (on ? fixed : nativ).test; - String.prototype.match = (on ? fixed : nativ).match; - String.prototype.replace = (on ? fixed : nativ).replace; - String.prototype.split = (on ? fixed : nativ).split; - - features.natives = on; - } +function setNatives(on) { + RegExp.prototype.exec = (on ? fixed : nativ).exec; + RegExp.prototype.test = (on ? fixed : nativ).test; + String.prototype.match = (on ? fixed : nativ).match; + String.prototype.replace = (on ? fixed : nativ).replace; + String.prototype.split = (on ? fixed : nativ).split; + + features.natives = on; +} /** * Returns the object, or throws an error if it is `null` or `undefined`. This is used to follow * the ES5 abstract operation `ToObject`. * - * @private * @param {*} value Object to check and return. * @returns {*} The provided object. */ - function toObject(value) { - // null or undefined - if (value == null) { - throw new TypeError('Cannot convert null or undefined to object'); - } - - return value; +function toObject(value) { + // null or undefined + if (value == null) { + throw new TypeError('Cannot convert null or undefined to object'); } -/* ============================== - * Constructor - * ============================== */ + return value; +} + +// ==--------------------------== +// Constructor +// ==--------------------------== /** * Creates an extended regular expression object for matching text with a pattern. Differs from a @@ -530,124 +516,124 @@ * // have fresh `lastIndex` properties (set to zero). * XRegExp(/regex/); */ - function XRegExp(pattern, flags) { - var context = { - hasNamedCapture: false, - captureNames: [] - }, - scope = defaultScope, - output = '', - pos = 0, - result, - token, - generated, - appliedPattern, - appliedFlags; - - if (XRegExp.isRegExp(pattern)) { - if (flags !== undefined) { - throw new TypeError('Cannot supply flags when copying a RegExp'); - } - return copyRegex(pattern); +function XRegExp(pattern, flags) { + if (XRegExp.isRegExp(pattern)) { + if (flags !== undefined) { + throw new TypeError('Cannot supply flags when copying a RegExp'); } + return copyRegex(pattern); + } - // Copy the argument behavior of `RegExp` - pattern = pattern === undefined ? '' : String(pattern); - flags = flags === undefined ? '' : String(flags); + // Copy the argument behavior of `RegExp` + pattern = pattern === undefined ? '' : String(pattern); + flags = flags === undefined ? '' : String(flags); - if (XRegExp.isInstalled('astral') && flags.indexOf('A') === -1) { - // This causes an error to be thrown if the Unicode Base addon is not available - flags += 'A'; - } + if (XRegExp.isInstalled('astral') && flags.indexOf('A') === -1) { + // This causes an error to be thrown if the Unicode Base addon is not available + flags += 'A'; + } - if (!patternCache[pattern]) { - patternCache[pattern] = {}; - } + if (!patternCache[pattern]) { + patternCache[pattern] = {}; + } - if (!patternCache[pattern][flags]) { - // Check for flag-related errors, and strip/apply flags in a leading mode modifier - result = prepareFlags(pattern, flags); - appliedPattern = result.pattern; - appliedFlags = result.flags; - - // Use XRegExp's tokens to translate the pattern to a native regex pattern. - // `appliedPattern.length` may change on each iteration if tokens use `reparse` - while (pos < appliedPattern.length) { - do { - // Check for custom tokens at the current position - result = runTokens(appliedPattern, appliedFlags, pos, scope, context); - // If the matched token used the `reparse` option, splice its output into the - // pattern before running tokens again at the same position - if (result && result.reparse) { - appliedPattern = appliedPattern.slice(0, pos) + - result.output + - appliedPattern.slice(pos + result.matchLength); - } - } while (result && result.reparse); - - if (result) { - output += result.output; - pos += (result.matchLength || 1); - } else { - // Get the native token at the current position - token = XRegExp.exec(appliedPattern, nativeTokens[scope], pos, 'sticky')[0]; - output += token; - pos += token.length; - if (token === '[' && scope === defaultScope) { - scope = classScope; - } else if (token === ']' && scope === classScope) { - scope = defaultScope; - } + if (!patternCache[pattern][flags]) { + var context = { + hasNamedCapture: false, + captureNames: [] + }; + var scope = defaultScope; + var output = ''; + var pos = 0; + var result; + + // Check for flag-related errors, and strip/apply flags in a leading mode modifier + var applied = prepareFlags(pattern, flags); + var appliedPattern = applied.pattern; + var appliedFlags = applied.flags; + + // Use XRegExp's tokens to translate the pattern to a native regex pattern. + // `appliedPattern.length` may change on each iteration if tokens use `reparse` + while (pos < appliedPattern.length) { + do { + // Check for custom tokens at the current position + result = runTokens(appliedPattern, appliedFlags, pos, scope, context); + // If the matched token used the `reparse` option, splice its output into the + // pattern before running tokens again at the same position + if (result && result.reparse) { + appliedPattern = appliedPattern.slice(0, pos) + + result.output + + appliedPattern.slice(pos + result.matchLength); } - } + } while (result && result.reparse); - patternCache[pattern][flags] = { - pattern: output, - // Strip all but native flags - flags: nativ.replace.call(appliedFlags, /[^gimuy]+/g, ''), - // `context.captureNames` has an item for each capturing group, even if unnamed - captures: context.hasNamedCapture ? context.captureNames : null - }; + if (result) { + output += result.output; + pos += (result.matchLength || 1); + } else { + // Get the native token at the current position + var token = XRegExp.exec(appliedPattern, nativeTokens[scope], pos, 'sticky')[0]; + output += token; + pos += token.length; + if (token === '[' && scope === defaultScope) { + scope = classScope; + } else if (token === ']' && scope === classScope) { + scope = defaultScope; + } + } } - generated = patternCache[pattern][flags]; - return augment( - new RegExp(generated.pattern, generated.flags), - generated.captures, - pattern, - flags - ); - }; + patternCache[pattern][flags] = { + // Use basic cleanup to collapse repeated empty groups like `(?:)(?:)` to `(?:)`. Empty + // groups are sometimes inserted during regex transpilation in order to keep tokens + // separated. However, more than one empty group in a row is never needed. + pattern: nativ.replace.call(output, /(?:\(\?:\))+/g, '(?:)'), + // Strip all but native flags + flags: nativ.replace.call(appliedFlags, /[^gimuy]+/g, ''), + // `context.captureNames` has an item for each capturing group, even if unnamed + captures: context.hasNamedCapture ? context.captureNames : null + }; + } + + var generated = patternCache[pattern][flags]; + return augment( + new RegExp(generated.pattern, generated.flags), + generated.captures, + pattern, + flags + ); +} // Add `RegExp.prototype` to the prototype chain - XRegExp.prototype = new RegExp(); +XRegExp.prototype = new RegExp(); -/* ============================== - * Public properties - * ============================== */ +// ==--------------------------== +// Public properties +// ==--------------------------== /** * The XRegExp version number as a string containing three dot-separated parts. For example, * '2.0.0-beta-3'. * * @static - * @memberOf XRegExp * @type String */ - XRegExp.version = '3.1.0'; +XRegExp.version = '3.1.1'; -/* ============================== - * Public methods - * ============================== */ +// ==--------------------------== +// Public methods +// ==--------------------------== -// Intentionally undocumented - XRegExp._hasNativeFlag = hasNativeFlag; +// Intentionally undocumented; used in tests and addons +XRegExp._hasNativeFlag = hasNativeFlag; +XRegExp._dec = dec; +XRegExp._hex = hex; +XRegExp._pad4 = pad4; /** * Extends XRegExp syntax and allows custom flags. This is used internally and can be used to * create XRegExp addons. If more than one token can match the same string, the last added wins. * - * @memberOf XRegExp * @param {RegExp} regex Regex object that matches the new token. * @param {Function} handler Function that returns a new pattern string (using native regex syntax) * to replace the matched token within all future XRegExp regexes. Has access to persistent @@ -692,45 +678,44 @@ * XRegExp('a+', 'U').exec('aaa')[0]; // -> 'a' * XRegExp('a+?', 'U').exec('aaa')[0]; // -> 'aaa' */ - XRegExp.addToken = function(regex, handler, options) { - options = options || {}; - var optionalFlags = options.optionalFlags, i; +XRegExp.addToken = function(regex, handler, options) { + options = options || {}; + var optionalFlags = options.optionalFlags, i; - if (options.flag) { - registerFlag(options.flag); - } + if (options.flag) { + registerFlag(options.flag); + } - if (optionalFlags) { - optionalFlags = nativ.split.call(optionalFlags, ''); - for (i = 0; i < optionalFlags.length; ++i) { - registerFlag(optionalFlags[i]); - } + if (optionalFlags) { + optionalFlags = nativ.split.call(optionalFlags, ''); + for (i = 0; i < optionalFlags.length; ++i) { + registerFlag(optionalFlags[i]); } + } - // Add to the private list of syntax tokens - tokens.push({ - regex: copyRegex(regex, { - addG: true, - addY: hasNativeY, - isInternalOnly: true - }), - handler: handler, - scope: options.scope || defaultScope, - flag: options.flag, - reparse: options.reparse, - leadChar: options.leadChar - }); - - // Reset the pattern cache used by the `XRegExp` constructor, since the same pattern and - // flags might now produce different results - XRegExp.cache.flush('patterns'); - }; + // Add to the private list of syntax tokens + tokens.push({ + regex: copyRegex(regex, { + addG: true, + addY: hasNativeY, + isInternalOnly: true + }), + handler: handler, + scope: options.scope || defaultScope, + flag: options.flag, + reparse: options.reparse, + leadChar: options.leadChar + }); + + // Reset the pattern cache used by the `XRegExp` constructor, since the same pattern and flags + // might now produce different results + XRegExp.cache.flush('patterns'); +}; /** * Caches and returns the result of calling `XRegExp(pattern, flags)`. On any subsequent call with * the same pattern and flag combination, the cached copy of the regex is returned. * - * @memberOf XRegExp * @param {String} pattern Regex pattern string. * @param {String} [flags] Any combination of XRegExp flags. * @returns {RegExp} Cached XRegExp object. @@ -740,31 +725,30 @@ * // The regex is compiled once only * } */ - XRegExp.cache = function(pattern, flags) { - if (!regexCache[pattern]) { - regexCache[pattern] = {}; - } - return regexCache[pattern][flags] || ( - regexCache[pattern][flags] = XRegExp(pattern, flags) - ); - }; - -// Intentionally undocumented - XRegExp.cache.flush = function(cacheName) { - if (cacheName === 'patterns') { - // Flush the pattern cache used by the `XRegExp` constructor - patternCache = {}; - } else { - // Flush the regex cache populated by `XRegExp.cache` - regexCache = {}; - } - }; +XRegExp.cache = function(pattern, flags) { + if (!regexCache[pattern]) { + regexCache[pattern] = {}; + } + return regexCache[pattern][flags] || ( + regexCache[pattern][flags] = XRegExp(pattern, flags) + ); +}; + +// Intentionally undocumented; used in tests +XRegExp.cache.flush = function(cacheName) { + if (cacheName === 'patterns') { + // Flush the pattern cache used by the `XRegExp` constructor + patternCache = {}; + } else { + // Flush the regex cache populated by `XRegExp.cache` + regexCache = {}; + } +}; /** * Escapes any regular expression metacharacters, for use when matching literal strings. The result * can safely be used at any point within a regex that uses any flags. * - * @memberOf XRegExp * @param {String} str String to escape. * @returns {String} String with regex metacharacters escaped. * @example @@ -772,9 +756,9 @@ * XRegExp.escape('Escaped? <.>'); * // -> 'Escaped\?\ <\.>' */ - XRegExp.escape = function(str) { - return nativ.replace.call(toObject(str), /[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); - }; +XRegExp.escape = function(str) { + return nativ.replace.call(toObject(str), /[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); +}; /** * Executes a regex search in a specified string. Returns a match array or `null`. If the provided @@ -784,7 +768,6 @@ * used, but is updated for compatibility. Also fixes browser bugs compared to the native * `RegExp.prototype.exec` and can be used reliably cross-browser. * - * @memberOf XRegExp * @param {String} str String to search. * @param {RegExp} regex Regex to search with. * @param {Number} [pos=0] Zero-based index at which to start the search. @@ -805,51 +788,50 @@ * } * // result -> ['2', '3', '4'] */ - XRegExp.exec = function(str, regex, pos, sticky) { - var cacheKey = 'g', - addY = false, - match, - r2; - - addY = hasNativeY && !!(sticky || (regex.sticky && sticky !== false)); - if (addY) { - cacheKey += 'y'; - } +XRegExp.exec = function(str, regex, pos, sticky) { + var cacheKey = 'g', + addY = false, + match, + r2; + + addY = hasNativeY && !!(sticky || (regex.sticky && sticky !== false)); + if (addY) { + cacheKey += 'y'; + } - regex[REGEX_DATA] = regex[REGEX_DATA] || {}; + regex[REGEX_DATA] = regex[REGEX_DATA] || {}; - // Shares cached copies with `XRegExp.match`/`replace` - r2 = regex[REGEX_DATA][cacheKey] || ( - regex[REGEX_DATA][cacheKey] = copyRegex(regex, { - addG: true, - addY: addY, - removeY: sticky === false, - isInternalOnly: true - }) - ); + // Shares cached copies with `XRegExp.match`/`replace` + r2 = regex[REGEX_DATA][cacheKey] || ( + regex[REGEX_DATA][cacheKey] = copyRegex(regex, { + addG: true, + addY: addY, + removeY: sticky === false, + isInternalOnly: true + }) + ); - r2.lastIndex = pos = pos || 0; + r2.lastIndex = pos = pos || 0; - // Fixed `exec` required for `lastIndex` fix, named backreferences, etc. - match = fixed.exec.call(r2, str); + // Fixed `exec` required for `lastIndex` fix, named backreferences, etc. + match = fixed.exec.call(r2, str); - if (sticky && match && match.index !== pos) { - match = null; - } + if (sticky && match && match.index !== pos) { + match = null; + } - if (regex.global) { - regex.lastIndex = match ? r2.lastIndex : 0; - } + if (regex.global) { + regex.lastIndex = match ? r2.lastIndex : 0; + } - return match; - }; + return match; +}; /** * Executes a provided function once per regex match. Searches always start at the beginning of the * string and continue until the end, regardless of the state of the regex's `global` property and * initial `lastIndex`. * - * @memberOf XRegExp * @param {String} str String to search. * @param {RegExp} regex Regex to search with. * @param {Function} callback Function to execute for each match. Invoked with four arguments: @@ -866,30 +848,29 @@ * }); * // evens -> [2, 4] */ - XRegExp.forEach = function(str, regex, callback) { - var pos = 0, - i = -1, - match; - - while ((match = XRegExp.exec(str, regex, pos))) { - // Because `regex` is provided to `callback`, the function could use the deprecated/ - // nonstandard `RegExp.prototype.compile` to mutate the regex. However, since - // `XRegExp.exec` doesn't use `lastIndex` to set the search position, this can't lead - // to an infinite loop, at least. Actually, because of the way `XRegExp.exec` caches - // globalized versions of regexes, mutating the regex will not have any effect on the - // iteration or matched strings, which is a nice side effect that brings extra safety - callback(match, ++i, str, regex); - - pos = match.index + (match[0].length || 1); - } - }; +XRegExp.forEach = function(str, regex, callback) { + var pos = 0, + i = -1, + match; + + while ((match = XRegExp.exec(str, regex, pos))) { + // Because `regex` is provided to `callback`, the function could use the deprecated/ + // nonstandard `RegExp.prototype.compile` to mutate the regex. However, since `XRegExp.exec` + // doesn't use `lastIndex` to set the search position, this can't lead to an infinite loop, + // at least. Actually, because of the way `XRegExp.exec` caches globalized versions of + // regexes, mutating the regex will not have any effect on the iteration or matched strings, + // which is a nice side effect that brings extra safety. + callback(match, ++i, str, regex); + + pos = match.index + (match[0].length || 1); + } +}; /** * Copies a regex object and adds flag `g`. The copy maintains extended data, is augmented with * `XRegExp.prototype` properties, and has a fresh `lastIndex` property (set to zero). Native * regexes are not recompiled using XRegExp syntax. * - * @memberOf XRegExp * @param {RegExp} regex Regex to globalize. * @returns {RegExp} Copy of the provided regex with flag `g` added. * @example @@ -897,15 +878,14 @@ * var globalCopy = XRegExp.globalize(/regex/); * globalCopy.global; // -> true */ - XRegExp.globalize = function(regex) { - return copyRegex(regex, {addG: true}); - }; +XRegExp.globalize = function(regex) { + return copyRegex(regex, {addG: true}); +}; /** * Installs optional features according to the specified options. Can be undone using * `XRegExp.uninstall`. * - * @memberOf XRegExp * @param {Object|String} options Options object or string. * @example * @@ -921,22 +901,21 @@ * // With an options string * XRegExp.install('astral natives'); */ - XRegExp.install = function(options) { - options = prepareOptions(options); +XRegExp.install = function(options) { + options = prepareOptions(options); - if (!features.astral && options.astral) { - setAstral(true); - } + if (!features.astral && options.astral) { + setAstral(true); + } - if (!features.natives && options.natives) { - setNatives(true); - } - }; + if (!features.natives && options.natives) { + setNatives(true); + } +}; /** * Checks whether an individual optional feature is installed. * - * @memberOf XRegExp * @param {String} feature Name of the feature to check. One of: *
  • `astral` *
  • `natives` @@ -945,15 +924,14 @@ * * XRegExp.isInstalled('astral'); */ - XRegExp.isInstalled = function(feature) { - return !!(features[feature]); - }; +XRegExp.isInstalled = function(feature) { + return !!(features[feature]); +}; /** * Returns `true` if an object is a regex; `false` if it isn't. This works correctly for regexes * created in another frame, when `instanceof` and `constructor` checks would fail. * - * @memberOf XRegExp * @param {*} value Object to check. * @returns {Boolean} Whether the object is a `RegExp` object. * @example @@ -963,10 +941,10 @@ * XRegExp.isRegExp(RegExp('^', 'm')); // -> true * XRegExp.isRegExp(XRegExp('(?s).')); // -> true */ - XRegExp.isRegExp = function(value) { - return toString.call(value) === '[object RegExp]'; - //return isType(value, 'RegExp'); - }; +XRegExp.isRegExp = function(value) { + return toString.call(value) === '[object RegExp]'; + //return isType(value, 'RegExp'); +}; /** * Returns the first matched string, or in global mode, an array containing all matched strings. @@ -975,7 +953,6 @@ * and an empty array instead of `null` when no matches are found in match-all mode). It also lets * you override flag g and ignore `lastIndex`, and fixes browser bugs. * - * @memberOf XRegExp * @param {String} str String to search. * @param {RegExp} regex Regex to search with. * @param {String} [scope='one'] Use 'one' to return the first match as a string. Use 'all' to @@ -995,35 +972,35 @@ * XRegExp.match('abc', /\w/, 'all'); // -> ['a', 'b', 'c'] * XRegExp.match('abc', /x/, 'all'); // -> [] */ - XRegExp.match = function(str, regex, scope) { - var global = (regex.global && scope !== 'one') || scope === 'all', - cacheKey = ((global ? 'g' : '') + (regex.sticky ? 'y' : '')) || 'noGY', - result, - r2; +XRegExp.match = function(str, regex, scope) { + var global = (regex.global && scope !== 'one') || scope === 'all', + cacheKey = ((global ? 'g' : '') + (regex.sticky ? 'y' : '')) || 'noGY', + result, + r2; + + regex[REGEX_DATA] = regex[REGEX_DATA] || {}; + + // Shares cached copies with `XRegExp.exec`/`replace` + r2 = regex[REGEX_DATA][cacheKey] || ( + regex[REGEX_DATA][cacheKey] = copyRegex(regex, { + addG: !!global, + removeG: scope === 'one', + isInternalOnly: true + }) + ); - regex[REGEX_DATA] = regex[REGEX_DATA] || {}; + result = nativ.match.call(toObject(str), r2); - // Shares cached copies with `XRegExp.exec`/`replace` - r2 = regex[REGEX_DATA][cacheKey] || ( - regex[REGEX_DATA][cacheKey] = copyRegex(regex, { - addG: !!global, - removeG: scope === 'one', - isInternalOnly: true - }) + if (regex.global) { + regex.lastIndex = ( + (scope === 'one' && result) ? + // Can't use `r2.lastIndex` since `r2` is nonglobal in this case + (result.index + result[0].length) : 0 ); + } - result = nativ.match.call(toObject(str), r2); - - if (regex.global) { - regex.lastIndex = ( - (scope === 'one' && result) ? - // Can't use `r2.lastIndex` since `r2` is nonglobal in this case - (result.index + result[0].length) : 0 - ); - } - - return global ? (result || []) : (result && result[0]); - }; + return global ? (result || []) : (result && result[0]); +}; /** * Retrieves the matches from searching a string using a chain of regexes that successively search @@ -1031,7 +1008,6 @@ * `regex` and `backref` properties. When a backreference is specified, the named or numbered * backreference is passed forward to the next regex or returned. * - * @memberOf XRegExp * @param {String} str String to search. * @param {Array} chain Regexes that each search for matches within preceding results. * @returns {Array} Matches by the last regex in the chain, or an empty array. @@ -1053,38 +1029,37 @@ * ]); * // -> ['xregexp.com', 'www.google.com'] */ - XRegExp.matchChain = function(str, chain) { - return (function recurseChain(values, level) { - var item = chain[level].regex ? chain[level] : {regex: chain[level]}, - matches = [], - addMatch = function(match) { - if (item.backref) { - /* Safari 4.0.5 (but not 5.0.5+) inappropriately uses sparse arrays to hold - * the `undefined`s for backreferences to nonparticipating capturing - * groups. In such cases, a `hasOwnProperty` or `in` check on its own would - * inappropriately throw the exception, so also check if the backreference - * is a number that is within the bounds of the array. - */ - if (!(match.hasOwnProperty(item.backref) || +item.backref < match.length)) { - throw new ReferenceError('Backreference to undefined group: ' + item.backref); - } - - matches.push(match[item.backref] || ''); - } else { - matches.push(match[0]); - } - }, - i; +XRegExp.matchChain = function(str, chain) { + return (function recurseChain(values, level) { + var item = chain[level].regex ? chain[level] : {regex: chain[level]}; + var matches = []; + + function addMatch(match) { + if (item.backref) { + // Safari 4.0.5 (but not 5.0.5+) inappropriately uses sparse arrays to hold the + // `undefined`s for backreferences to nonparticipating capturing groups. In such + // cases, a `hasOwnProperty` or `in` check on its own would inappropriately throw + // the exception, so also check if the backreference is a number that is within the + // bounds of the array. + if (!(match.hasOwnProperty(item.backref) || +item.backref < match.length)) { + throw new ReferenceError('Backreference to undefined group: ' + item.backref); + } - for (i = 0; i < values.length; ++i) { - XRegExp.forEach(values[i], item.regex, addMatch); + matches.push(match[item.backref] || ''); + } else { + matches.push(match[0]); } + } - return ((level === chain.length - 1) || !matches.length) ? - matches : - recurseChain(matches, level + 1); - }([str], 0)); - }; + for (var i = 0; i < values.length; ++i) { + XRegExp.forEach(values[i], item.regex, addMatch); + } + + return ((level === chain.length - 1) || !matches.length) ? + matches : + recurseChain(matches, level + 1); + }([str], 0)); +}; /** * Returns a new string with one or all matches of a pattern replaced. The pattern can be a string @@ -1094,7 +1069,6 @@ * functions can use named backreferences via `arguments[0].name`. Also fixes browser bugs compared * to the native `String.prototype.replace` and can be used reliably cross-browser. * - * @memberOf XRegExp * @param {String} str String to search. * @param {RegExp|String} search Search pattern to be replaced. * @param {String|Function} replacement Replacement string or a function invoked to create it. @@ -1133,39 +1107,39 @@ * XRegExp.replace('RegExp builds RegExps', 'RegExp', 'XRegExp', 'all'); * // -> 'XRegExp builds XRegExps' */ - XRegExp.replace = function(str, search, replacement, scope) { - var isRegex = XRegExp.isRegExp(search), - global = (search.global && scope !== 'one') || scope === 'all', - cacheKey = ((global ? 'g' : '') + (search.sticky ? 'y' : '')) || 'noGY', - s2 = search, - result; - - if (isRegex) { - search[REGEX_DATA] = search[REGEX_DATA] || {}; - - // Shares cached copies with `XRegExp.exec`/`match`. Since a copy is used, `search`'s - // `lastIndex` isn't updated *during* replacement iterations - s2 = search[REGEX_DATA][cacheKey] || ( - search[REGEX_DATA][cacheKey] = copyRegex(search, { - addG: !!global, - removeG: scope === 'one', - isInternalOnly: true - }) - ); - } else if (global) { - s2 = new RegExp(XRegExp.escape(String(search)), 'g'); - } +XRegExp.replace = function(str, search, replacement, scope) { + var isRegex = XRegExp.isRegExp(search), + global = (search.global && scope !== 'one') || scope === 'all', + cacheKey = ((global ? 'g' : '') + (search.sticky ? 'y' : '')) || 'noGY', + s2 = search, + result; + + if (isRegex) { + search[REGEX_DATA] = search[REGEX_DATA] || {}; + + // Shares cached copies with `XRegExp.exec`/`match`. Since a copy is used, `search`'s + // `lastIndex` isn't updated *during* replacement iterations + s2 = search[REGEX_DATA][cacheKey] || ( + search[REGEX_DATA][cacheKey] = copyRegex(search, { + addG: !!global, + removeG: scope === 'one', + isInternalOnly: true + }) + ); + } else if (global) { + s2 = new RegExp(XRegExp.escape(String(search)), 'g'); + } - // Fixed `replace` required for named backreferences, etc. - result = fixed.replace.call(toObject(str), s2, replacement); + // Fixed `replace` required for named backreferences, etc. + result = fixed.replace.call(toObject(str), s2, replacement); - if (isRegex && search.global) { - // Fixes IE, Safari bug (last tested IE 9, Safari 5.1) - search.lastIndex = 0; - } + if (isRegex && search.global) { + // Fixes IE, Safari bug (last tested IE 9, Safari 5.1) + search.lastIndex = 0; + } - return result; - }; + return result; +}; /** * Performs batch processing of string replacements. Used like `XRegExp.replace`, but accepts an @@ -1174,7 +1148,6 @@ * replacement string or function, and an optional scope of 'one' or 'all'. Uses the XRegExp * replacement text syntax, which supports named backreference properties via `${name}`. * - * @memberOf XRegExp * @param {String} str String to search. * @param {Array} replacements Array of replacement detail arrays. * @returns {String} New string with all replacements. @@ -1191,16 +1164,16 @@ * }] * ]); */ - XRegExp.replaceEach = function(str, replacements) { - var i, r; +XRegExp.replaceEach = function(str, replacements) { + var i, r; - for (i = 0; i < replacements.length; ++i) { - r = replacements[i]; - str = XRegExp.replace(str, r[0], r[1], r[2]); - } + for (i = 0; i < replacements.length; ++i) { + r = replacements[i]; + str = XRegExp.replace(str, r[0], r[1], r[2]); + } - return str; - }; + return str; +}; /** * Splits a string into an array of strings using a regex or string separator. Matches of the @@ -1209,7 +1182,6 @@ * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably * cross-browser. * - * @memberOf XRegExp * @param {String} str String to split. * @param {RegExp|String} separator Regex or string to use for separating the string. * @param {Number} [limit] Maximum number of items to include in the result array. @@ -1228,9 +1200,9 @@ * XRegExp.split('..word1..', /([a-z]+)(\d+)/i); * // -> ['..', 'word', '1', '..'] */ - XRegExp.split = function(str, separator, limit) { - return fixed.split.call(toObject(str), separator, limit); - }; +XRegExp.split = function(str, separator, limit) { + return fixed.split.call(toObject(str), separator, limit); +}; /** * Executes a regex search in a specified string. Returns `true` or `false`. Optional `pos` and @@ -1239,7 +1211,6 @@ * updated for compatibility. Also fixes browser bugs compared to the native * `RegExp.prototype.test` and can be used reliably cross-browser. * - * @memberOf XRegExp * @param {String} str String to search. * @param {RegExp} regex Regex to search with. * @param {Number} [pos=0] Zero-based index at which to start the search. @@ -1255,16 +1226,15 @@ * XRegExp.test('abc', /c/, 0, 'sticky'); // -> false * XRegExp.test('abc', /c/, 2, 'sticky'); // -> true */ - XRegExp.test = function(str, regex, pos, sticky) { - // Do this the easy way :-) - return !!XRegExp.exec(str, regex, pos, sticky); - }; +XRegExp.test = function(str, regex, pos, sticky) { + // Do this the easy way :-) + return !!XRegExp.exec(str, regex, pos, sticky); +}; /** * Uninstalls optional features according to the specified options. All optional features start out * uninstalled, so this is used to undo the actions of `XRegExp.install`. * - * @memberOf XRegExp * @param {Object|String} options Options object or string. * @example * @@ -1280,17 +1250,17 @@ * // With an options string * XRegExp.uninstall('astral natives'); */ - XRegExp.uninstall = function(options) { - options = prepareOptions(options); +XRegExp.uninstall = function(options) { + options = prepareOptions(options); - if (features.astral && options.astral) { - setAstral(false); - } + if (features.astral && options.astral) { + setAstral(false); + } - if (features.natives && options.natives) { - setNatives(false); - } - }; + if (features.natives && options.natives) { + setNatives(false); + } +}; /** * Returns an XRegExp object that is the union of the given patterns. Patterns can be provided as @@ -1299,7 +1269,6 @@ * the larger combined pattern. Native flags used by provided regexes are ignored in favor of the * `flags` argument. * - * @memberOf XRegExp * @param {Array} patterns Regexes and strings to combine. * @param {String} [flags] Any combination of XRegExp flags. * @returns {RegExp} Union of the provided regexes and strings. @@ -1308,161 +1277,158 @@ * XRegExp.union(['a+b*c', /(dogs)\1/, /(cats)\1/], 'i'); * // -> /a\+b\*c|(dogs)\1|(cats)\2/i */ - XRegExp.union = function(patterns, flags) { - var parts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g, - output = [], - numCaptures = 0, - numPriorCaptures, - captureNames, - pattern, - rewrite = function(match, paren, backref) { - var name = captureNames[numCaptures - numPriorCaptures]; - - // Capturing group - if (paren) { - ++numCaptures; - // If the current capture has a name, preserve the name - if (name) { - return '(?<' + name + '>'; - } - // Backreference - } else if (backref) { - // Rewrite the backreference - return '\\' + (+backref + numPriorCaptures); - } +XRegExp.union = function(patterns, flags) { + var numCaptures = 0; + var numPriorCaptures; + var captureNames; + + function rewrite(match, paren, backref) { + var name = captureNames[numCaptures - numPriorCaptures]; + + // Capturing group + if (paren) { + ++numCaptures; + // If the current capture has a name, preserve the name + if (name) { + return '(?<' + name + '>'; + } + // Backreference + } else if (backref) { + // Rewrite the backreference + return '\\' + (+backref + numPriorCaptures); + } - return match; - }, - i; + return match; + } - if (!(isType(patterns, 'Array') && patterns.length)) { - throw new TypeError('Must provide a nonempty array of patterns to merge'); - } + if (!(isType(patterns, 'Array') && patterns.length)) { + throw new TypeError('Must provide a nonempty array of patterns to merge'); + } - for (i = 0; i < patterns.length; ++i) { - pattern = patterns[i]; + var parts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g; + var output = []; + var pattern; + for (var i = 0; i < patterns.length; ++i) { + pattern = patterns[i]; - if (XRegExp.isRegExp(pattern)) { - numPriorCaptures = numCaptures; - captureNames = (pattern[REGEX_DATA] && pattern[REGEX_DATA].captureNames) || []; + if (XRegExp.isRegExp(pattern)) { + numPriorCaptures = numCaptures; + captureNames = (pattern[REGEX_DATA] && pattern[REGEX_DATA].captureNames) || []; - // Rewrite backreferences. Passing to XRegExp dies on octals and ensures patterns - // are independently valid; helps keep this simple. Named captures are put back - output.push(nativ.replace.call(XRegExp(pattern.source).source, parts, rewrite)); - } else { - output.push(XRegExp.escape(pattern)); - } + // Rewrite backreferences. Passing to XRegExp dies on octals and ensures patterns are + // independently valid; helps keep this simple. Named captures are put back + output.push(nativ.replace.call(XRegExp(pattern.source).source, parts, rewrite)); + } else { + output.push(XRegExp.escape(pattern)); } + } - return XRegExp(output.join('|'), flags); - }; + return XRegExp(output.join('|'), flags); +}; -/* ============================== - * Fixed/extended native methods - * ============================== */ +// ==--------------------------== +// Fixed/extended native methods +// ==--------------------------== /** * Adds named capture support (with backreferences returned as `result.name`), and fixes browser * bugs in the native `RegExp.prototype.exec`. Calling `XRegExp.install('natives')` uses this to * override the native method. Use via `XRegExp.exec` without overriding natives. * - * @private * @param {String} str String to search. * @returns {Array} Match array with named backreference properties, or `null`. */ - fixed.exec = function(str) { - var origLastIndex = this.lastIndex, - match = nativ.exec.apply(this, arguments), - name, - r2, - i; - - if (match) { - // Fix browsers whose `exec` methods don't return `undefined` for nonparticipating - // capturing groups. This fixes IE 5.5-8, but not IE 9's quirks mode or emulation of - // older IEs. IE 9 in standards mode follows the spec - if (!correctExecNpcg && match.length > 1 && indexOf(match, '') > -1) { - r2 = copyRegex(this, { - removeG: true, - isInternalOnly: true - }); - // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed - // matching due to characters outside the match - nativ.replace.call(String(str).slice(match.index), r2, function() { - var len = arguments.length, i; - // Skip index 0 and the last 2 - for (i = 1; i < len - 2; ++i) { - if (arguments[i] === undefined) { - match[i] = undefined; - } - } - }); - } - - // Attach named capture properties - if (this[REGEX_DATA] && this[REGEX_DATA].captureNames) { - // Skip index 0 - for (i = 1; i < match.length; ++i) { - name = this[REGEX_DATA].captureNames[i - 1]; - if (name) { - match[name] = match[i]; +fixed.exec = function(str) { + var origLastIndex = this.lastIndex, + match = nativ.exec.apply(this, arguments), + name, + r2, + i; + + if (match) { + // Fix browsers whose `exec` methods don't return `undefined` for nonparticipating capturing + // groups. This fixes IE 5.5-8, but not IE 9's quirks mode or emulation of older IEs. IE 9 + // in standards mode follows the spec. + if (!correctExecNpcg && match.length > 1 && indexOf(match, '') > -1) { + r2 = copyRegex(this, { + removeG: true, + isInternalOnly: true + }); + // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed + // matching due to characters outside the match + nativ.replace.call(String(str).slice(match.index), r2, function() { + var len = arguments.length, i; + // Skip index 0 and the last 2 + for (i = 1; i < len - 2; ++i) { + if (arguments[i] === undefined) { + match[i] = undefined; } } - } + }); + } - // Fix browsers that increment `lastIndex` after zero-length matches - if (this.global && !match[0].length && (this.lastIndex > match.index)) { - this.lastIndex = match.index; + // Attach named capture properties + if (this[REGEX_DATA] && this[REGEX_DATA].captureNames) { + // Skip index 0 + for (i = 1; i < match.length; ++i) { + name = this[REGEX_DATA].captureNames[i - 1]; + if (name) { + match[name] = match[i]; + } } } - if (!this.global) { - // Fixes IE, Opera bug (last tested IE 9, Opera 11.6) - this.lastIndex = origLastIndex; + // Fix browsers that increment `lastIndex` after zero-length matches + if (this.global && !match[0].length && (this.lastIndex > match.index)) { + this.lastIndex = match.index; } + } - return match; - }; + if (!this.global) { + // Fixes IE, Opera bug (last tested IE 9, Opera 11.6) + this.lastIndex = origLastIndex; + } + + return match; +}; /** * Fixes browser bugs in the native `RegExp.prototype.test`. Calling `XRegExp.install('natives')` * uses this to override the native method. * - * @private * @param {String} str String to search. * @returns {Boolean} Whether the regex matched the provided value. */ - fixed.test = function(str) { - // Do this the easy way :-) - return !!fixed.exec.call(this, str); - }; +fixed.test = function(str) { + // Do this the easy way :-) + return !!fixed.exec.call(this, str); +}; /** * Adds named capture support (with backreferences returned as `result.name`), and fixes browser * bugs in the native `String.prototype.match`. Calling `XRegExp.install('natives')` uses this to * override the native method. * - * @private * @param {RegExp|*} regex Regex to search with. If not a regex object, it is passed to `RegExp`. * @returns {Array} If `regex` uses flag g, an array of match strings or `null`. Without flag g, * the result of calling `regex.exec(this)`. */ - fixed.match = function(regex) { - var result; +fixed.match = function(regex) { + var result; - if (!XRegExp.isRegExp(regex)) { - // Use the native `RegExp` rather than `XRegExp` - regex = new RegExp(regex); - } else if (regex.global) { - result = nativ.match.apply(this, arguments); - // Fixes IE bug - regex.lastIndex = 0; + if (!XRegExp.isRegExp(regex)) { + // Use the native `RegExp` rather than `XRegExp` + regex = new RegExp(regex); + } else if (regex.global) { + result = nativ.match.apply(this, arguments); + // Fixes IE bug + regex.lastIndex = 0; - return result; - } + return result; + } - return fixed.exec.call(regex, toObject(this)); - }; + return fixed.exec.call(regex, toObject(this)); +}; /** * Adds support for `${n}` tokens for named and numbered backreferences in replacement text, and @@ -1473,212 +1439,210 @@ * that this doesn't support SpiderMonkey's proprietary third (`flags`) argument. Use via * `XRegExp.replace` without overriding natives. * - * @private * @param {RegExp|String} search Search pattern to be replaced. * @param {String|Function} replacement Replacement string or a function invoked to create it. * @returns {String} New string with one or all matches replaced. */ - fixed.replace = function(search, replacement) { - var isRegex = XRegExp.isRegExp(search), - origLastIndex, - captureNames, - result; - - if (isRegex) { - if (search[REGEX_DATA]) { - captureNames = search[REGEX_DATA].captureNames; - } - // Only needed if `search` is nonglobal - origLastIndex = search.lastIndex; - } else { - search += ''; // Type-convert +fixed.replace = function(search, replacement) { + var isRegex = XRegExp.isRegExp(search), + origLastIndex, + captureNames, + result; + + if (isRegex) { + if (search[REGEX_DATA]) { + captureNames = search[REGEX_DATA].captureNames; } + // Only needed if `search` is nonglobal + origLastIndex = search.lastIndex; + } else { + search += ''; // Type-convert + } - // Don't use `typeof`; some older browsers return 'function' for regex objects - if (isType(replacement, 'Function')) { - // Stringifying `this` fixes a bug in IE < 9 where the last argument in replacement - // functions isn't type-converted to a string - result = nativ.replace.call(String(this), search, function() { - var args = arguments, i; - if (captureNames) { - // Change the `arguments[0]` string primitive to a `String` object that can - // store properties. This really does need to use `String` as a constructor - args[0] = new String(args[0]); - // Store named backreferences on the first argument - for (i = 0; i < captureNames.length; ++i) { - if (captureNames[i]) { - args[0][captureNames[i]] = args[i + 1]; - } + // Don't use `typeof`; some older browsers return 'function' for regex objects + if (isType(replacement, 'Function')) { + // Stringifying `this` fixes a bug in IE < 9 where the last argument in replacement + // functions isn't type-converted to a string + result = nativ.replace.call(String(this), search, function() { + var args = arguments, i; + if (captureNames) { + // Change the `arguments[0]` string primitive to a `String` object that can store + // properties. This really does need to use `String` as a constructor + args[0] = new String(args[0]); + // Store named backreferences on the first argument + for (i = 0; i < captureNames.length; ++i) { + if (captureNames[i]) { + args[0][captureNames[i]] = args[i + 1]; } } - // Update `lastIndex` before calling `replacement`. Fixes IE, Chrome, Firefox, - // Safari bug (last tested IE 9, Chrome 17, Firefox 11, Safari 5.1) - if (isRegex && search.global) { - search.lastIndex = args[args.length - 2] + args[0].length; - } - // ES6 specs the context for replacement functions as `undefined` - return replacement.apply(undefined, args); - }); - } else { - // Ensure that the last value of `args` will be a string when given nonstring `this`, - // while still throwing on null or undefined context - result = nativ.replace.call(this == null ? this : String(this), search, function() { - // Keep this function's `arguments` available through closure - var args = arguments; - return nativ.replace.call(String(replacement), replacementToken, function($0, $1, $2) { - var n; - // Named or numbered backreference with curly braces - if ($1) { - // XRegExp behavior for `${n}`: - // 1. Backreference to numbered capture, if `n` is an integer. Use `0` for - // for the entire match. Any number of leading zeros may be used. - // 2. Backreference to named capture `n`, if it exists and is not an - // integer overridden by numbered capture. In practice, this does not - // overlap with numbered capture since XRegExp does not allow named - // capture to use a bare integer as the name. - // 3. If the name or number does not refer to an existing capturing group, - // it's an error. - n = +$1; // Type-convert; drop leading zeros - if (n <= args.length - 3) { - return args[n] || ''; - } - // Groups with the same name is an error, else would need `lastIndexOf` - n = captureNames ? indexOf(captureNames, $1) : -1; - if (n < 0) { - throw new SyntaxError('Backreference to undefined group ' + $0); - } - return args[n + 1] || ''; - } - // Else, special variable or numbered backreference without curly braces - if ($2 === '$') { // $$ - return '$'; - } - if ($2 === '&' || +$2 === 0) { // $&, $0 (not followed by 1-9), $00 - return args[0]; - } - if ($2 === '`') { // $` (left context) - return args[args.length - 1].slice(0, args[args.length - 2]); + } + // Update `lastIndex` before calling `replacement`. Fixes IE, Chrome, Firefox, Safari + // bug (last tested IE 9, Chrome 17, Firefox 11, Safari 5.1) + if (isRegex && search.global) { + search.lastIndex = args[args.length - 2] + args[0].length; + } + // ES6 specs the context for replacement functions as `undefined` + return replacement.apply(undefined, args); + }); + } else { + // Ensure that the last value of `args` will be a string when given nonstring `this`, + // while still throwing on null or undefined context + result = nativ.replace.call(this == null ? this : String(this), search, function() { + // Keep this function's `arguments` available through closure + var args = arguments; + return nativ.replace.call(String(replacement), replacementToken, function($0, $1, $2) { + var n; + // Named or numbered backreference with curly braces + if ($1) { + // XRegExp behavior for `${n}`: + // 1. Backreference to numbered capture, if `n` is an integer. Use `0` for the + // entire match. Any number of leading zeros may be used. + // 2. Backreference to named capture `n`, if it exists and is not an integer + // overridden by numbered capture. In practice, this does not overlap with + // numbered capture since XRegExp does not allow named capture to use a bare + // integer as the name. + // 3. If the name or number does not refer to an existing capturing group, it's + // an error. + n = +$1; // Type-convert; drop leading zeros + if (n <= args.length - 3) { + return args[n] || ''; } - if ($2 === "'") { // $' (right context) - return args[args.length - 1].slice(args[args.length - 2] + args[0].length); + // Groups with the same name is an error, else would need `lastIndexOf` + n = captureNames ? indexOf(captureNames, $1) : -1; + if (n < 0) { + throw new SyntaxError('Backreference to undefined group ' + $0); } - // Else, numbered backreference without curly braces - $2 = +$2; // Type-convert; drop leading zero - // XRegExp behavior for `$n` and `$nn`: - // - Backrefs end after 1 or 2 digits. Use `${..}` for more digits. - // - `$1` is an error if no capturing groups. - // - `$10` is an error if less than 10 capturing groups. Use `${1}0` instead. - // - `$01` is `$1` if at least one capturing group, else it's an error. - // - `$0` (not followed by 1-9) and `$00` are the entire match. - // Native behavior, for comparison: - // - Backrefs end after 1 or 2 digits. Cannot reference capturing group 100+. - // - `$1` is a literal `$1` if no capturing groups. - // - `$10` is `$1` followed by a literal `0` if less than 10 capturing groups. - // - `$01` is `$1` if at least one capturing group, else it's a literal `$01`. - // - `$0` is a literal `$0`. - if (!isNaN($2)) { - if ($2 > args.length - 3) { - throw new SyntaxError('Backreference to undefined group ' + $0); - } - return args[$2] || ''; + return args[n + 1] || ''; + } + // Else, special variable or numbered backreference without curly braces + if ($2 === '$') { // $$ + return '$'; + } + if ($2 === '&' || +$2 === 0) { // $&, $0 (not followed by 1-9), $00 + return args[0]; + } + if ($2 === '`') { // $` (left context) + return args[args.length - 1].slice(0, args[args.length - 2]); + } + if ($2 === "'") { // $' (right context) + return args[args.length - 1].slice(args[args.length - 2] + args[0].length); + } + // Else, numbered backreference without curly braces + $2 = +$2; // Type-convert; drop leading zero + // XRegExp behavior for `$n` and `$nn`: + // - Backrefs end after 1 or 2 digits. Use `${..}` for more digits. + // - `$1` is an error if no capturing groups. + // - `$10` is an error if less than 10 capturing groups. Use `${1}0` instead. + // - `$01` is `$1` if at least one capturing group, else it's an error. + // - `$0` (not followed by 1-9) and `$00` are the entire match. + // Native behavior, for comparison: + // - Backrefs end after 1 or 2 digits. Cannot reference capturing group 100+. + // - `$1` is a literal `$1` if no capturing groups. + // - `$10` is `$1` followed by a literal `0` if less than 10 capturing groups. + // - `$01` is `$1` if at least one capturing group, else it's a literal `$01`. + // - `$0` is a literal `$0`. + if (!isNaN($2)) { + if ($2 > args.length - 3) { + throw new SyntaxError('Backreference to undefined group ' + $0); } - // `$` followed by an unsupported char is an error, unlike native JS - throw new SyntaxError('Invalid token ' + $0); - }); + return args[$2] || ''; + } + // `$` followed by an unsupported char is an error, unlike native JS + throw new SyntaxError('Invalid token ' + $0); }); - } + }); + } - if (isRegex) { - if (search.global) { - // Fixes IE, Safari bug (last tested IE 9, Safari 5.1) - search.lastIndex = 0; - } else { - // Fixes IE, Opera bug (last tested IE 9, Opera 11.6) - search.lastIndex = origLastIndex; - } + if (isRegex) { + if (search.global) { + // Fixes IE, Safari bug (last tested IE 9, Safari 5.1) + search.lastIndex = 0; + } else { + // Fixes IE, Opera bug (last tested IE 9, Opera 11.6) + search.lastIndex = origLastIndex; } + } - return result; - }; + return result; +}; /** * Fixes browser bugs in the native `String.prototype.split`. Calling `XRegExp.install('natives')` * uses this to override the native method. Use via `XRegExp.split` without overriding natives. * - * @private * @param {RegExp|String} separator Regex or string to use for separating the string. * @param {Number} [limit] Maximum number of items to include in the result array. * @returns {Array} Array of substrings. */ - fixed.split = function(separator, limit) { - if (!XRegExp.isRegExp(separator)) { - // Browsers handle nonregex split correctly, so use the faster native method - return nativ.split.apply(this, arguments); - } +fixed.split = function(separator, limit) { + if (!XRegExp.isRegExp(separator)) { + // Browsers handle nonregex split correctly, so use the faster native method + return nativ.split.apply(this, arguments); + } - var str = String(this), - output = [], - origLastIndex = separator.lastIndex, - lastLastIndex = 0, - lastLength; - - // Values for `limit`, per the spec: - // If undefined: pow(2,32) - 1 - // If 0, Infinity, or NaN: 0 - // If positive number: limit = floor(limit); if (limit >= pow(2,32)) limit -= pow(2,32); - // If negative number: pow(2,32) - floor(abs(limit)) - // If other: Type-convert, then use the above rules - // This line fails in very strange ways for some values of `limit` in Opera 10.5-10.63, - // unless Opera Dragonfly is open (go figure). It works in at least Opera 9.5-10.1 and 11+ - limit = (limit === undefined ? -1 : limit) >>> 0; - - XRegExp.forEach(str, separator, function(match) { - // This condition is not the same as `if (match[0].length)` - if ((match.index + match[0].length) > lastLastIndex) { - output.push(str.slice(lastLastIndex, match.index)); - if (match.length > 1 && match.index < str.length) { - Array.prototype.push.apply(output, match.slice(1)); - } - lastLength = match[0].length; - lastLastIndex = match.index + lastLength; + var str = String(this), + output = [], + origLastIndex = separator.lastIndex, + lastLastIndex = 0, + lastLength; + + // Values for `limit`, per the spec: + // If undefined: pow(2,32) - 1 + // If 0, Infinity, or NaN: 0 + // If positive number: limit = floor(limit); if (limit >= pow(2,32)) limit -= pow(2,32); + // If negative number: pow(2,32) - floor(abs(limit)) + // If other: Type-convert, then use the above rules + // This line fails in very strange ways for some values of `limit` in Opera 10.5-10.63, unless + // Opera Dragonfly is open (go figure). It works in at least Opera 9.5-10.1 and 11+ + limit = (limit === undefined ? -1 : limit) >>> 0; + + XRegExp.forEach(str, separator, function(match) { + // This condition is not the same as `if (match[0].length)` + if ((match.index + match[0].length) > lastLastIndex) { + output.push(str.slice(lastLastIndex, match.index)); + if (match.length > 1 && match.index < str.length) { + Array.prototype.push.apply(output, match.slice(1)); } - }); + lastLength = match[0].length; + lastLastIndex = match.index + lastLength; + } + }); - if (lastLastIndex === str.length) { - if (!nativ.test.call(separator, '') || lastLength) { - output.push(''); - } - } else { - output.push(str.slice(lastLastIndex)); + if (lastLastIndex === str.length) { + if (!nativ.test.call(separator, '') || lastLength) { + output.push(''); } + } else { + output.push(str.slice(lastLastIndex)); + } - separator.lastIndex = origLastIndex; - return output.length > limit ? output.slice(0, limit) : output; - }; + separator.lastIndex = origLastIndex; + return output.length > limit ? output.slice(0, limit) : output; +}; -/* ============================== - * Built-in syntax/flag tokens - * ============================== */ +// ==--------------------------== +// Built-in syntax/flag tokens +// ==--------------------------== /* * Letter escapes that natively match literal characters: `\a`, `\A`, etc. These should be * SyntaxErrors but are allowed in web reality. XRegExp makes them errors for cross-browser * consistency and to reserve their syntax, but lets them be superseded by addons. */ - XRegExp.addToken( - /\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/, - function(match, scope) { - // \B is allowed in default scope only - if (match[1] === 'B' && scope === defaultScope) { - return match[0]; - } - throw new SyntaxError('Invalid escape ' + match[0]); - }, - { - scope: 'all', - leadChar: '\\' +XRegExp.addToken( + /\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/, + function(match, scope) { + // \B is allowed in default scope only + if (match[1] === 'B' && scope === defaultScope) { + return match[0]; } - ); + throw new SyntaxError('Invalid escape ' + match[0]); + }, + { + scope: 'all', + leadChar: '\\' + } +); /* * Unicode code point escape with curly braces: `\u{N..}`. `N..` is any one or more digit @@ -1688,134 +1652,137 @@ * if you follow a `\u{N..}` token that references a code point above U+FFFF with a quantifier, or * if you use the same in a character class. */ - XRegExp.addToken( - /\\u{([\dA-Fa-f]+)}/, - function(match, scope, flags) { - var code = dec(match[1]); - if (code > 0x10FFFF) { - throw new SyntaxError('Invalid Unicode code point ' + match[0]); - } - if (code <= 0xFFFF) { - // Converting to \uNNNN avoids needing to escape the literal character and keep it - // separate from preceding tokens - return '\\u' + pad4(hex(code)); - } - // If `code` is between 0xFFFF and 0x10FFFF, require and defer to native handling - if (hasNativeU && flags.indexOf('u') > -1) { - return match[0]; - } - throw new SyntaxError('Cannot use Unicode code point above \\u{FFFF} without flag u'); - }, - { - scope: 'all', - leadChar: '\\' +XRegExp.addToken( + /\\u{([\dA-Fa-f]+)}/, + function(match, scope, flags) { + var code = dec(match[1]); + if (code > 0x10FFFF) { + throw new SyntaxError('Invalid Unicode code point ' + match[0]); } - ); + if (code <= 0xFFFF) { + // Converting to \uNNNN avoids needing to escape the literal character and keep it + // separate from preceding tokens + return '\\u' + pad4(hex(code)); + } + // If `code` is between 0xFFFF and 0x10FFFF, require and defer to native handling + if (hasNativeU && flags.indexOf('u') > -1) { + return match[0]; + } + throw new SyntaxError('Cannot use Unicode code point above \\u{FFFF} without flag u'); + }, + { + scope: 'all', + leadChar: '\\' + } +); /* * Empty character class: `[]` or `[^]`. This fixes a critical cross-browser syntax inconsistency. * Unless this is standardized (per the ES spec), regex syntax can't be accurately parsed because * character class endings can't be determined. */ - XRegExp.addToken( - /\[(\^?)]/, - function(match) { - // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S]. - // (?!) should work like \b\B, but is unreliable in some versions of Firefox - return match[1] ? '[\\s\\S]' : '\\b\\B'; - }, - {leadChar: '['} - ); +XRegExp.addToken( + /\[(\^?)]/, + function(match) { + // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S]. + // (?!) should work like \b\B, but is unreliable in some versions of Firefox + return match[1] ? '[\\s\\S]' : '\\b\\B'; + }, + {leadChar: '['} +); /* * Comment pattern: `(?# )`. Inline comments are an alternative to the line comments allowed in * free-spacing mode (flag x). */ - XRegExp.addToken( - /\(\?#[^)]*\)/, - function(match, scope, flags) { - // Keep tokens separated unless the following token is a quantifier - return isQuantifierNext(match.input, match.index + match[0].length, flags) ? - '' : '(?:)'; - }, - {leadChar: '('} - ); +XRegExp.addToken( + /\(\?#[^)]*\)/, + function(match, scope, flags) { + // Keep tokens separated unless the following token is a quantifier. This avoids e.g. + // inadvertedly changing `\1(?#)1` to `\11`. + return isQuantifierNext(match.input, match.index + match[0].length, flags) ? + '' : '(?:)'; + }, + {leadChar: '('} +); /* * Whitespace and line comments, in free-spacing mode (aka extended mode, flag x) only. */ - XRegExp.addToken( - /\s+|#.*/, - function(match, scope, flags) { - // Keep tokens separated unless the following token is a quantifier - return isQuantifierNext(match.input, match.index + match[0].length, flags) ? - '' : '(?:)'; - }, - {flag: 'x'} - ); +XRegExp.addToken( + /\s+|#[^\n]*\n?/, + function(match, scope, flags) { + // Keep tokens separated unless the following token is a quantifier. This avoids e.g. + // inadvertedly changing `\1 1` to `\11`. + return isQuantifierNext(match.input, match.index + match[0].length, flags) ? + '' : '(?:)'; + }, + {flag: 'x'} +); /* * Dot, in dotall mode (aka singleline mode, flag s) only. */ - XRegExp.addToken( - /\./, - function() { - return '[\\s\\S]'; - }, - { - flag: 's', - leadChar: '.' - } - ); +XRegExp.addToken( + /\./, + function() { + return '[\\s\\S]'; + }, + { + flag: 's', + leadChar: '.' + } +); /* * Named backreference: `\k`. Backreference names can use the characters A-Z, a-z, 0-9, _, * and $ only. Also allows numbered backreferences as `\k`. */ - XRegExp.addToken( - /\\k<([\w$]+)>/, - function(match) { - // Groups with the same name is an error, else would need `lastIndexOf` - var index = isNaN(match[1]) ? (indexOf(this.captureNames, match[1]) + 1) : +match[1], - endIndex = match.index + match[0].length; - if (!index || index > this.captureNames.length) { - throw new SyntaxError('Backreference to undefined group ' + match[0]); - } - // Keep backreferences separate from subsequent literal numbers - return '\\' + index + ( - endIndex === match.input.length || isNaN(match.input.charAt(endIndex)) ? - '' : '(?:)' - ); - }, - {leadChar: '\\'} - ); +XRegExp.addToken( + /\\k<([\w$]+)>/, + function(match) { + // Groups with the same name is an error, else would need `lastIndexOf` + var index = isNaN(match[1]) ? (indexOf(this.captureNames, match[1]) + 1) : +match[1], + endIndex = match.index + match[0].length; + if (!index || index > this.captureNames.length) { + throw new SyntaxError('Backreference to undefined group ' + match[0]); + } + // Keep backreferences separate from subsequent literal numbers. This avoids e.g. + // inadvertedly changing `(?)\k1` to `()\11`. + return '\\' + index + ( + endIndex === match.input.length || isNaN(match.input.charAt(endIndex)) ? + '' : '(?:)' + ); + }, + {leadChar: '\\'} +); /* * Numbered backreference or octal, plus any following digits: `\0`, `\11`, etc. Octals except `\0` * not followed by 0-9 and backreferences to unopened capture groups throw an error. Other matches * are returned unaltered. IE < 9 doesn't support backreferences above `\99` in regex syntax. */ - XRegExp.addToken( - /\\(\d+)/, - function(match, scope) { - if ( - !( - scope === defaultScope && - /^[1-9]/.test(match[1]) && - +match[1] <= this.captureNames.length - ) && - match[1] !== '0' - ) { - throw new SyntaxError('Cannot use octal escape or backreference to undefined group ' + - match[0]); - } - return match[0]; - }, - { - scope: 'all', - leadChar: '\\' +XRegExp.addToken( + /\\(\d+)/, + function(match, scope) { + if ( + !( + scope === defaultScope && + /^[1-9]/.test(match[1]) && + +match[1] <= this.captureNames.length + ) && + match[1] !== '0' + ) { + throw new SyntaxError('Cannot use octal escape or backreference to undefined group ' + + match[0]); } - ); + return match[0]; + }, + { + scope: 'all', + leadChar: '\\' + } +); /* * Named capturing group; match the opening delimiter only: `(?`. Capture names can use the @@ -1824,48 +1791,44 @@ * supported the Python-style syntax. Otherwise, XRegExp might treat numbered backreferences to * Python-style named capture as octals. */ - XRegExp.addToken( - /\(\?P?<([\w$]+)>/, - function(match) { - // Disallow bare integers as names because named backreferences are added to match - // arrays and therefore numeric properties may lead to incorrect lookups - if (!isNaN(match[1])) { - throw new SyntaxError('Cannot use integer as capture name ' + match[0]); - } - if (match[1] === 'length' || match[1] === '__proto__') { - throw new SyntaxError('Cannot use reserved word as capture name ' + match[0]); - } - if (indexOf(this.captureNames, match[1]) > -1) { - throw new SyntaxError('Cannot use same name for multiple groups ' + match[0]); - } - this.captureNames.push(match[1]); - this.hasNamedCapture = true; - return '('; - }, - {leadChar: '('} - ); +XRegExp.addToken( + /\(\?P?<([\w$]+)>/, + function(match) { + // Disallow bare integers as names because named backreferences are added to match arrays + // and therefore numeric properties may lead to incorrect lookups + if (!isNaN(match[1])) { + throw new SyntaxError('Cannot use integer as capture name ' + match[0]); + } + if (match[1] === 'length' || match[1] === '__proto__') { + throw new SyntaxError('Cannot use reserved word as capture name ' + match[0]); + } + if (indexOf(this.captureNames, match[1]) > -1) { + throw new SyntaxError('Cannot use same name for multiple groups ' + match[0]); + } + this.captureNames.push(match[1]); + this.hasNamedCapture = true; + return '('; + }, + {leadChar: '('} +); /* * Capturing group; match the opening parenthesis only. Required for support of named capturing * groups. Also adds explicit capture mode (flag n). */ - XRegExp.addToken( - /\((?!\?)/, - function(match, scope, flags) { - if (flags.indexOf('n') > -1) { - return '(?:'; - } - this.captureNames.push(null); - return '('; - }, - { - optionalFlags: 'n', - leadChar: '(' +XRegExp.addToken( + /\((?!\?)/, + function(match, scope, flags) { + if (flags.indexOf('n') > -1) { + return '(?:'; } - ); - -/* ============================== - * Expose XRegExp - * ============================== */ + this.captureNames.push(null); + return '('; + }, + { + optionalFlags: 'n', + leadChar: '(' + } +); - module.exports = XRegExp; +module.exports = XRegExp; diff --git a/tools/eslint/package.json b/tools/eslint/package.json index c5787d4cfc1c8b..77a386a9b843fd 100644 --- a/tools/eslint/package.json +++ b/tools/eslint/package.json @@ -1,19 +1,19 @@ { "_args": [ [ - "eslint@latest", + "eslint", "/Users/trott/io.js/tools" ] ], "_from": "eslint@latest", - "_id": "eslint@2.9.0", + "_id": "eslint@3.0.1", "_inCache": true, "_installable": true, "_location": "/eslint", "_nodeVersion": "4.4.2", "_npmOperationalInternal": { "host": "packages-12-west.internal.npmjs.com", - "tmp": "tmp/eslint-2.9.0.tgz_1461949357357_0.922593503491953" + "tmp": "tmp/eslint-3.0.1.tgz_1467741316725_0.5076132179237902" }, "_npmUser": { "email": "nicholas@nczconsulting.com", @@ -23,8 +23,8 @@ "_phantomChildren": {}, "_requested": { "name": "eslint", - "raw": "eslint@latest", - "rawSpec": "latest", + "raw": "eslint", + "rawSpec": "", "scope": null, "spec": "latest", "type": "tag" @@ -32,10 +32,10 @@ "_requiredBy": [ "#USER" ], - "_resolved": "https://registry.npmjs.org/eslint/-/eslint-2.9.0.tgz", - "_shasum": "5b3fdb7497bb042e2747e3d1fe95f404dca39a60", + "_resolved": "https://registry.npmjs.org/eslint/-/eslint-3.0.1.tgz", + "_shasum": "ff12eafdc04ea71d173a099d4658a136e7157934", "_shrinkwrap": null, - "_spec": "eslint@latest", + "_spec": "eslint", "_where": "/Users/trott/io.js/tools", "author": { "email": "nicholas+npm@nczconsulting.com", @@ -51,10 +51,10 @@ "chalk": "^1.1.3", "concat-stream": "^1.4.6", "debug": "^2.1.1", - "doctrine": "^1.2.1", + "doctrine": "^1.2.2", "es6-map": "^0.1.3", "escope": "^3.6.0", - "espree": "3.1.4", + "espree": "^3.1.6", "estraverse": "^4.2.0", "esutils": "^2.0.2", "file-entry-cache": "^1.1.1", @@ -67,15 +67,16 @@ "is-resolvable": "^1.0.0", "js-yaml": "^3.5.1", "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", "lodash": "^4.0.0", "mkdirp": "^0.5.0", "optionator": "^0.8.1", - "path-is-absolute": "^1.0.0", "path-is-inside": "^1.0.1", "pluralize": "^1.2.1", "progress": "^1.1.8", "require-uncached": "^1.0.2", "shelljs": "^0.6.0", + "strip-bom": "^3.0.0", "strip-json-comments": "~1.0.1", "table": "^3.7.8", "text-table": "~0.2.0", @@ -97,15 +98,19 @@ "gh-got": "^2.2.0", "istanbul": "^0.4.0", "jsdoc": "^3.3.0-beta1", + "karma": "^0.13.22", + "karma-mocha": "^1.0.1", + "karma-mocha-reporter": "^2.0.3", + "karma-phantomjs-launcher": "^1.0.0", "leche": "^2.1.1", "linefix": "^0.1.1", "load-perf": "^0.2.0", "markdownlint": "^0.1.0", "mocha": "^2.4.5", - "mocha-phantomjs": "4.0.1", + "mock-fs": "^3.9.0", "npm-license": "^0.3.2", - "phantomjs-polyfill": "0.0.1", - "proxyquire": "^1.0.0", + "phantomjs-prebuilt": "^2.1.7", + "proxyquire": ">=1.0.0 <1.7.5", "semver": "^5.0.3", "shelljs-nodecli": "~0.1.0", "sinon": "^1.17.2", @@ -114,11 +119,11 @@ }, "directories": {}, "dist": { - "shasum": "5b3fdb7497bb042e2747e3d1fe95f404dca39a60", - "tarball": "https://registry.npmjs.org/eslint/-/eslint-2.9.0.tgz" + "shasum": "ff12eafdc04ea71d173a099d4658a136e7157934", + "tarball": "https://registry.npmjs.org/eslint/-/eslint-3.0.1.tgz" }, "engines": { - "node": ">=0.10" + "node": ">=4" }, "files": [ "LICENSE", @@ -128,7 +133,7 @@ "lib", "messages" ], - "gitHead": "d8887638a9eaeeda6ea09f7d625d1bc57ea7f436", + "gitHead": "0fd4b6db5ff273a8475fe9ddc25486a10bf40f83", "homepage": "http://eslint.org", "keywords": [ "ast", @@ -170,5 +175,5 @@ "release": "node Makefile.js release", "test": "node Makefile.js test" }, - "version": "2.9.0" + "version": "3.0.1" }