diff --git a/.eslintrc b/.eslintrc index 65bf3b9fb66..98f055da7ec 100644 --- a/.eslintrc +++ b/.eslintrc @@ -58,7 +58,7 @@ rules: brace-style: [2, 1tbs, {allowSingleLine: true}] comma-spacing: 2 eol-last: 2 - indent: [2, 2, {SwitchCase: 1}] + indent: [2, 2, {SwitchCase: 1, MemberExpression: 1}] key-spacing: [2, {mode: minimum}] keyword-spacing: 2 linebreak-style: [1, unix] @@ -87,6 +87,7 @@ rules: no-new-symbol: 2 no-this-before-super: 2 prefer-const: 2 + rest-spread-spacing: 2 template-curly-spacing: 2 # Custom rules in tools/eslint-rules diff --git a/.gitignore b/.gitignore index c7361af80c7..ade43c5baaf 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ ipch/ *.opensdf *.VC.opendb .vs/ +.vscode/ /config.mk /config.gypi diff --git a/.remarkrc b/.remarkrc new file mode 100644 index 00000000000..d00f2c24882 --- /dev/null +++ b/.remarkrc @@ -0,0 +1,35 @@ +{ + "plugins": { + "remark-lint": { + "code-block-style": false, + "definition-case": false, + "emphasis-marker": false, + "first-heading-level": false, + "heading-increment": false, + "list-item-content-indent": false, + "list-item-bullet-indent": false, + "list-item-indent": false, + "list-item-spacing": false, + "maximum-heading-length": false, + "maximum-line-length": false, + "no-consecutive-blank-lines": false, + "no-duplicate-headings": false, + "no-emphasis-as-heading": false, + "no-file-name-articles": false, + "no-file-name-irregular-characters": false, + "no-heading-punctuation": false, + "no-html": false, + "no-inline-padding": false, + "no-shell-dollars": false, + "no-shortcut-reference-link": false, + "no-literal-urls": false, + "no-missing-blank-lines": false, + "no-multiple-toplevel-headings": false, + "no-undefined-references": false, + "ordered-list-marker-style": false, + "ordered-list-marker-value": false, + "table-pipe-alignment": false, + "unordered-list-marker-style": false + } + } +} diff --git a/BUILDING.md b/BUILDING.md index 532c478bbb7..a0978a80505 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -28,7 +28,7 @@ On FreeBSD and OpenBSD, you may also need: * libexecinfo (FreeBSD and OpenBSD only) -```text +```console $ ./configure $ make $ [sudo] make install @@ -37,7 +37,7 @@ $ [sudo] make install If your Python binary is in a non-standard location or has a non-standard name, run the following instead: -```text +```console $ export PYTHON=/path/to/python $ $PYTHON ./configure $ make @@ -46,13 +46,13 @@ $ [sudo] make install To run the tests: -```text +```console $ make test ``` To run the native module tests: -```text +```console $ make test-addons ``` @@ -61,7 +61,7 @@ To run the npm test suite: *note: to run the suite on node v4 or earlier you must first* *run `make install`* -``` +```console $ make test-npm ``` @@ -69,13 +69,13 @@ To build the documentation: This will build Node.js first (if necessary) and then use it to build the docs: -```text +```console $ make doc ``` If you have an existing Node.js you can build just the docs with: -```text +```console $ NODE=node make doc-only ``` @@ -83,13 +83,13 @@ $ NODE=node make doc-only To read the documentation: -```text +```console $ man doc/node.1 ``` To test if Node.js was built correctly: -``` +```console $ node -e "console.log('Hello from Node.js ' + process.version)" ``` @@ -101,25 +101,25 @@ Prerequisites: * [Python 2.6 or 2.7](https://www.python.org/downloads/) * One of: * [Visual C++ Build Tools](http://landinghub.visualstudio.com/visual-cpp-build-tools) - * [Visual Studio](https://www.visualstudio.com/) 2013 / 2015, all editions including the Community edition - * [Visual Studio](https://www.visualstudio.com/) Express 2013 / 2015 for Desktop + * [Visual Studio 2015 Update 3](https://www.visualstudio.com/), all editions + including the Community edition. * Basic Unix tools required for some tests, [Git for Windows](http://git-scm.com/download/win) includes Git Bash and tools which can be included in the global `PATH`. -```text +```console > vcbuild nosign ``` To run the tests: -```text +```console > vcbuild test ``` To test if Node.js was built correctly: -```text +```console > Release\node -e "console.log('Hello from Node.js', process.version)" ``` @@ -136,7 +136,7 @@ Be sure you have downloaded and extracted [Android NDK] (https://developer.android.com/tools/sdk/ndk/index.html) before in a folder. Then run: -``` +```console $ ./android-configure /path/to/your/android-ndk $ make ``` @@ -165,13 +165,13 @@ Node.js source does not include all locales.) ##### Unix / OS X: -```text +```console $ ./configure --with-intl=full-icu --download=all ``` ##### Windows: -```text +```console > vcbuild full-icu download-all ``` @@ -182,19 +182,19 @@ The `Intl` object will not be available, nor some other APIs such as ##### Unix / OS X: -```text +```console $ ./configure --without-intl ``` ##### Windows: -```text +```console > vcbuild without-intl ``` #### Use existing installed ICU (Unix / OS X only): -```text +```console $ pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu ``` @@ -210,14 +210,18 @@ Download the file named something like `icu4c-**##.#**-src.tgz` (or ##### Unix / OS X -```text -# from an already-unpacked ICU: +From an already-unpacked ICU: +```console $ ./configure --with-intl=[small-icu,full-icu] --with-icu-source=/path/to/icu +``` -# from a local ICU tarball +From a local ICU tarball: +```console $ ./configure --with-intl=[small-icu,full-icu] --with-icu-source=/path/to/icu.tgz +``` -# from a tarball URL +From a tarball URL: +```console $ ./configure --with-intl=full-icu --with-icu-source=http://url/to/icu.tgz ``` @@ -227,7 +231,7 @@ First unpack latest ICU to `deps/icu` [icu4c-**##.#**-src.tgz](http://icu-project.org/download) (or `.zip`) as `deps/icu` (You'll have: `deps/icu/source/...`) -```text +```console > vcbuild full-icu ``` diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 90d73e80e96..2bab2e20314 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -60,12 +60,20 @@ and work schedules. Trivial changes (e.g. those which fix minor bugs or improve performance without affecting API or causing other wide-reaching impact) may be landed after a shorter delay. -Where there is no disagreement amongst Collaborators, a pull request -may be landed given appropriate review. Where there is discussion +For non-breaking changes, if there is no disagreement amongst Collaborators, a +pull request may be landed given appropriate review. Where there is discussion amongst Collaborators, consensus should be sought if possible. The lack of consensus may indicate the need to elevate discussion to the CTC for resolution (see below). +Breaking changes (that is, pull requests that require an increase in the +major version number, known as `semver-major` changes) must be elevated for +review by the CTC. This does not necessarily mean that the PR must be put onto +the CTC meeting agenda. If multiple CTC members approve (`LGTM`) the PR and no +Collaborators oppose the PR, it can be landed. Where there is disagreement among +CTC members or objections from one or more Collaborators, `semver-major` pull +requests should be put on the CTC meeting agenda. + All bugfixes require a test case which demonstrates the defect. The test should *fail* before the change, and *pass* after the change. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50db95b3de9..ba8ca3da720 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,7 +100,7 @@ changed and why. Follow these guidelines when writing one: A good commit log can look something like this: -``` +```txt subsystem: explaining the commit in one line Body of commit message is a few lines of text, explaining things @@ -122,7 +122,7 @@ what subsystem (or subsystems) your changes touch. If your patch fixes an open issue, you can add a reference to it at the end of the log. Use the `Fixes:` prefix and the full issue URL. For example: -``` +```txt Fixes: https://github.com/nodejs/node/issues/1337 ``` @@ -135,7 +135,6 @@ $ git fetch upstream $ git rebase upstream/master ``` - ### Step 5: Test Bug fixes and features **should come with tests**. Add your tests in the @@ -143,15 +142,28 @@ Bug fixes and features **should come with tests**. Add your tests in the project, see this [guide](./doc/guides/writing_tests.md). Looking at other tests to see how they should be structured can also help. +To run the tests on Unix / OS X: + ```text $ ./configure && make -j8 test ``` +Windows: + +```text +> vcbuild test +``` + +(See the [BUILDING.md](./BUILDING.md) for more details.) + 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`. +Running `make test`/`vcbuild 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`/`vcbuild jslint`. 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/GOVERNANCE.md b/GOVERNANCE.md index 34b2f5fd1ec..d3ba8355e0f 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -56,6 +56,20 @@ For the current list of Collaborators, see the project A guide for Collaborators is maintained in [COLLABORATOR_GUIDE.md](./COLLABORATOR_GUIDE.md). +### Collaborator Activities + +Typical activities of a Collaborator include: + +* helping users and novice contributors +* contributing code and documentation changes that improve the project +* reviewing and commenting on issues and pull requests +* participation in working groups +* merging pull requests + +While the above are typical things done by Collaborators, there are no required +activities to retain Collaborator status. There is currently no process by which +inactive Collaborators are removed from the project. + ## CTC Membership CTC seats are not time-limited. There is no fixed size of the CTC. The CTC @@ -67,11 +81,15 @@ membership beyond these rules. The CTC may add additional members to the CTC by a standard CTC motion. -A CTC member may be removed from the CTC by voluntary resignation, or by -a standard CTC motion. +When a CTC member's participation in [CTC activities](#ctc-activities) has become +minimal for a sustained period of time, the CTC will request that the member +either indicate an intention to increase participation or voluntarily resign. + +CTC members may only be removed by voluntary resignation or through a standard +CTC motion. Changes to CTC membership should be posted in the agenda, and may be -suggested as any other agenda item (see "CTC Meetings" below). +suggested as any other agenda item (see [CTC Meetings](#ctc-meetings) below). No more than 1/3 of the CTC members may be affiliated with the same employer. If removal or resignation of a CTC member, or a change of @@ -80,7 +98,21 @@ the CTC membership shares an employer, then the situation must be immediately remedied by the resignation or removal of one or more CTC members affiliated with the over-represented employer(s). -## CTC Meetings +### CTC Activities + +Typical activities of a CTC member include: + +* attending the weekly meeting +* commenting on the weekly CTC meeting issue and issues labeled `ctc-agenda` +* participating in CTC email threads +* volunteering for tasks that arise from CTC meetings and related discussions +* other activities (beyond those typical of Collaborators) that facilitate the + smooth day-to-day operation of the Node.js project + +Note that CTC members are also Collaborators and therefore typically perform +Collaborator activities as well. + +### CTC Meetings The CTC meets weekly in a voice conference call. The meeting is run by a designated moderator approved by the CTC. Each meeting is streamed on YouTube. @@ -119,6 +151,8 @@ When an agenda item has appeared to reach a consensus, the moderator will ask "Does anyone object?" as a final call for dissent from the consensus. If an agenda item cannot reach a consensus, a CTC member can call for either a -closing vote or a vote to table the issue to the next meeting. The call for a -vote must be approved by a simple majority of the CTC or else the discussion -will continue. +closing vote or a vote to table the issue to the next meeting. All votes +(including votes to close or table) pass if and only if more than 50% of the CTC +members (excluding individuals who explicitly abstain) vote in favor. For +example, if there are 20 CTC members, and 5 of those members indicate that they +abstain, then 8 votes in favor are required for a resolution to pass. diff --git a/Makefile b/Makefile index c8279682cc7..fac19326946 100644 --- a/Makefile +++ b/Makefile @@ -150,7 +150,8 @@ ADDONS_BINDING_SOURCES := \ # Implicitly depends on $(NODE_EXE), see the build-addons rule for rationale. # Depends on node-gyp package.json so that build-addons is (re)executed when # node-gyp is updated as part of an npm update. -test/addons/.buildstamp: deps/npm/node_modules/node-gyp/package.json \ +test/addons/.buildstamp: config.gypi \ + deps/npm/node_modules/node-gyp/package.json \ $(ADDONS_BINDING_GYPS) $(ADDONS_BINDING_SOURCES) \ deps/uv/include/*.h deps/v8/include/*.h \ src/node.h src/node_buffer.h src/node_object_wrap.h \ @@ -696,7 +697,7 @@ cpplint: @$(PYTHON) tools/cpplint.py $(CPPLINT_FILES) @$(PYTHON) tools/check-imports.py -ifneq ("","$(wildcard tools/eslint/bin/eslint.js)") +ifneq ("","$(wildcard tools/eslint/lib/eslint.js)") lint: jslint cpplint CONFLICT_RE=^>>>>>>> [0-9A-Fa-f]+|^<<<<<<< [A-Za-z]+ lint-ci: jslint-ci cpplint diff --git a/benchmark/README.md b/benchmark/README.md index fcbb66946b0..225236cc103 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -30,8 +30,6 @@ install.packages("ggplot2") install.packages("plyr") ``` -[wrk]: https://github.com/wg/wrk - ## Running benchmarks ### Running individual benchmarks @@ -43,7 +41,7 @@ conclusions about the performance. Individual benchmarks can be executed by simply executing the benchmark script with node. -``` +```console $ node benchmark/buffers/buffer-tostring.js buffers/buffer-tostring.js n=10000000 len=0 arg=true: 62710590.393305704 @@ -65,7 +63,7 @@ measured in ops/sec (higher is better).** Furthermore you can specify a subset of the configurations, by setting them in the process arguments: -``` +```console $ node benchmark/buffers/buffer-tostring.js len=1024 buffers/buffer-tostring.js n=10000000 len=1024 arg=true: 3498295.68561504 @@ -78,7 +76,7 @@ Similar to running individual benchmarks, a group of benchmarks can be executed by using the `run.js` tool. Again this does not provide the statistical information to make any conclusions. -``` +```console $ node benchmark/run.js arrays arrays/var-int.js @@ -98,7 +96,7 @@ arrays/zero-int.js n=25 type=Buffer: 90.49906662339653 ``` It is possible to execute more groups by adding extra process arguments. -``` +```console $ node benchmark/run.js arrays buffers ``` @@ -119,13 +117,13 @@ First build two versions of node, one from the master branch (here called The `compare.js` tool will then produce a csv file with the benchmark results. -``` +```console $ node benchmark/compare.js --old ./node-master --new ./node-pr-5134 string_decoder > compare-pr-5134.csv ``` For analysing the benchmark results use the `compare.R` tool. -``` +```console $ cat compare-pr-5134.csv | Rscript benchmark/compare.R improvement significant p.value @@ -159,8 +157,6 @@ _For the statistically minded, the R script performs an [independent/unpaired same for both versions. The significant field will show a star if the p-value is less than `0.05`._ -[t-test]: https://en.wikipedia.org/wiki/Student%27s_t-test#Equal_or_unequal_sample_sizes.2C_unequal_variances - The `compare.R` tool can also produce a box plot by using the `--plot filename` option. In this case there are 48 different benchmark combinations, thus you may want to filter the csv file. This can be done while benchmarking using the @@ -168,7 +164,7 @@ may want to filter the csv file. This can be done while benchmarking using the afterwards using tools such as `sed` or `grep`. In the `sed` case be sure to keep the first line since that contains the header information. -``` +```console $ cat compare-pr-5134.csv | sed '1p;/encoding=ascii/!d' | Rscript benchmark/compare.R --plot compare-plot.png improvement significant p.value @@ -190,7 +186,7 @@ example to analyze the time complexity. To do this use the `scatter.js` tool, this will run a benchmark multiple times and generate a csv with the results. -``` +```console $ node benchmark/scatter.js benchmark/string_decoder/string-decoder.js > scatter.csv ``` @@ -198,7 +194,7 @@ After generating the csv, a comparison table can be created using the `scatter.R` tool. Even more useful it creates an actual scatter plot when using the `--plot filename` option. -``` +```console $ cat scatter.csv | Rscript benchmark/scatter.R --xaxis chunk --category encoding --plot scatter-plot.png --log aggregating variable: inlen @@ -229,7 +225,7 @@ can be solved by filtering. This can be done while benchmarking using the afterwards using tools such as `sed` or `grep`. In the `sed` case be sure to keep the first line since that contains the header information. -``` +```console $ cat scatter.csv | sed -E '1p;/([^,]+, ){3}128,/!d' | Rscript benchmark/scatter.R --xaxis chunk --category encoding --plot scatter-plot.png --log chunk encoding mean confidence.interval @@ -290,3 +286,6 @@ function main(conf) { bench.end(conf.n); } ``` + +[wrk]: https://github.com/wg/wrk +[t-test]: https://en.wikipedia.org/wiki/Student%27s_t-test#Equal_or_unequal_sample_sizes.2C_unequal_variances diff --git a/benchmark/buffers/buffer-bytelength.js b/benchmark/buffers/buffer-bytelength.js index 273115b3def..f52cbc2c6ba 100644 --- a/benchmark/buffers/buffer-bytelength.js +++ b/benchmark/buffers/buffer-bytelength.js @@ -50,7 +50,7 @@ function main(conf) { } function buildString(str, times) { - if (times == 1) return str; + if (times === 1) return str; return str + buildString(str, times - 1); } diff --git a/benchmark/common.js b/benchmark/common.js index 669a4c642b2..3807fea7957 100644 --- a/benchmark/common.js +++ b/benchmark/common.js @@ -30,7 +30,7 @@ function Benchmark(fn, options) { Benchmark.prototype._parseArgs = function(argv, options) { const cliOptions = Object.assign({}, options); - // Parse configuarion arguments + // Parse configuration arguments for (const arg of argv) { const match = arg.match(/^(.+?)=([\s\S]*)$/); if (!match || !match[1]) { @@ -52,7 +52,7 @@ Benchmark.prototype._queue = function(options) { const queue = []; const keys = Object.keys(options); - // Perform a depth-first walk though all options to genereate a + // Perform a depth-first walk though all options to generate a // configuration list that contains all combinations. function recursive(keyIndex, prevConfig) { const key = keys[keyIndex]; @@ -171,9 +171,9 @@ Benchmark.prototype._run = function() { }; Benchmark.prototype.start = function() { - if (this._started) + if (this._started) { throw new Error('Called start more than once in a single benchmark'); - + } this._started = true; this._time = process.hrtime(); }; @@ -195,7 +195,7 @@ Benchmark.prototype.end = function(operations) { }; function formatResult(data) { - // Construct confiuration string, " A=a, B=b, ..." + // Construct configuration string, " A=a, B=b, ..." let conf = ''; for (const key of Object.keys(data.conf)) { conf += ' ' + key + '=' + JSON.stringify(data.conf[key]); diff --git a/benchmark/compare.js b/benchmark/compare.js index fb179e0e470..de328d60fcb 100644 --- a/benchmark/compare.js +++ b/benchmark/compare.js @@ -33,7 +33,8 @@ const benchmarks = cli.benchmarks(); if (benchmarks.length === 0) { console.error('no benchmarks found'); - process.exit(1); + process.exitCode = 1; + return; } // Create queue from the benchmarks list such both node versions are tested @@ -65,7 +66,7 @@ console.log('"binary", "filename", "configuration", "rate", "time"'); } conf = conf.slice(1); - // Escape qoutes (") for correct csv formatting + // Escape quotes (") for correct csv formatting conf = conf.replace(/"/g, '""'); console.log(`"${job.binary}", "${job.filename}", "${conf}", ` + diff --git a/benchmark/crypto/cipher-stream.js b/benchmark/crypto/cipher-stream.js index b8e1622bf9f..11e2c38c0bd 100644 --- a/benchmark/crypto/cipher-stream.js +++ b/benchmark/crypto/cipher-stream.js @@ -31,7 +31,7 @@ function main(conf) { var bob_secret = bob.computeSecret(alice.getPublicKey(), pubEnc, 'hex'); // alice_secret and bob_secret should be the same - assert(alice_secret == bob_secret); + assert(alice_secret === bob_secret); var alice_cipher = crypto.createCipher(conf.cipher, alice_secret); var bob_cipher = crypto.createDecipher(conf.cipher, bob_secret); diff --git a/benchmark/dgram/array-vs-concat.js b/benchmark/dgram/array-vs-concat.js index 1f07a504239..8b1d34d0e74 100644 --- a/benchmark/dgram/array-vs-concat.js +++ b/benchmark/dgram/array-vs-concat.js @@ -46,14 +46,14 @@ function server() { var onsend = type === 'concat' ? onsendConcat : onsendMulti; function onsendConcat() { - if (sent++ % num == 0) + if (sent++ % num === 0) for (var i = 0; i < num; i++) { socket.send(Buffer.concat(chunk), PORT, '127.0.0.1', onsend); } } function onsendMulti() { - if (sent++ % num == 0) + if (sent++ % num === 0) for (var i = 0; i < num; i++) { socket.send(chunk, PORT, '127.0.0.1', onsend); } diff --git a/benchmark/dgram/multi-buffer.js b/benchmark/dgram/multi-buffer.js index 85e9561de8c..3277547119c 100644 --- a/benchmark/dgram/multi-buffer.js +++ b/benchmark/dgram/multi-buffer.js @@ -45,7 +45,7 @@ function server() { var socket = dgram.createSocket('udp4'); function onsend() { - if (sent++ % num == 0) + if (sent++ % num === 0) for (var i = 0; i < num; i++) socket.send(chunk, PORT, '127.0.0.1', onsend); } diff --git a/benchmark/dgram/offset-length.js b/benchmark/dgram/offset-length.js index ce9f4b025ad..5b7762b21e7 100644 --- a/benchmark/dgram/offset-length.js +++ b/benchmark/dgram/offset-length.js @@ -37,7 +37,7 @@ function server() { var socket = dgram.createSocket('udp4'); function onsend() { - if (sent++ % num == 0) + if (sent++ % num === 0) for (var i = 0; i < num; i++) socket.send(chunk, 0, chunk.length, PORT, '127.0.0.1', onsend); } diff --git a/benchmark/dgram/single-buffer.js b/benchmark/dgram/single-buffer.js index 4793f65eeab..e01b60b4297 100644 --- a/benchmark/dgram/single-buffer.js +++ b/benchmark/dgram/single-buffer.js @@ -37,7 +37,7 @@ function server() { var socket = dgram.createSocket('udp4'); function onsend() { - if (sent++ % num == 0) + if (sent++ % num === 0) for (var i = 0; i < num; i++) socket.send(chunk, PORT, '127.0.0.1', onsend); } diff --git a/benchmark/fs/bench-realpath.js b/benchmark/fs/bench-realpath.js new file mode 100644 index 00000000000..1a181935f14 --- /dev/null +++ b/benchmark/fs/bench-realpath.js @@ -0,0 +1,46 @@ +'use strict'; + +const common = require('../common'); +const fs = require('fs'); +const path = require('path'); +const resolved_path = path.resolve(__dirname, '../../lib/'); +const relative_path = path.relative(__dirname, '../../lib/'); + +const bench = common.createBenchmark(main, { + n: [1e4], + type: ['relative', 'resolved'], +}); + + +function main(conf) { + const n = conf.n >>> 0; + const type = conf.type; + + bench.start(); + if (type === 'relative') + relativePath(n); + else if (type === 'resolved') + resolvedPath(n); + else + throw new Error('unknown "type": ' + type); +} + +function relativePath(n) { + (function r(cntr) { + if (--cntr <= 0) + return bench.end(n); + fs.realpath(relative_path, function() { + r(cntr); + }); + }(n)); +} + +function resolvedPath(n) { + (function r(cntr) { + if (--cntr <= 0) + return bench.end(n); + fs.realpath(resolved_path, function() { + r(cntr); + }); + }(n)); +} diff --git a/benchmark/fs/bench-realpathSync.js b/benchmark/fs/bench-realpathSync.js new file mode 100644 index 00000000000..ae1c78d30d1 --- /dev/null +++ b/benchmark/fs/bench-realpathSync.js @@ -0,0 +1,39 @@ +'use strict'; + +const common = require('../common'); +const fs = require('fs'); +const path = require('path'); +const resolved_path = path.resolve(__dirname, '../../lib/'); +const relative_path = path.relative(__dirname, '../../lib/'); + +const bench = common.createBenchmark(main, { + n: [1e4], + type: ['relative', 'resolved'], +}); + + +function main(conf) { + const n = conf.n >>> 0; + const type = conf.type; + + bench.start(); + if (type === 'relative') + relativePath(n); + else if (type === 'resolved') + resolvedPath(n); + else + throw new Error('unknown "type": ' + type); + bench.end(n); +} + +function relativePath(n) { + for (var i = 0; i < n; i++) { + fs.realpathSync(relative_path); + } +} + +function resolvedPath(n) { + for (var i = 0; i < n; i++) { + fs.realpathSync(resolved_path); + } +} diff --git a/benchmark/http/_http_simple.js b/benchmark/http/_http_simple.js index 7e2eed53a1a..1c965b21c15 100644 --- a/benchmark/http/_http_simple.js +++ b/benchmark/http/_http_simple.js @@ -37,7 +37,7 @@ var server = module.exports = http.createServer(function(req, res) { var status = 200; var n, i; - if (command == 'bytes') { + if (command === 'bytes') { n = ~~arg; if (n <= 0) throw new Error('bytes called with n <= 0'); @@ -46,7 +46,7 @@ var server = module.exports = http.createServer(function(req, res) { } body = storedBytes[n]; - } else if (command == 'buffer') { + } else if (command === 'buffer') { n = ~~arg; if (n <= 0) throw new Error('buffer called with n <= 0'); @@ -58,7 +58,7 @@ var server = module.exports = http.createServer(function(req, res) { } body = storedBuffer[n]; - } else if (command == 'unicode') { + } else if (command === 'unicode') { n = ~~arg; if (n <= 0) throw new Error('unicode called with n <= 0'); @@ -67,14 +67,14 @@ var server = module.exports = http.createServer(function(req, res) { } body = storedUnicode[n]; - } else if (command == 'quit') { + } else if (command === 'quit') { res.connection.server.close(); body = 'quitting'; - } else if (command == 'fixed') { + } else if (command === 'fixed') { body = fixed; - } else if (command == 'echo') { + } else if (command === 'echo') { res.writeHead(200, { 'Content-Type': 'text/plain', 'Transfer-Encoding': 'chunked' }); req.pipe(res); diff --git a/benchmark/run.js b/benchmark/run.js index 756a7408bbb..16e620f9a0d 100644 --- a/benchmark/run.js +++ b/benchmark/run.js @@ -10,22 +10,38 @@ const cli = CLI(`usage: ./node run.js [options] [--] ... --filter pattern string to filter benchmark scripts --set variable=value set benchmark variable (can be repeated) + --format [simple|csv] optional value that specifies the output format `, { arrayArgs: ['set'] }); const benchmarks = cli.benchmarks(); if (benchmarks.length === 0) { - console.error('no benchmarks found'); - process.exit(1); + console.error('No benchmarks found'); + process.exitCode = 1; + return; +} + +const validFormats = ['csv', 'simple']; +const format = cli.optional.format || 'simple'; +if (!validFormats.includes(format)) { + console.error('Invalid format detected'); + process.exitCode = 1; + return; +} + +if (format === 'csv') { + console.log('"filename", "configuration", "rate", "time"'); } (function recursive(i) { const filename = benchmarks[i]; const child = fork(path.resolve(__dirname, filename), cli.optional.set); - console.log(); - console.log(filename); + if (format !== 'csv') { + console.log(); + console.log(filename); + } child.on('message', function(data) { // Construct configuration string, " A=a, B=b, ..." @@ -33,8 +49,15 @@ if (benchmarks.length === 0) { for (const key of Object.keys(data.conf)) { conf += ' ' + key + '=' + JSON.stringify(data.conf[key]); } - - console.log(`${data.name}${conf}: ${data.rate}`); + // delete first space of the configuration + conf = conf.slice(1); + if (format === 'csv') { + // Escape quotes (") for correct csv formatting + conf = conf.replace(/"/g, '""'); + console.log(`"${data.name}", "${conf}", ${data.rate}, ${data.time}`); + } else { + console.log(`${data.name} ${conf}: ${data.rate}`); + } }); child.once('close', function(code) { diff --git a/common.gypi b/common.gypi index 97498a36f4a..168e9628269 100644 --- a/common.gypi +++ b/common.gypi @@ -14,6 +14,7 @@ 'msvs_windows_target_platform_version': 'v10.0', # used for node_engine==chakracore 'node_shared%': 'false', + 'force_dynamic_crt%': 0, 'node_use_v8_platform%': 'true', 'node_use_bundled_v8%': 'true', 'node_module_version%': '', @@ -113,11 +114,24 @@ ['OS == "android"', { 'cflags': [ '-fPIE' ], 'ldflags': [ '-fPIE', '-pie' ] + }], + ['node_shared=="true"', { + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 3, # MultiThreadedDebugDLL (/MDd) + } + } + }], + ['node_shared=="false"', { + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 1 # MultiThreadedDebug (/MTd) + } + } }] ], 'msvs_settings': { 'VCCLCompilerTool': { - 'RuntimeLibrary': 1, # static debug 'Optimization': 0, # /Od, no optimization 'MinimalRebuild': 'false', 'OmitFramePointers': 'false', @@ -153,11 +167,24 @@ ['OS == "android"', { 'cflags': [ '-fPIE' ], 'ldflags': [ '-fPIE', '-pie' ] + }], + ['node_shared=="true"', { + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 2 # MultiThreadedDLL (/MD) + } + } + }], + ['node_shared=="false"', { + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 0 # MultiThreaded (/MT) + } + } }] ], 'msvs_settings': { 'VCCLCompilerTool': { - 'RuntimeLibrary': 0, # static release 'Optimization': 3, # /Ox, full optimization 'FavorSizeOrSpeed': 1, # /Ot, favour speed over size 'InlineFunctionExpansion': 2, # /Ob2, inline anything eligible @@ -282,8 +309,9 @@ 'cflags_cc': [ '-fno-rtti', '-fno-exceptions', '-std=gnu++0x' ], 'ldflags': [ '-rdynamic' ], 'target_conditions': [ - ['_type=="static_library"', { - 'standalone_static_library': 1, # disable thin archive which needs binutils >= 2.19 + # The 1990s toolchain on SmartOS can't handle thin archives. + ['_type=="static_library" and OS=="solaris"', { + 'standalone_static_library': 1, }], ], 'conditions': [ @@ -339,9 +367,13 @@ }], ], }], - [ 'OS=="android"', { - 'defines': ['_GLIBCXX_USE_C99_MATH'], - 'libraries': [ '-llog' ], + ['OS=="android"', { + 'target_conditions': [ + ['_toolset=="target"', { + 'defines': [ '_GLIBCXX_USE_C99_MATH' ], + 'libraries': [ '-llog' ], + }], + ], }], ['OS=="mac"', { 'defines': ['_DARWIN_USE_64_BIT_INODE=1'], diff --git a/configure b/configure index e918a7ddbe5..29e135ae8e8 100755 --- a/configure +++ b/configure @@ -848,7 +848,11 @@ def configure_node(o): o['variables']['node_no_browser_globals'] = b(options.no_browser_globals) o['variables']['node_shared'] = b(options.shared) - o['variables']['node_module_version'] = int(getmoduleversion.get_version()) + node_module_version = getmoduleversion.get_version() + shlib_suffix = '%s.dylib' if sys.platform == 'darwin' else 'so.%s' + shlib_suffix %= node_module_version + o['variables']['node_module_version'] = int(node_module_version) + o['variables']['shlib_suffix'] = shlib_suffix if options.linked_module: o['variables']['library_files'] = options.linked_module @@ -897,6 +901,7 @@ def configure_v8(o): o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true' o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform) o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8) + o['variables']['force_dynamic_crt'] = 1 if options.shared else 0 o['variables']['node_enable_d8'] = b(options.enable_d8) if options.enable_d8: o['variables']['test_isolation_mode'] = 'noop' # Needed by d8.gyp. diff --git a/deps/cares/cares.gyp b/deps/cares/cares.gyp index 745e38e33d2..158cef39b51 100644 --- a/deps/cares/cares.gyp +++ b/deps/cares/cares.gyp @@ -37,6 +37,7 @@ 'sources': [ 'common.gypi', 'include/ares.h', + 'include/ares_rules.h', 'include/ares_version.h', 'include/nameser.h', 'src/ares_cancel.c', @@ -83,7 +84,6 @@ 'src/ares_process.c', 'src/ares_query.c', 'src/ares__read_line.c', - 'src/ares_rules.h', 'src/ares_search.c', 'src/ares_send.c', 'src/ares_setup.h', diff --git a/deps/chakrashim/include/v8-version.h b/deps/chakrashim/include/v8-version.h index 833a4bed8cd..60cda0d7e7b 100644 --- a/deps/chakrashim/include/v8-version.h +++ b/deps/chakrashim/include/v8-version.h @@ -34,7 +34,7 @@ #define V8_MAJOR_VERSION 5 #define V8_MINOR_VERSION 1 #define V8_BUILD_NUMBER 281 -#define V8_PATCH_LEVEL 69 +#define V8_PATCH_LEVEL 80 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/chakrashim/include/v8.h b/deps/chakrashim/include/v8.h index 4d70ef5d3bf..7ce56a00e0c 100644 --- a/deps/chakrashim/include/v8.h +++ b/deps/chakrashim/include/v8.h @@ -1603,6 +1603,8 @@ class PropertyCallbackInfo { Local Data() const { return _data; } Local This() const { return _thisObject; } Local Holder() const { return _holder; } + // CHAKRA-TODO + bool ShouldThrowOnError() const { return true; } ReturnValue GetReturnValue() const { return ReturnValue( &(const_cast*>(this)->_returnValue)); diff --git a/deps/v8/build/toolchain.gypi b/deps/v8/build/toolchain.gypi index 60908980730..519779edb4f 100644 --- a/deps/v8/build/toolchain.gypi +++ b/deps/v8/build/toolchain.gypi @@ -39,6 +39,7 @@ 'ubsan_vptr%': 0, 'v8_target_arch%': '<(target_arch)', 'v8_host_byteorder%': ' out_buffer, while (*data == 0x66) data++; if (*data == 0xf && data[1] == 0x1f) { AppendToBuffer("nop"); // 0x66 prefix - } else if (*data == 0x90) { - AppendToBuffer("nop"); // 0x66 prefix - } else if (*data == 0x8B) { + } else if (*data == 0x39) { data++; - data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); + data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data); + } else if (*data == 0x3B) { + data++; + data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data); + } else if (*data == 0x81) { + data++; + AppendToBuffer("cmpw "); + data += PrintRightOperand(data); + int imm = *reinterpret_cast(data); + AppendToBuffer(",0x%x", imm); + data += 2; } else if (*data == 0x89) { data++; int mod, regop, rm; @@ -1614,6 +1622,11 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, AppendToBuffer("mov_w "); data += PrintRightOperand(data); AppendToBuffer(",%s", NameOfCPURegister(regop)); + } else if (*data == 0x8B) { + data++; + data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); + } else if (*data == 0x90) { + AppendToBuffer("nop"); // 0x66 prefix } else if (*data == 0xC7) { data++; AppendToBuffer("%s ", "mov_w"); diff --git a/deps/v8/src/regexp/jsregexp.cc b/deps/v8/src/regexp/jsregexp.cc index ddb4a16cafb..bbbfbeb7992 100644 --- a/deps/v8/src/regexp/jsregexp.cc +++ b/deps/v8/src/regexp/jsregexp.cc @@ -5879,6 +5879,7 @@ Vector CharacterRange::GetWordBounds() { void CharacterRange::AddCaseEquivalents(Isolate* isolate, Zone* zone, ZoneList* ranges, bool is_one_byte) { + CharacterRange::Canonicalize(ranges); int range_count = ranges->length(); for (int i = 0; i < range_count; i++) { CharacterRange range = ranges->at(i); diff --git a/deps/v8/test/cctest/test-assembler-ia32.cc b/deps/v8/test/cctest/test-assembler-ia32.cc index 12733c2cdda..e4cac56c150 100644 --- a/deps/v8/test/cctest/test-assembler-ia32.cc +++ b/deps/v8/test/cctest/test-assembler-ia32.cc @@ -1497,4 +1497,45 @@ TEST(AssemblerIa32JumpTables2) { } } +TEST(Regress621926) { + // Bug description: + // The opcodes for cmpw r/m16, r16 and cmpw r16, r/m16 were swapped. + // This was causing non-commutative comparisons to produce the wrong result. + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast(CcTest::isolate()); + HandleScope scope(isolate); + Assembler assm(isolate, nullptr, 0); + + uint16_t a = 42; + + Label fail; + __ push(ebx); + __ mov(ebx, Immediate(reinterpret_cast(&a))); + __ mov(eax, Immediate(41)); + __ cmpw(eax, Operand(ebx, 0)); + __ j(above_equal, &fail); + __ cmpw(Operand(ebx, 0), eax); + __ j(below_equal, &fail); + __ mov(eax, 1); + __ pop(ebx); + __ ret(0); + __ bind(&fail); + __ mov(eax, 0); + __ pop(ebx); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + Handle code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle()); + +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif + + F0 f = FUNCTION_CAST(code->entry()); + CHECK_EQ(f(), 1); +} + #undef __ diff --git a/deps/v8/test/mjsunit/regress/regress-5199.js b/deps/v8/test/mjsunit/regress/regress-5199.js new file mode 100644 index 00000000000..818e71a06d3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-5199.js @@ -0,0 +1,5 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +assertTrue(/(a[\u1000A])+/i.test('aa')); diff --git a/deps/v8_inspector/README.md b/deps/v8_inspector/README.md index d99d25f94ce..60578c90324 100644 --- a/deps/v8_inspector/README.md +++ b/deps/v8_inspector/README.md @@ -7,4 +7,5 @@ Node.js support for the [Chrome Debug Protocol][https://developer.chrome.com/dev * third_party/v8_inspector/platform/v8_inspector: vendored from https://chromium.googlesource.com/chromium/src/third_party/WebKit/Source/platform/v8_inspector * third_party/v8_inspector/platform/inspector_protocol: vendored from https://chromium.googlesource.com/chromium/src/third_party/WebKit/Source/platform/inspector_protocol * third_party/jinja2: vendored from https://github.com/mitsuhiko/jinja2 + * The `tests/` directory `ext/jinja.el` file have been deleted. * third_party/markupsafe: vendored from https://github.com/mitsuhiko/markupsafe diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Array.h b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Array.h index d92af3a5ed7..720182258b9 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Array.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Array.h @@ -17,7 +17,7 @@ namespace blink { namespace protocol { template -class ArrayBase { +class Array { public: static std::unique_ptr> create() { @@ -31,12 +31,12 @@ class ArrayBase { errors->addError("array expected"); return nullptr; } - errors->push(); std::unique_ptr> result(new Array()); + errors->push(); for (size_t i = 0; i < array->size(); ++i) { errors->setName(String16::fromInteger(i)); - T item = FromValue::parse(array->at(i), errors); - result->m_vector.push_back(item); + std::unique_ptr item = ValueConversions::parse(array->at(i), errors); + result->m_vector.push_back(std::move(item)); } errors->pop(); if (errors->hasErrors()) @@ -44,9 +44,9 @@ class ArrayBase { return result; } - void addItem(const T& value) + void addItem(std::unique_ptr value) { - m_vector.push_back(value); + m_vector.push_back(std::move(value)); } size_t length() @@ -54,31 +54,25 @@ class ArrayBase { return m_vector.size(); } - T get(size_t index) + T* get(size_t index) { - return m_vector[index]; + return m_vector[index].get(); } std::unique_ptr serialize() { std::unique_ptr result = ListValue::create(); for (auto& item : m_vector) - result->pushValue(toValue(item)); + result->pushValue(ValueConversions::serialize(item)); return result; } private: - std::vector m_vector; + std::vector> m_vector; }; -template<> class Array : public ArrayBase {}; -template<> class Array : public ArrayBase {}; -template<> class Array : public ArrayBase {}; -template<> class Array : public ArrayBase {}; -template<> class Array : public ArrayBase {}; - template -class Array { +class ArrayBase { public: static std::unique_ptr> create() { @@ -92,12 +86,12 @@ class Array { errors->addError("array expected"); return nullptr; } - std::unique_ptr> result(new Array()); errors->push(); + std::unique_ptr> result(new Array()); for (size_t i = 0; i < array->size(); ++i) { errors->setName(String16::fromInteger(i)); - std::unique_ptr item = FromValue::parse(array->at(i), errors); - result->m_vector.push_back(std::move(item)); + T item = ValueConversions::parse(array->at(i), errors); + result->m_vector.push_back(item); } errors->pop(); if (errors->hasErrors()) @@ -105,9 +99,9 @@ class Array { return result; } - void addItem(std::unique_ptr value) + void addItem(const T& value) { - m_vector.push_back(std::move(value)); + m_vector.push_back(value); } size_t length() @@ -115,23 +109,29 @@ class Array { return m_vector.size(); } - T* get(size_t index) + T get(size_t index) { - return m_vector[index].get(); + return m_vector[index]; } std::unique_ptr serialize() { std::unique_ptr result = ListValue::create(); for (auto& item : m_vector) - result->pushValue(toValue(item)); + result->pushValue(ValueConversions::serialize(item)); return result; } private: - std::vector> m_vector; + std::vector m_vector; }; +template<> class Array : public ArrayBase {}; +template<> class Array : public ArrayBase {}; +template<> class Array : public ArrayBase {}; +template<> class Array : public ArrayBase {}; +template<> class Array : public ArrayBase {}; + } // namespace platform } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/CodeGenerator.py b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/CodeGenerator.py index c785c79b528..0b09c8e9040 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/CodeGenerator.py +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/CodeGenerator.py @@ -24,11 +24,18 @@ # In Blink, jinja2 is in chromium's third_party directory. # Insert at 1 so at front to override system libraries, and # after path[0] == invoking script dir -third_party_dir = os.path.normpath(os.path.join( +blink_third_party_dir = os.path.normpath(os.path.join( module_path, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir, "third_party")) -if os.path.isdir(third_party_dir): - sys.path.insert(1, third_party_dir) +if os.path.isdir(blink_third_party_dir): + sys.path.insert(1, blink_third_party_dir) + +# In V8, it is in third_party folder +v8_third_party_dir = os.path.normpath(os.path.join( + module_path, os.pardir, os.pardir, "third_party")) + +if os.path.isdir(v8_third_party_dir): + sys.path.insert(1, v8_third_party_dir) # In Node, it is in deps folder deps_dir = os.path.normpath(os.path.join( @@ -43,10 +50,13 @@ cmdline_parser = optparse.OptionParser() cmdline_parser.add_option("--protocol") cmdline_parser.add_option("--include") +cmdline_parser.add_option("--include_package") cmdline_parser.add_option("--string_type") cmdline_parser.add_option("--export_macro") cmdline_parser.add_option("--output_dir") cmdline_parser.add_option("--output_package") +cmdline_parser.add_option("--exported_dir") +cmdline_parser.add_option("--exported_package") try: arg_options, arg_values = cmdline_parser.parse_args() @@ -54,12 +64,23 @@ if not protocol_file: raise Exception("Protocol directory must be specified") include_file = arg_options.include + include_package = arg_options.include_package + if include_file and not include_package: + raise Exception("Include package must be specified when using include file") + if include_package and not include_file: + raise Exception("Include file must be specified when using include package") output_dirname = arg_options.output_dir if not output_dirname: raise Exception("Output directory must be specified") output_package = arg_options.output_package if not output_package: raise Exception("Output package must be specified") + exported_dirname = arg_options.exported_dir + if not exported_dirname: + exported_dirname = os.path.join(output_dirname, "exported") + exported_package = arg_options.exported_package + if not exported_package: + exported_package = os.path.join(output_package, "exported") string_type = arg_options.string_type if not string_type: raise Exception("String type must be specified") @@ -84,30 +105,38 @@ def up_to_date(): os.path.getmtime(__file__), os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_h.template")), os.path.getmtime(os.path.join(templates_dir, "TypeBuilder_cpp.template")), + os.path.getmtime(os.path.join(templates_dir, "Exported_h.template")), + os.path.getmtime(os.path.join(templates_dir, "Imported_h.template")), os.path.getmtime(protocol_file)) for domain in parsed_json["domains"]: name = domain["domain"] - h_path = os.path.join(output_dirname, name + ".h") - cpp_path = os.path.join(output_dirname, name + ".cpp") - if not os.path.exists(h_path) or not os.path.exists(cpp_path): - return False - generated_ts = max(os.path.getmtime(h_path), os.path.getmtime(cpp_path)) - if generated_ts < template_ts: - return False + paths = [] + if name in generate_domains: + paths = [os.path.join(output_dirname, name + ".h"), os.path.join(output_dirname, name + ".cpp")] + if domain["has_exports"]: + paths.append(os.path.join(exported_dirname, name + ".h")) + if name in include_domains and domain["has_exports"]: + paths = [os.path.join(output_dirname, name + '.h')] + for path in paths: + if not os.path.exists(path): + return False + generated_ts = os.path.getmtime(path) + if generated_ts < template_ts: + return False return True -if up_to_date(): - sys.exit() - - def to_title_case(name): return name[:1].upper() + name[1:] def dash_to_camelcase(word): - return "".join(to_title_case(x) or "-" for x in word.split("-")) + prefix = "" + if word[0] == "-": + prefix = "Negative" + word = word[1:] + return prefix + "".join(to_title_case(x) or "-" for x in word.split("-")) def initialize_jinja_env(cache_dir): @@ -144,12 +173,47 @@ def patch_full_qualified_refs_in_domain(json, domain_name): continue if json["$ref"].find(".") == -1: json["$ref"] = domain_name + "." + json["$ref"] + return for domain in json_api["domains"]: patch_full_qualified_refs_in_domain(domain, domain["domain"]) +def calculate_exports(): + def calculate_exports_in_json(json_value): + has_exports = False + if isinstance(json_value, list): + for item in json_value: + has_exports = calculate_exports_in_json(item) or has_exports + if isinstance(json_value, dict): + has_exports = ("exported" in json_value and json_value["exported"]) or has_exports + for key in json_value: + has_exports = calculate_exports_in_json(json_value[key]) or has_exports + return has_exports + + json_api["has_exports"] = False + for domain_json in json_api["domains"]: + domain_json["has_exports"] = calculate_exports_in_json(domain_json) + json_api["has_exports"] = json_api["has_exports"] or domain_json["has_exports"] + + +def create_include_type_definition(domain_name, type): + # pylint: disable=W0622 + return { + "return_type": "std::unique_ptr" % (domain_name, type["id"]), + "pass_type": "std::unique_ptr" % (domain_name, type["id"]), + "to_raw_type": "%s.get()", + "to_pass_type": "std::move(%s)", + "to_rvalue": "std::move(%s)", + "type": "std::unique_ptr" % (domain_name, type["id"]), + "raw_type": "protocol::%s::API::%s" % (domain_name, type["id"]), + "raw_pass_type": "protocol::%s::API::%s*" % (domain_name, type["id"]), + "raw_return_type": "protocol::%s::API::%s*" % (domain_name, type["id"]), + } + + def create_user_type_definition(domain_name, type): + # pylint: disable=W0622 return { "return_type": "std::unique_ptr" % (domain_name, type["id"]), "pass_type": "std::unique_ptr" % (domain_name, type["id"]), @@ -164,6 +228,7 @@ def create_user_type_definition(domain_name, type): def create_object_type_definition(): + # pylint: disable=W0622 return { "return_type": "std::unique_ptr", "pass_type": "std::unique_ptr", @@ -178,6 +243,7 @@ def create_object_type_definition(): def create_any_type_definition(): + # pylint: disable=W0622 return { "return_type": "std::unique_ptr", "pass_type": "std::unique_ptr", @@ -192,6 +258,7 @@ def create_any_type_definition(): def create_string_type_definition(domain): + # pylint: disable=W0622 return { "return_type": string_type, "pass_type": ("const %s&" % string_type), @@ -206,6 +273,7 @@ def create_string_type_definition(domain): def create_primitive_type_definition(type): + # pylint: disable=W0622 typedefs = { "number": "double", "integer": "int", @@ -244,6 +312,7 @@ def create_primitive_type_definition(type): def wrap_array_definition(type): + # pylint: disable=W0622 return { "return_type": "std::unique_ptr>" % type["raw_type"], "pass_type": "std::unique_ptr>" % type["raw_type"], @@ -265,15 +334,18 @@ def create_type_definitions(): if not ("types" in domain): continue for type in domain["types"]: - if type["type"] == "object": - type_definitions[domain["domain"] + "." + type["id"]] = create_user_type_definition(domain["domain"], type) + type_name = domain["domain"] + "." + type["id"] + if type["type"] == "object" and domain["domain"] in include_domains: + type_definitions[type_name] = create_include_type_definition(domain["domain"], type) + elif type["type"] == "object": + type_definitions[type_name] = create_user_type_definition(domain["domain"], type) elif type["type"] == "array": items_type = type["items"]["type"] - type_definitions[domain["domain"] + "." + type["id"]] = wrap_array_definition(type_definitions[items_type]) + type_definitions[type_name] = wrap_array_definition(type_definitions[items_type]) elif type["type"] == domain["domain"] + ".string": - type_definitions[domain["domain"] + "." + type["id"]] = create_string_type_definition(domain["domain"]) + type_definitions[type_name] = create_string_type_definition(domain["domain"]) else: - type_definitions[domain["domain"] + "." + type["id"]] = create_primitive_type_definition(type["type"]) + type_definitions[type_name] = create_primitive_type_definition(type["type"]) def type_definition(name): @@ -303,7 +375,25 @@ def has_disable(commands): return False +def generate(domain_object, template, file_name): + template_context = { + "domain": domain_object, + "join_arrays": join_arrays, + "resolve_type": resolve_type, + "type_definition": type_definition, + "has_disable": has_disable, + "export_macro": export_macro, + "output_package": output_package, + "exported_package": exported_package, + "include_package": include_package + } + out_file = output_file(file_name) + out_file.write(template.render(template_context)) + out_file.close() + + generate_domains = [] +include_domains = [] json_api = {} json_api["domains"] = parsed_json["domains"] @@ -314,44 +404,33 @@ def has_disable(commands): input_file = open(include_file, "r") json_string = input_file.read() parsed_json = json.loads(json_string) + for domain in parsed_json["domains"]: + include_domains.append(domain["domain"]) json_api["domains"] += parsed_json["domains"] - patch_full_qualified_refs() +calculate_exports() create_type_definitions() +if up_to_date(): + sys.exit() if not os.path.exists(output_dirname): os.mkdir(output_dirname) -jinja_env = initialize_jinja_env(output_dirname) - -h_template_name = "/TypeBuilder_h.template" -cpp_template_name = "/TypeBuilder_cpp.template" -h_template = jinja_env.get_template(h_template_name) -cpp_template = jinja_env.get_template(cpp_template_name) - - -def generate(domain): - class_name = domain["domain"] - h_file_name = output_dirname + "/" + class_name + ".h" - cpp_file_name = output_dirname + "/" + class_name + ".cpp" - - template_context = { - "domain": domain, - "join_arrays": join_arrays, - "resolve_type": resolve_type, - "type_definition": type_definition, - "has_disable": has_disable, - "export_macro": export_macro, - "output_package": output_package, - } - h_file = output_file(h_file_name) - cpp_file = output_file(cpp_file_name) - h_file.write(h_template.render(template_context)) - cpp_file.write(cpp_template.render(template_context)) - h_file.close() - cpp_file.close() +if json_api["has_exports"] and not os.path.exists(exported_dirname): + os.mkdir(exported_dirname) +jinja_env = initialize_jinja_env(output_dirname) +h_template = jinja_env.get_template("/TypeBuilder_h.template") +cpp_template = jinja_env.get_template("/TypeBuilder_cpp.template") +exported_template = jinja_env.get_template("/Exported_h.template") +imported_template = jinja_env.get_template("/Imported_h.template") for domain in json_api["domains"]: + class_name = domain["domain"] if domain["domain"] in generate_domains: - generate(domain) + generate(domain, h_template, output_dirname + "/" + class_name + ".h") + generate(domain, cpp_template, output_dirname + "/" + class_name + ".cpp") + if domain["has_exports"]: + generate(domain, exported_template, exported_dirname + "/" + class_name + ".h") + if domain["domain"] in include_domains and domain["has_exports"]: + generate(domain, imported_template, output_dirname + "/" + class_name + ".h") diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/DispatcherBase.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/DispatcherBase.cpp index 49422eba09a..8f154f42ac2 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/DispatcherBase.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/DispatcherBase.cpp @@ -34,7 +34,7 @@ void DispatcherBase::Callback::dispose() void DispatcherBase::Callback::sendIfActive(std::unique_ptr partialMessage, const ErrorString& invocationError) { - if (!m_backendImpl->get()) + if (!m_backendImpl || !m_backendImpl->get()) return; m_backendImpl->get()->sendResponse(m_callId, invocationError, nullptr, std::move(partialMessage)); m_backendImpl = nullptr; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Exported_h.template b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Exported_h.template new file mode 100644 index 00000000000..5cfabc53cf1 --- /dev/null +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Exported_h.template @@ -0,0 +1,65 @@ +// This file is generated + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef protocol_{{domain.domain}}_api_h +#define protocol_{{domain.domain}}_api_h + +{% if export_macro == "PLATFORM_EXPORT" %} +#include "platform/inspector_protocol/Platform.h" +{% else %} +#include "core/CoreExport.h" +{% endif %} +#include "platform/inspector_protocol/String16.h" + +namespace blink { +namespace protocol { +namespace {{domain.domain}} { +namespace API { + +// ------------- Enums. + {% for type in domain.types %} + {% if ("enum" in type) and type.exported %} + +namespace {{type.id}}Enum { + {% for literal in type.enum %} +{{export_macro}} extern const char* {{ literal | dash_to_camelcase}}; + {% endfor %} +} // {{type.id}}Enum + {% endif %} + {% endfor %} + {% for command in join_arrays(domain, ["commands", "events"]) %} + {% for param in join_arrays(command, ["parameters", "returns"]) %} + {% if ("enum" in param) and (param.exported) %} + +namespace {{command.name | to_title_case}} { +namespace {{param.name | to_title_case}}Enum { + {% for literal in param.enum %} +{{export_macro}} extern const char* {{ literal | dash_to_camelcase}}; + {% endfor %} +} // {{param.name | to_title_case}}Enum +} // {{command.name | to_title_case }} + {% endif %} + {% endfor %} + {% endfor %} + +// ------------- Types. + {% for type in domain.types %} + {% if not (type.type == "object") or not ("properties" in type) or not (type.exported) %}{% continue %}{% endif %} + +class {{export_macro}} {{type.id}} { +public: + virtual String16 toJSONString() const = 0; + virtual ~{{type.id}}() { } + static std::unique_ptr fromJSONString(const String16& json); +}; + {% endfor %} + +} // namespace API +} // namespace {{domain.domain}} +} // namespace protocol +} // namespace blink + +#endif // !defined(protocol_{{domain.domain}}_api_h) diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Imported_h.template b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Imported_h.template new file mode 100644 index 00000000000..a9abdad1726 --- /dev/null +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Imported_h.template @@ -0,0 +1,49 @@ +// This file is generated + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef protocol_{{domain.domain}}_imported_h +#define protocol_{{domain.domain}}_imported_h + +#include "platform/inspector_protocol/ErrorSupport.h" +#include "platform/inspector_protocol/ValueConversions.h" +#include "platform/inspector_protocol/Values.h" +#include "{{include_package}}/{{domain.domain}}.h" + +namespace blink { +namespace protocol { + {% for type in domain.types %} + {% if not (type.type == "object") or not ("properties" in type) or not (type.exported) %}{% continue %}{% endif %} + +template<> +struct ValueConversions<{{domain.domain}}::API::{{type.id}}> { + static std::unique_ptr<{{domain.domain}}::API::{{type.id}}> parse(protocol::Value* value, ErrorSupport* errors) + { + if (!value) { + errors->addError("value expected"); + return nullptr; + } + std::unique_ptr<{{domain.domain}}::API::{{type.id}}> result = {{domain.domain}}::API::{{type.id}}::fromJSONString(value->toJSONString()); + if (!result) + errors->addError("cannot parse"); + return result; + } + + static std::unique_ptr serialize({{domain.domain}}::API::{{type.id}}* value) + { + return SerializedValue::create(value->toJSONString()); + } + + static std::unique_ptr serialize(const std::unique_ptr<{{domain.domain}}::API::{{type.id}}>& value) + { + return SerializedValue::create(value->toJSONString()); + } +}; + {% endfor %} + +} // namespace protocol +} // namespace blink + +#endif // !defined(protocol_{{domain.domain}}_imported_h) diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.cpp index 4883f4ceda4..10c7fa61017 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.cpp @@ -113,14 +113,6 @@ inline char upperNibbleToASCIIHexDigit(char c) return nibble < 10 ? '0' + nibble : 'A' + nibble - 10; } -template inline bool isASCIIAlphaCaselessEqual(CharType cssCharacter, char character) -{ - // This function compares a (preferrably) constant ASCII - // lowercase letter to any input character. - DCHECK(character >= 'a' && character <= 'z'); - return LIKELY(toASCIILowerUnchecked(cssCharacter) == character); -} - inline int inlineUTF8SequenceLengthNonASCII(char b0) { if ((b0 & 0xC0) != 0xC0) diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.h b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.h index 703e5b0f025..4dd4369ebdd 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/String16STL.h @@ -5,6 +5,7 @@ #ifndef String16STL_h #define String16STL_h +#include #include #include #include @@ -141,7 +142,7 @@ class String16 { static inline bool isSpaceOrNewline(UChar c) { - return false; + return std::isspace(c); // NOLINT } class String16Builder { diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_cpp.template b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_cpp.template index 909fea4e71a..e3c2fa1de67 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_cpp.template +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_cpp.template @@ -7,6 +7,7 @@ #include "{{output_package}}/{{domain.domain}}.h" #include "platform/inspector_protocol/DispatcherBase.h" +#include "platform/inspector_protocol/Parser.h" namespace blink { namespace protocol { @@ -15,6 +16,7 @@ namespace {{domain.domain}} { // ------------- Enum values from types. const char Metainfo::domainName[] = "{{domain.domain}}"; +const char Metainfo::commandPrefix[] = "{{domain.domain}}."; {% for type in domain.types %} {% if "enum" in type %} @@ -22,7 +24,17 @@ namespace {{type.id}}Enum { {% for literal in type.enum %} const char* {{ literal | dash_to_camelcase}} = "{{literal}}"; {% endfor %} -} // {{type.id}}Enum +} // namespace {{type.id}}Enum + {% if type.exported %} + +namespace API { +namespace {{type.id}}Enum { + {% for literal in type.enum %} +const char* {{ literal | dash_to_camelcase}} = "{{literal}}"; + {% endfor %} +} // namespace {{type.id}}Enum +} // namespace API + {% endif %} {% endif %} {% for property in type.properties %} {% if "enum" in property %} @@ -49,11 +61,11 @@ std::unique_ptr<{{type.id}}> {{type.id}}::parse(protocol::Value* value, ErrorSup {% if property.optional %} if ({{property.name}}Value) { errors->setName("{{property.name}}"); - result->m_{{property.name}} = FromValue<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); + result->m_{{property.name}} = ValueConversions<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); } {% else %} errors->setName("{{property.name}}"); - result->m_{{property.name}} = FromValue<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); + result->m_{{property.name}} = ValueConversions<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); {% endif %} {% endfor %} errors->pop(); @@ -68,9 +80,9 @@ std::unique_ptr {{type.id}}::serialize() const {% for property in type.properties %} {% if property.optional %} if (m_{{property.name}}.isJust()) - result->setValue("{{property.name}}", toValue(m_{{property.name}}.fromJust())); + result->setValue("{{property.name}}", ValueConversions<{{resolve_type(property).raw_type}}>::serialize(m_{{property.name}}.fromJust())); {% else %} - result->setValue("{{property.name}}", toValue({{resolve_type(property).to_raw_type % ("m_" + property.name)}})); + result->setValue("{{property.name}}", ValueConversions<{{resolve_type(property).raw_type}}>::serialize({{resolve_type(property).to_raw_type % ("m_" + property.name)}})); {% endif %} {% endfor %} return result; @@ -81,6 +93,23 @@ std::unique_ptr<{{type.id}}> {{type.id}}::clone() const ErrorSupport errors; return parse(serialize().get(), &errors); } + {% if type.exported %} + +String16 {{type.id}}::toJSONString() const +{ + return serialize()->toJSONString(); +} + +// static +std::unique_ptr API::{{type.id}}::fromJSONString(const String16& json) +{ + ErrorSupport errors; + std::unique_ptr value = parseJSON(json); + if (!value) + return nullptr; + return protocol::{{domain.domain}}::{{type.id}}::parse(value.get(), &errors); +} + {% endif %} {% endfor %} // ------------- Enum values from params. @@ -94,8 +123,20 @@ namespace {{param.name | to_title_case}}Enum { {% for literal in param.enum %} const char* {{ literal | to_title_case}} = "{{literal}}"; {% endfor %} -} // {{param.name | to_title_case}}Enum -} // {{command.name | to_title_case }} +} // namespace {{param.name | to_title_case}}Enum +} // namespace {{command.name | to_title_case }} + {% if param.exported %} + +namespace API { +namespace {{command.name | to_title_case}} { +namespace {{param.name | to_title_case}}Enum { + {% for literal in param.enum %} +const char* {{ literal | to_title_case}} = "{{literal}}"; + {% endfor %} +} // namespace {{param.name | to_title_case}}Enum +} // namespace {{command.name | to_title_case }} +} // namespace API + {% endif %} {% endif %} {% endfor %} {% endfor %} @@ -119,9 +160,9 @@ void Frontend::{{event.name}}( {% for parameter in event.parameters %} {% if "optional" in parameter %} if ({{parameter.name}}.isJust()) - paramsObject->setValue("{{parameter.name}}", toValue({{parameter.name}}.fromJust())); + paramsObject->setValue("{{parameter.name}}", ValueConversions<{{resolve_type(parameter).raw_type}}>::serialize({{parameter.name}}.fromJust())); {% else %} - paramsObject->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).to_raw_type % parameter.name}})); + paramsObject->setValue("{{parameter.name}}", ValueConversions<{{resolve_type(parameter).raw_type}}>::serialize({{resolve_type(parameter).to_raw_type % parameter.name}})); {% endif %} {% endfor %} jsonMessage->setObject("params", std::move(paramsObject)); @@ -196,9 +237,9 @@ public: {% for parameter in command.returns %} {% if "optional" in parameter %} if ({{parameter.name}}.isJust()) - resultObject->setValue("{{parameter.name}}", toValue({{parameter.name}}.fromJust())); + resultObject->setValue("{{parameter.name}}", ValueConversions<{{resolve_type(parameter).raw_type}}>::serialize({{parameter.name}}.fromJust())); {% else %} - resultObject->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).to_raw_type % parameter.name}})); + resultObject->setValue("{{parameter.name}}", ValueConversions<{{resolve_type(parameter).raw_type}}>::serialize({{resolve_type(parameter).to_raw_type % parameter.name}})); {% endif %} {% endfor %} sendIfActive(std::move(resultObject), ErrorString()); @@ -225,11 +266,11 @@ void DispatcherImpl::{{command.name}}(int callId, std::unique_ptr in_{{property.name}}; if ({{property.name}}Value) { errors->setName("{{property.name}}"); - in_{{property.name}} = FromValue<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); + in_{{property.name}} = ValueConversions<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); } {% else %} errors->setName("{{property.name}}"); - {{resolve_type(property).type}} in_{{property.name}} = FromValue<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); + {{resolve_type(property).type}} in_{{property.name}} = ValueConversions<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors); {% endif %} {% endfor %} errors->pop(); @@ -253,6 +294,7 @@ void DispatcherImpl::{{command.name}}(int callId, std::unique_ptr weak = weakPtr(); + {% if not("async" in command) %} ErrorString error; m_backend->{{command.name}}(&error {%- for property in command.parameters -%} @@ -262,29 +304,38 @@ void DispatcherImpl::{{command.name}}(int callId, std::unique_ptrsetValue("{{parameter.name}}", toValue(out_{{parameter.name}}.fromJust())); - {% else %} - result->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).to_raw_type % ("out_" + parameter.name)}})); - {% endif %} - {% endfor %} + result->setValue("{{parameter.name}}", ValueConversions<{{resolve_type(parameter).raw_type}}>::serialize(out_{{parameter.name}}.fromJust())); + {% else %} + result->setValue("{{parameter.name}}", ValueConversions<{{resolve_type(parameter).raw_type}}>::serialize({{resolve_type(parameter).to_raw_type % ("out_" + parameter.name)}})); + {% endif %} + {% endfor %} } if (weak->get()) weak->get()->sendResponse(callId, error, std::move(result)); - {% elif not("async" in command) %} + {% else %} if (weak->get()) weak->get()->sendResponse(callId, error); + {% endif %} + {%- else %} + m_backend->{{command.name}}( + {%- for property in command.parameters -%} + {%- if "optional" in property -%} + in_{{property.name}}, + {%- else -%} + {{resolve_type(property).to_pass_type % ("in_" + property.name)}}, + {%- endif -%} + {%- endfor -%} + std::move(callback)); {% endif %} } {% endfor %} diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_h.template b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_h.template index 05ca81d3a57..83310065e0f 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_h.template +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/TypeBuilder_h.template @@ -23,9 +23,14 @@ #include "platform/inspector_protocol/String16.h" #include "platform/inspector_protocol/Values.h" #include "platform/inspector_protocol/ValueConversions.h" +// For each imported domain we generate a ValueConversions struct instead of a full domain definition +// and include Domain::API version from there. {% for name in domain.dependencies %} #include "{{output_package}}/{{name}}.h" {% endfor %} +{% if domain["has_exports"] %} +#include "{{exported_package}}/{{domain.domain}}.h" +{% endif %} namespace blink { namespace protocol { @@ -53,7 +58,7 @@ namespace {{type.id}}Enum { {% for literal in type.enum %} {{export_macro}} extern const char* {{ literal | dash_to_camelcase}}; {% endfor %} -} // {{type.id}}Enum +} // namespace {{type.id}}Enum {% endif %} {% endfor %} {% for command in join_arrays(domain, ["commands", "events"]) %} @@ -77,7 +82,8 @@ namespace {{param.name | to_title_case}}Enum { {% set type_def = type_definition(domain.domain + "." + type.id)%} // {{type.description}} -class {{export_macro}} {{type.id}} { +class {{export_macro}} {{type.id}} {% if type.exported %}: public API::{{type.id}} {% endif %}{ + PROTOCOL_DISALLOW_COPY({{type.id}}); public: static std::unique_ptr<{{type.id}}> parse(protocol::Value* value, ErrorSupport* errors); @@ -103,6 +109,9 @@ public: std::unique_ptr serialize() const; std::unique_ptr<{{type.id}}> clone() const; + {% if type.exported %} + String16 toJSONString() const override; + {% endif %} template class {{type.id}}Builder { @@ -205,16 +214,21 @@ public: ) = 0; }; {% endif %} - virtual void {{command.name}}(ErrorString* + virtual void {{command.name}}( + {%- if not("async" in command) -%} + ErrorString* + {%- endif -%} {%- for parameter in command.parameters -%} + {%- if (not loop.first) or not("async" in command) -%}, {% endif -%} {%- if "optional" in parameter -%} - , const Maybe<{{resolve_type(parameter).raw_type}}>& in_{{parameter.name}} + const Maybe<{{resolve_type(parameter).raw_type}}>& in_{{parameter.name}} {%- else -%} - , {{resolve_type(parameter).pass_type}} in_{{parameter.name}} + {{resolve_type(parameter).pass_type}} in_{{parameter.name}} {%- endif -%} {%- endfor -%} {%- if "async" in command -%} - , std::unique_ptr<{{command.name | to_title_case}}Callback> callback + {%- if command.parameters -%}, {% endif -%} + std::unique_ptr<{{command.name | to_title_case}}Callback> callback {%- else -%} {%- for parameter in command.returns -%} {%- if "optional" in parameter -%} @@ -276,6 +290,7 @@ public: using FrontendClass = Frontend; using DispatcherClass = Dispatcher; static const char domainName[]; + static const char commandPrefix[]; }; } // namespace {{domain.domain}} diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/ValueConversions.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/ValueConversions.cpp deleted file mode 100644 index 98b8e7f5dff..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/ValueConversions.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "platform/inspector_protocol/ValueConversions.h" - -namespace blink { -namespace protocol { - -std::unique_ptr toValue(int value) -{ - return FundamentalValue::create(value); -} - -std::unique_ptr toValue(double value) -{ - return FundamentalValue::create(value); -} - -std::unique_ptr toValue(bool value) -{ - return FundamentalValue::create(value); -} - -std::unique_ptr toValue(const String16& param) -{ - return StringValue::create(param); -} - -std::unique_ptr toValue(const String& param) -{ - return StringValue::create(param); -} - -std::unique_ptr toValue(Value* param) -{ - return param->clone(); -} - -std::unique_ptr toValue(DictionaryValue* param) -{ - return param->clone(); -} - -std::unique_ptr toValue(ListValue* param) -{ - return param->clone(); -} - -} // namespace protocol -} // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/ValueConversions.h b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/ValueConversions.h index dd7b2e78641..ba1d08047aa 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/ValueConversions.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/ValueConversions.h @@ -13,42 +13,26 @@ namespace blink { namespace protocol { -PLATFORM_EXPORT std::unique_ptr toValue(int value); - -PLATFORM_EXPORT std::unique_ptr toValue(double value); - -PLATFORM_EXPORT std::unique_ptr toValue(bool value); - -PLATFORM_EXPORT std::unique_ptr toValue(const String16& param); - -PLATFORM_EXPORT std::unique_ptr toValue(const String& param); - -PLATFORM_EXPORT std::unique_ptr toValue(protocol::Value* param); - -PLATFORM_EXPORT std::unique_ptr toValue(protocol::DictionaryValue* param); - -PLATFORM_EXPORT std::unique_ptr toValue(protocol::ListValue* param); - -template std::unique_ptr toValue(T* param) -{ - return param->serialize(); -} - -template std::unique_ptr toValue(const std::unique_ptr& param) -{ - return toValue(param.get()); -} - template -struct FromValue { +struct ValueConversions { static std::unique_ptr parse(protocol::Value* value, ErrorSupport* errors) { return T::parse(value, errors); } + + static std::unique_ptr serialize(T* value) + { + return value->serialize(); + } + + static std::unique_ptr serialize(const std::unique_ptr& value) + { + return value->serialize(); + } }; template<> -struct FromValue { +struct ValueConversions { static bool parse(protocol::Value* value, ErrorSupport* errors) { bool result = false; @@ -57,10 +41,15 @@ struct FromValue { errors->addError("boolean value expected"); return result; } + + static std::unique_ptr serialize(bool value) + { + return FundamentalValue::create(value); + } }; template<> -struct FromValue { +struct ValueConversions { static int parse(protocol::Value* value, ErrorSupport* errors) { int result = 0; @@ -69,10 +58,15 @@ struct FromValue { errors->addError("integer value expected"); return result; } + + static std::unique_ptr serialize(int value) + { + return FundamentalValue::create(value); + } }; template<> -struct FromValue { +struct ValueConversions { static double parse(protocol::Value* value, ErrorSupport* errors) { double result = 0; @@ -81,10 +75,15 @@ struct FromValue { errors->addError("double value expected"); return result; } + + static std::unique_ptr serialize(double value) + { + return FundamentalValue::create(value); + } }; template<> -struct FromValue { +struct ValueConversions { static String parse(protocol::Value* value, ErrorSupport* errors) { String16 result; @@ -93,10 +92,15 @@ struct FromValue { errors->addError("string value expected"); return result; } + + static std::unique_ptr serialize(const String& value) + { + return StringValue::create(value); + } }; template<> -struct FromValue { +struct ValueConversions { static String16 parse(protocol::Value* value, ErrorSupport* errors) { String16 result; @@ -105,10 +109,15 @@ struct FromValue { errors->addError("string value expected"); return result; } + + static std::unique_ptr serialize(const String16& value) + { + return StringValue::create(value); + } }; template<> -struct FromValue { +struct ValueConversions { static std::unique_ptr parse(protocol::Value* value, ErrorSupport* errors) { bool success = !!value; @@ -118,10 +127,20 @@ struct FromValue { } return value->clone(); } + + static std::unique_ptr serialize(Value* value) + { + return value->clone(); + } + + static std::unique_ptr serialize(const std::unique_ptr& value) + { + return value->clone(); + } }; template<> -struct FromValue { +struct ValueConversions { static std::unique_ptr parse(protocol::Value* value, ErrorSupport* errors) { bool success = value && value->type() == protocol::Value::TypeObject; @@ -129,10 +148,20 @@ struct FromValue { errors->addError("object expected"); return DictionaryValue::cast(value->clone()); } + + static std::unique_ptr serialize(DictionaryValue* value) + { + return value->clone(); + } + + static std::unique_ptr serialize(const std::unique_ptr& value) + { + return value->clone(); + } }; template<> -struct FromValue { +struct ValueConversions { static std::unique_ptr parse(protocol::Value* value, ErrorSupport* errors) { bool success = value && value->type() == protocol::Value::TypeArray; @@ -140,15 +169,15 @@ struct FromValue { errors->addError("list expected"); return ListValue::cast(value->clone()); } -}; -template class Array; + static std::unique_ptr serialize(ListValue* value) + { + return value->clone(); + } -template -struct FromValue> { - static std::unique_ptr> parse(protocol::Value* value, ErrorSupport* errors) + static std::unique_ptr serialize(const std::unique_ptr& value) { - return protocol::Array::parse(value, errors); + return value->clone(); } }; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.cpp index 7d4ec242ae4..5b8f13b4930 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.cpp @@ -92,6 +92,11 @@ bool Value::asString(String16*) const return false; } +bool Value::asSerialized(String16*) const +{ + return false; +} + String16 Value::toJSONString() const { String16Builder result; @@ -188,6 +193,23 @@ std::unique_ptr StringValue::clone() const return StringValue::create(m_stringValue); } +bool SerializedValue::asSerialized(String16* output) const +{ + *output = m_serializedValue; + return true; +} + +void SerializedValue::writeJSON(String16Builder* output) const +{ + DCHECK(type() == TypeSerialized); + output->append(m_serializedValue); +} + +std::unique_ptr SerializedValue::clone() const +{ + return SerializedValue::create(m_serializedValue); +} + DictionaryValue::~DictionaryValue() { } diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.h b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.h index 07a2cac9249..48a2012758a 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/Values.h @@ -38,7 +38,8 @@ class PLATFORM_EXPORT Value { TypeDouble, TypeString, TypeObject, - TypeArray + TypeArray, + TypeSerialized }; ValueType type() const { return m_type; } @@ -49,6 +50,7 @@ class PLATFORM_EXPORT Value { virtual bool asDouble(double* output) const; virtual bool asInteger(int* output) const; virtual bool asString(String16* output) const; + virtual bool asSerialized(String16* output) const; String16 toJSONString() const; virtual void writeJSON(String16Builder* output) const; @@ -123,6 +125,24 @@ class PLATFORM_EXPORT StringValue : public Value { String16 m_stringValue; }; +class PLATFORM_EXPORT SerializedValue : public Value { +public: + static std::unique_ptr create(const String16& value) + { + return wrapUnique(new SerializedValue(value)); + } + + bool asSerialized(String16* output) const override; + void writeJSON(String16Builder* output) const override; + std::unique_ptr clone() const override; + +private: + explicit SerializedValue(const String16& value) : Value(TypeSerialized), m_serializedValue(value) { } + explicit SerializedValue(const char* value) : Value(TypeSerialized), m_serializedValue(value) { } + + String16 m_serializedValue; +}; + class PLATFORM_EXPORT DictionaryValue : public Value { public: using Entry = std::pair; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/generate-inspector-protocol-version b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/generate-inspector-protocol-version index 838a3ed2dd8..0c01e163bbd 100755 --- a/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/generate-inspector-protocol-version +++ b/deps/v8_inspector/third_party/v8_inspector/platform/inspector_protocol/generate-inspector-protocol-version @@ -60,7 +60,7 @@ except ImportError: def list_to_map(items, key): result = {} for item in items: - if not "hidden" in item: + if not "experimental" in item and not "hidden" in item: result[item[key]] = item return result @@ -287,7 +287,7 @@ def self_test(): { "name": "requestWillBeSent", "parameters": [ - { "name": "frameId", "type": "string", "hidden": True }, + { "name": "frameId", "type": "string", "experimental": True }, { "name": "request", "$ref": "Request" }, { "name": "becameOptional", "type": "string" }, { "name": "removedRequired", "type": "string" }, @@ -451,7 +451,8 @@ def main(): load_domains_and_baselines(arg_values[1], domains, baseline_domains) expected_errors = [ - "Debugger.globalObjectCleared: event has been removed" + "Debugger.globalObjectCleared: event has been removed", + "Runtime.executionContextCreated.context parameter->Runtime.ExecutionContextDescription.frameId: required property has been removed" ] errors = compare_schemas(baseline_domains, domains, False) diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/DebuggerScript.js b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/DebuggerScript.js index 5b534f32216..cd9a2bd56dd 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/DebuggerScript.js +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/DebuggerScript.js @@ -141,14 +141,22 @@ DebuggerScript._executionContextId = function(contextData) { if (!contextData) return 0; - var firstComma = contextData.indexOf(","); - if (firstComma === -1) - return 0; - var secondComma = contextData.indexOf(",", firstComma + 1); - if (secondComma === -1) + var match = contextData.match(/^[^,]*,([^,]*),.*$/); + if (!match) return 0; + return parseInt(match[1], 10) || 0; +} - return parseInt(contextData.substring(firstComma + 1, secondComma), 10) || 0; +/** + * @param {string|undefined} contextData + * @return {string} + */ +DebuggerScript._executionContextAuxData = function(contextData) +{ + if (!contextData) + return ""; + var match = contextData.match(/^[^,]*,[^,]*,(.*)$/); + return match ? match[1] : ""; } /** @@ -168,7 +176,7 @@ DebuggerScript.getScripts = function(contextGroupId) if (!script.context_data) continue; // Context data is a string in the following format: - // ,,("default"|"nondefault") + // ,, if (script.context_data.indexOf(contextDataPrefix) !== 0) continue; } @@ -208,7 +216,8 @@ DebuggerScript._formatScript = function(script) endLine: endLine, endColumn: endColumn, executionContextId: DebuggerScript._executionContextId(script.context_data), - isContentScript: !!script.context_data && script.context_data.endsWith(",nondefault"), + // Note that we cannot derive aux data from context id because of compilation cache. + executionContextAuxData: DebuggerScript._executionContextAuxData(script.context_data), isInternalScript: script.is_debugger_script }; } diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.cpp index 302b635ed47..3b4552ee8d9 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.cpp @@ -39,14 +39,13 @@ #include "platform/v8_inspector/RemoteObjectId.h" #include "platform/v8_inspector/V8Compat.h" #include "platform/v8_inspector/V8Console.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" #include "platform/v8_inspector/V8FunctionCall.h" #include "platform/v8_inspector/V8InjectedScriptHost.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8Debugger.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" using blink::protocol::Array; using blink::protocol::Debugger::CallFrame; @@ -72,7 +71,7 @@ std::unique_ptr InjectedScript::create(InspectedContext* inspect v8::Context::Scope scope(context); std::unique_ptr injectedScriptNative(new InjectedScriptNative(isolate)); - v8::Local scriptHostWrapper = V8InjectedScriptHost::create(context, inspectedContext->debugger()); + v8::Local scriptHostWrapper = V8InjectedScriptHost::create(context, inspectedContext->inspector()); injectedScriptNative->setOnInjectedScriptHost(scriptHostWrapper); // Inject javascript into the context. The compiled script is supposed to evaluate into @@ -82,7 +81,7 @@ std::unique_ptr InjectedScript::create(InspectedContext* inspect // to create and configure InjectedScript instance that is going to be used by the inspector. String16 injectedScriptSource(reinterpret_cast(InjectedScriptSource_js), sizeof(InjectedScriptSource_js)); v8::Local value; - if (!inspectedContext->debugger()->compileAndRunInternalScript(context, toV8String(isolate, injectedScriptSource)).ToLocal(&value)) + if (!inspectedContext->inspector()->compileAndRunInternalScript(context, toV8String(isolate, injectedScriptSource)).ToLocal(&value)) return nullptr; DCHECK(value->IsFunction()); v8::Local function = v8::Local::Cast(value); @@ -111,7 +110,7 @@ InjectedScript::~InjectedScript() void InjectedScript::getProperties(ErrorString* errorString, v8::Local object, const String16& groupName, bool ownProperties, bool accessorPropertiesOnly, bool generatePreview, std::unique_ptr>* properties, Maybe* exceptionDetails) { v8::HandleScope handles(m_context->isolate()); - V8FunctionCall function(m_context->debugger(), m_context->context(), v8Value(), "getProperties"); + V8FunctionCall function(m_context->inspector(), m_context->context(), v8Value(), "getProperties"); function.appendArgument(object); function.appendArgument(groupName); function.appendArgument(ownProperties); @@ -127,7 +126,7 @@ void InjectedScript::getProperties(ErrorString* errorString, v8::Local protocolValue = toProtocolValue(function.context(), resultValue); + std::unique_ptr protocolValue = toProtocolValue(m_context->context(), resultValue); if (hasInternalError(errorString, !protocolValue)) return; protocol::ErrorSupport errors(errorString); @@ -179,7 +178,7 @@ bool InjectedScript::wrapObjectProperty(ErrorString* errorString, v8::Local array, v8::Local property, const String16& groupName, bool forceValueType, bool generatePreview) const { - V8FunctionCall function(m_context->debugger(), m_context->context(), v8Value(), "wrapPropertyInArray"); + V8FunctionCall function(m_context->inspector(), m_context->context(), v8Value(), "wrapPropertyInArray"); function.appendArgument(array); function.appendArgument(property); function.appendArgument(groupName); @@ -192,7 +191,7 @@ bool InjectedScript::wrapPropertyInArray(ErrorString* errorString, v8::Local array, const String16& groupName, bool forceValueType, bool generatePreview) const { - V8FunctionCall function(m_context->debugger(), m_context->context(), v8Value(), "wrapObjectsInArray"); + V8FunctionCall function(m_context->inspector(), m_context->context(), v8Value(), "wrapObjectsInArray"); function.appendArgument(array); function.appendArgument(groupName); function.appendArgument(forceValueType); @@ -204,7 +203,7 @@ bool InjectedScript::wrapObjectsInArray(ErrorString* errorString, v8::Local InjectedScript::wrapValue(ErrorString* errorString, v8::Local value, const String16& groupName, bool forceValueType, bool generatePreview) const { - V8FunctionCall function(m_context->debugger(), m_context->context(), v8Value(), "wrapObject"); + V8FunctionCall function(m_context->inspector(), m_context->context(), v8Value(), "wrapObject"); function.appendArgument(value); function.appendArgument(groupName); function.appendArgument(forceValueType); @@ -219,7 +218,7 @@ v8::MaybeLocal InjectedScript::wrapValue(ErrorString* errorString, v8 std::unique_ptr InjectedScript::wrapTable(v8::Local table, v8::Local columns) const { v8::HandleScope handles(m_context->isolate()); - V8FunctionCall function(m_context->debugger(), m_context->context(), v8Value(), "wrapTable"); + V8FunctionCall function(m_context->inspector(), m_context->context(), v8Value(), "wrapTable"); function.appendArgument(table); if (columns.IsEmpty()) function.appendArgument(false); @@ -256,7 +255,7 @@ void InjectedScript::releaseObjectGroup(const String16& objectGroup) void InjectedScript::setCustomObjectFormatterEnabled(bool enabled) { v8::HandleScope handles(m_context->isolate()); - V8FunctionCall function(m_context->debugger(), m_context->context(), v8Value(), "setCustomObjectFormatterEnabled"); + V8FunctionCall function(m_context->inspector(), m_context->context(), v8Value(), "setCustomObjectFormatterEnabled"); function.appendArgument(enabled); bool hadException = false; function.call(hadException); @@ -290,12 +289,12 @@ v8::MaybeLocal InjectedScript::resolveCallArgument(ErrorString* error return v8::MaybeLocal(); return object; } - if (callArgument->hasValue()) { - String16 value = callArgument->getValue(nullptr)->toJSONString(); - if (callArgument->getType(String16()) == "number") - value = "Number(" + value + ")"; + if (callArgument->hasValue() || callArgument->hasUnserializableValue()) { + String16 value = callArgument->hasValue() ? + callArgument->getValue(nullptr)->toJSONString() : + "Number(\"" + callArgument->getUnserializableValue("") + "\")"; v8::Local object; - if (!m_context->debugger()->compileAndRunInternalScript(m_context->context(), toV8String(m_context->isolate(), value)).ToLocal(&object)) { + if (!m_context->inspector()->compileAndRunInternalScript(m_context->context(), toV8String(m_context->isolate(), value)).ToLocal(&object)) { *errorString = "Couldn't parse value object in call argument"; return v8::MaybeLocal(); } @@ -315,7 +314,7 @@ std::unique_ptr InjectedScript::createExcep v8::Local stackTrace = message->GetStackTrace(); if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0) - exceptionDetailsObject->setStackTrace(m_context->debugger()->createStackTrace(stackTrace)->buildInspectorObject()); + exceptionDetailsObject->setStackTrace(m_context->inspector()->debugger()->createStackTrace(stackTrace)->buildInspectorObjectImpl()); return exceptionDetailsObject; } @@ -353,15 +352,15 @@ v8::Local InjectedScript::commandLineAPI() return m_commandLineAPI.Get(m_context->isolate()); } -InjectedScript::Scope::Scope(ErrorString* errorString, V8DebuggerImpl* debugger, int contextGroupId) +InjectedScript::Scope::Scope(ErrorString* errorString, V8InspectorImpl* inspector, int contextGroupId) : m_errorString(errorString) - , m_debugger(debugger) + , m_inspector(inspector) , m_contextGroupId(contextGroupId) , m_injectedScript(nullptr) - , m_handleScope(debugger->isolate()) - , m_tryCatch(debugger->isolate()) + , m_handleScope(inspector->isolate()) + , m_tryCatch(inspector->isolate()) , m_ignoreExceptionsAndMuteConsole(false) - , m_previousPauseOnExceptionsState(V8DebuggerImpl::DontPauseOnExceptions) + , m_previousPauseOnExceptionsState(V8Debugger::DontPauseOnExceptions) , m_userGesture(false) { } @@ -370,7 +369,7 @@ bool InjectedScript::Scope::initialize() { cleanup(); // TODO(dgozman): what if we reattach to the same context group during evaluate? Introduce a session id? - V8InspectorSessionImpl* session = m_debugger->sessionForContextGroup(m_contextGroupId); + V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup(m_contextGroupId); if (!session) { *m_errorString = "Internal error"; return false; @@ -394,17 +393,18 @@ void InjectedScript::Scope::ignoreExceptionsAndMuteConsole() { DCHECK(!m_ignoreExceptionsAndMuteConsole); m_ignoreExceptionsAndMuteConsole = true; - m_debugger->client()->muteWarningsAndDeprecations(m_contextGroupId); - m_previousPauseOnExceptionsState = setPauseOnExceptionsState(V8DebuggerImpl::DontPauseOnExceptions); + m_inspector->client()->muteMetrics(m_contextGroupId); + m_inspector->muteExceptions(m_contextGroupId); + m_previousPauseOnExceptionsState = setPauseOnExceptionsState(V8Debugger::DontPauseOnExceptions); } -V8DebuggerImpl::PauseOnExceptionsState InjectedScript::Scope::setPauseOnExceptionsState(V8DebuggerImpl::PauseOnExceptionsState newState) +V8Debugger::PauseOnExceptionsState InjectedScript::Scope::setPauseOnExceptionsState(V8Debugger::PauseOnExceptionsState newState) { - if (!m_debugger->enabled()) + if (!m_inspector->debugger()->enabled()) return newState; - V8DebuggerImpl::PauseOnExceptionsState presentState = m_debugger->getPauseOnExceptionsState(); + V8Debugger::PauseOnExceptionsState presentState = m_inspector->debugger()->getPauseOnExceptionsState(); if (presentState != newState) - m_debugger->setPauseOnExceptionsState(newState); + m_inspector->debugger()->setPauseOnExceptionsState(newState); return presentState; } @@ -412,7 +412,7 @@ void InjectedScript::Scope::pretendUserGesture() { DCHECK(!m_userGesture); m_userGesture = true; - m_debugger->client()->beginUserGesture(); + m_inspector->client()->beginUserGesture(); } void InjectedScript::Scope::cleanup() @@ -428,15 +428,16 @@ InjectedScript::Scope::~Scope() { if (m_ignoreExceptionsAndMuteConsole) { setPauseOnExceptionsState(m_previousPauseOnExceptionsState); - m_debugger->client()->unmuteWarningsAndDeprecations(m_contextGroupId); + m_inspector->client()->unmuteMetrics(m_contextGroupId); + m_inspector->unmuteExceptions(m_contextGroupId); } if (m_userGesture) - m_debugger->client()->endUserGesture(); + m_inspector->client()->endUserGesture(); cleanup(); } -InjectedScript::ContextScope::ContextScope(ErrorString* errorString, V8DebuggerImpl* debugger, int contextGroupId, int executionContextId) - : InjectedScript::Scope(errorString, debugger, contextGroupId) +InjectedScript::ContextScope::ContextScope(ErrorString* errorString, V8InspectorImpl* inspector, int contextGroupId, int executionContextId) + : InjectedScript::Scope(errorString, inspector, contextGroupId) , m_executionContextId(executionContextId) { } @@ -450,8 +451,8 @@ void InjectedScript::ContextScope::findInjectedScript(V8InspectorSessionImpl* se m_injectedScript = session->findInjectedScript(m_errorString, m_executionContextId); } -InjectedScript::ObjectScope::ObjectScope(ErrorString* errorString, V8DebuggerImpl* debugger, int contextGroupId, const String16& remoteObjectId) - : InjectedScript::Scope(errorString, debugger, contextGroupId) +InjectedScript::ObjectScope::ObjectScope(ErrorString* errorString, V8InspectorImpl* inspector, int contextGroupId, const String16& remoteObjectId) + : InjectedScript::Scope(errorString, inspector, contextGroupId) , m_remoteObjectId(remoteObjectId) { } @@ -474,8 +475,8 @@ void InjectedScript::ObjectScope::findInjectedScript(V8InspectorSessionImpl* ses m_injectedScript = injectedScript; } -InjectedScript::CallFrameScope::CallFrameScope(ErrorString* errorString, V8DebuggerImpl* debugger, int contextGroupId, const String16& remoteObjectId) - : InjectedScript::Scope(errorString, debugger, contextGroupId) +InjectedScript::CallFrameScope::CallFrameScope(ErrorString* errorString, V8InspectorImpl* inspector, int contextGroupId, const String16& remoteObjectId) + : InjectedScript::Scope(errorString, inspector, contextGroupId) , m_remoteCallFrameId(remoteObjectId) { } diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.h index ab847ee0412..b65a857eb90 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScript.h @@ -36,7 +36,7 @@ #include "platform/v8_inspector/InjectedScriptNative.h" #include "platform/v8_inspector/InspectedContext.h" #include "platform/v8_inspector/V8Console.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8Debugger.h" #include "platform/v8_inspector/protocol/Runtime.h" #include @@ -45,6 +45,7 @@ namespace blink { class RemoteObjectId; class V8FunctionCall; +class V8InspectorImpl; class V8InspectorSessionImpl; namespace protocol { @@ -99,32 +100,32 @@ class InjectedScript final { const v8::TryCatch& tryCatch() const { return m_tryCatch; } protected: - Scope(ErrorString*, V8DebuggerImpl*, int contextGroupId); + Scope(ErrorString*, V8InspectorImpl*, int contextGroupId); ~Scope(); virtual void findInjectedScript(V8InspectorSessionImpl*) = 0; ErrorString* m_errorString; - V8DebuggerImpl* m_debugger; + V8InspectorImpl* m_inspector; int m_contextGroupId; InjectedScript* m_injectedScript; private: void cleanup(); - V8DebuggerImpl::PauseOnExceptionsState setPauseOnExceptionsState(V8DebuggerImpl::PauseOnExceptionsState); + V8Debugger::PauseOnExceptionsState setPauseOnExceptionsState(V8Debugger::PauseOnExceptionsState); v8::HandleScope m_handleScope; v8::TryCatch m_tryCatch; v8::Local m_context; std::unique_ptr m_commandLineAPIScope; bool m_ignoreExceptionsAndMuteConsole; - V8DebuggerImpl::PauseOnExceptionsState m_previousPauseOnExceptionsState; + V8Debugger::PauseOnExceptionsState m_previousPauseOnExceptionsState; bool m_userGesture; }; class ContextScope: public Scope { PROTOCOL_DISALLOW_COPY(ContextScope); public: - ContextScope(ErrorString*, V8DebuggerImpl*, int contextGroupId, int executionContextId); + ContextScope(ErrorString*, V8InspectorImpl*, int contextGroupId, int executionContextId); ~ContextScope(); private: void findInjectedScript(V8InspectorSessionImpl*) override; @@ -134,7 +135,7 @@ class InjectedScript final { class ObjectScope: public Scope { PROTOCOL_DISALLOW_COPY(ObjectScope); public: - ObjectScope(ErrorString*, V8DebuggerImpl*, int contextGroupId, const String16& remoteObjectId); + ObjectScope(ErrorString*, V8InspectorImpl*, int contextGroupId, const String16& remoteObjectId); ~ObjectScope(); const String16& objectGroupName() const { return m_objectGroupName; } v8::Local object() const { return m_object; } @@ -148,7 +149,7 @@ class InjectedScript final { class CallFrameScope: public Scope { PROTOCOL_DISALLOW_COPY(CallFrameScope); public: - CallFrameScope(ErrorString*, V8DebuggerImpl*, int contextGroupId, const String16& remoteCallFrameId); + CallFrameScope(ErrorString*, V8InspectorImpl*, int contextGroupId, const String16& remoteCallFrameId); ~CallFrameScope(); size_t frameOrdinal() const { return m_frameOrdinal; } private: diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScriptSource.js b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScriptSource.js index d2b3b2725ee..7e8b2cb41ba 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScriptSource.js +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InjectedScriptSource.js @@ -60,7 +60,7 @@ function push(array, var_args) */ function toString(obj) { - // We don't use String(obj) because String16 could be overridden. + // We don't use String(obj) because String could be overridden. // Also the ("" + obj) expression may throw. try { return "" + obj; @@ -115,7 +115,7 @@ function isArrayLike(obj) return false; try { if (typeof obj.splice === "function") { - if (!InjectedScriptHost.suppressWarningsAndCallFunction(Object.prototype.hasOwnProperty, obj, ["length"])) + if (!InjectedScriptHost.objectHasOwnProperty(/** @type {!Object} */ (obj), "length")) return false; var len = obj.length; return typeof len === "number" && isUInt32(len); @@ -170,12 +170,11 @@ domAttributesWithObservableSideEffectOnGet["Response"]["body"] = true; function doesAttributeHaveObservableSideEffectOnGet(object, attribute) { for (var interfaceName in domAttributesWithObservableSideEffectOnGet) { - var isInstance = InjectedScriptHost.suppressWarningsAndCallFunction(function(object, interfaceName) { - return /* suppressBlacklist */ typeof inspectedGlobalObject[interfaceName] === "function" && object instanceof inspectedGlobalObject[interfaceName]; - }, null, [object, interfaceName]); - if (isInstance) { + var interfaceFunction = inspectedGlobalObject[interfaceName]; + // instanceof call looks safe after typeof check. + var isInstance = typeof interfaceFunction === "function" && /* suppressBlacklist */ object instanceof interfaceFunction; + if (isInstance) return attribute in domAttributesWithObservableSideEffectOnGet[interfaceName]; - } } return false; } @@ -200,18 +199,17 @@ InjectedScript.primitiveTypes = { } /** - * @type {!Map} + * @type {!Object} * @const */ -InjectedScript.closureTypes = new Map([ - ["local", "Local"], - ["closure", "Closure"], - ["catch", "Catch"], - ["block", "Block"], - ["script", "Script"], - ["with", "With Block"], - ["global", "Global"] -]); +InjectedScript.closureTypes = { __proto__: null }; +InjectedScript.closureTypes["local"] = "Local"; +InjectedScript.closureTypes["closure"] = "Closure"; +InjectedScript.closureTypes["catch"] = "Catch"; +InjectedScript.closureTypes["block"] = "Block"; +InjectedScript.closureTypes["script"] = "Script"; +InjectedScript.closureTypes["with"] = "With Block"; +InjectedScript.closureTypes["global"] = "Global"; InjectedScript.prototype = { /** @@ -369,6 +367,21 @@ InjectedScript.prototype = { return descriptors; }, + /** + * @param {!Object} object + * @return {?Object} + */ + _objectPrototype: function(object) + { + if (InjectedScriptHost.subtype(object) === "proxy") + return null; + try { + return Object.getPrototypeOf(object); + } catch (e) { + return null; + } + }, + /** * @param {!Object} object * @param {boolean=} ownProperties @@ -397,12 +410,12 @@ InjectedScript.prototype = { try { propertyProcessed[property] = true; - var descriptor = nullifyObjectProto(InjectedScriptHost.suppressWarningsAndCallFunction(Object.getOwnPropertyDescriptor, Object, [o, property])); + var descriptor = nullifyObjectProto(Object.getOwnPropertyDescriptor(o, property)); if (descriptor) { if (accessorPropertiesOnly && !("get" in descriptor || "set" in descriptor)) continue; if ("get" in descriptor && "set" in descriptor && name != "__proto__" && InjectedScriptHost.formatAccessorsAsProperties(object, descriptor.get) && !doesAttributeHaveObservableSideEffectOnGet(object, name)) { - descriptor.value = InjectedScriptHost.suppressWarningsAndCallFunction(function(attribute) { return this[attribute]; }, object, [property]); + descriptor.value = object[property]; descriptor.isOwn = true; delete descriptor.get; delete descriptor.set; @@ -441,8 +454,8 @@ InjectedScript.prototype = { if (propertyNamesOnly) { for (var i = 0; i < propertyNamesOnly.length; ++i) { var name = propertyNamesOnly[i]; - for (var o = object; this._isDefined(o); o = InjectedScriptHost.prototype(o)) { - if (InjectedScriptHost.suppressWarningsAndCallFunction(Object.prototype.hasOwnProperty, o, [name])) { + for (var o = object; this._isDefined(o); o = this._objectPrototype(o)) { + if (InjectedScriptHost.objectHasOwnProperty(o, name)) { for (var descriptor of process(o, [name])) yield descriptor; break; @@ -465,11 +478,11 @@ InjectedScript.prototype = { var skipGetOwnPropertyNames; try { - skipGetOwnPropertyNames = InjectedScriptHost.isTypedArray(object) && object.length > 500000; + skipGetOwnPropertyNames = InjectedScriptHost.subtype(object) === "typedarray" && object.length > 500000; } catch (e) { } - for (var o = object; this._isDefined(o); o = InjectedScriptHost.prototype(o)) { + for (var o = object; this._isDefined(o); o = this._objectPrototype(o)) { if (InjectedScriptHost.subtype(o) === "proxy") continue; if (skipGetOwnPropertyNames && o === object) { @@ -488,7 +501,7 @@ InjectedScript.prototype = { yield descriptor; } if (ownProperties) { - var proto = InjectedScriptHost.prototype(o); + var proto = this._objectPrototype(o); if (proto && !accessorPropertiesOnly) yield { name: "__proto__", value: proto, writable: true, configurable: true, enumerable: false, isOwn: true, __proto__: null }; break; @@ -613,7 +626,7 @@ InjectedScript.prototype = { return "Proxy"; var className = InjectedScriptHost.internalConstructorName(obj); - if (subtype === "array") { + if (subtype === "array" || subtype === "typedarray") { if (typeof obj.length === "number") className += "[" + obj.length + "]"; return className; @@ -624,7 +637,8 @@ InjectedScript.prototype = { if (isSymbol(obj)) { try { - return /** @type {string} */ (InjectedScriptHost.suppressWarningsAndCallFunction(Symbol.prototype.toString, obj)) || "Symbol"; + // It isn't safe, because Symbol.prototype.toString can be overriden. + return /* suppressBlacklist */ obj.toString() || "Symbol"; } catch (e) { return "Symbol"; } @@ -655,7 +669,7 @@ InjectedScript.prototype = { return "Scopes[" + obj.length + "]"; if (subtype === "internal#scope") - return (InjectedScript.closureTypes.get(obj.type) || "Unknown") + (obj.name ? " (" + obj.name + ")" : ""); + return (InjectedScript.closureTypes[obj.type] || "Unknown") + (obj.name ? " (" + obj.name + ")" : ""); return className; }, @@ -718,13 +732,13 @@ InjectedScript.RemoteObject = function(object, objectGroupName, doNotBind, force // Provide user-friendly number values. if (this.type === "number") { this.description = toStringDescription(object); - // Override "value" property for values that can not be JSON-stringified. switch (this.description) { case "NaN": case "Infinity": case "-Infinity": case "-0": - this.value = this.description; + delete this.value; + this.unserializableValue = this.description; break; } } @@ -780,7 +794,8 @@ InjectedScript.RemoteObject.prototype = { */ function logError(error) { - Promise.resolve().then(inspectedGlobalObject.console.error.bind(inspectedGlobalObject.console, "Custom Formatter Failed: " + error.message)); + // We use user code to generate custom output for object, we can use user code for reporting error too. + Promise.resolve().then(/* suppressBlacklist */ inspectedGlobalObject.console.error.bind(inspectedGlobalObject.console, "Custom Formatter Failed: " + error.message)); } /** @@ -791,7 +806,7 @@ InjectedScript.RemoteObject.prototype = { */ function wrap(object, customObjectConfig) { - return InjectedScriptHost.suppressWarningsAndCallFunction(injectedScript._wrapObject, injectedScript, [ object, objectGroupName, false, false, null, false, false, customObjectConfig ]); + return injectedScript._wrapObject(object, objectGroupName, false, false, null, false, false, customObjectConfig); } try { @@ -915,7 +930,7 @@ InjectedScript.RemoteObject.prototype = { continue; // Ignore length property of array. - if (this.subtype === "array" && name === "length") + if ((this.subtype === "array" || this.subtype === "typedarray") && name === "length") continue; // Ignore size property of map, set. diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.cpp index 5b52e015a54..16e0f027322 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.cpp @@ -6,10 +6,10 @@ #include "platform/v8_inspector/InjectedScript.h" #include "platform/v8_inspector/V8Console.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8StringUtil.h" #include "platform/v8_inspector/public/V8ContextInfo.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" namespace blink { @@ -20,7 +20,7 @@ void InspectedContext::weakCallback(const v8::WeakCallbackInfo context->m_context.Reset(); data.SetSecondPassCallback(&InspectedContext::weakCallback); } else { - context->m_debugger->discardInspectedContext(context->m_contextGroupId, context->m_contextId); + context->m_inspector->discardInspectedContext(context->m_contextGroupId, context->m_contextId); } } @@ -29,20 +29,19 @@ void InspectedContext::consoleWeakCallback(const v8::WeakCallbackInfom_console.Reset(); } -InspectedContext::InspectedContext(V8DebuggerImpl* debugger, const V8ContextInfo& info, int contextId) - : m_debugger(debugger) +InspectedContext::InspectedContext(V8InspectorImpl* inspector, const V8ContextInfo& info, int contextId) + : m_inspector(inspector) , m_context(info.context->GetIsolate(), info.context) , m_contextId(contextId) , m_contextGroupId(info.contextGroupId) - , m_isDefault(info.isDefault) , m_origin(info.origin) , m_humanReadableName(info.humanReadableName) - , m_frameId(info.frameId) + , m_auxData(info.auxData) , m_reported(false) { m_context.SetWeak(this, &InspectedContext::weakCallback, v8::WeakCallbackType::kParameter); - v8::Isolate* isolate = m_debugger->isolate(); + v8::Isolate* isolate = m_inspector->isolate(); v8::Local global = info.context->Global(); v8::Local console = V8Console::createConsole(this, info.hasMemoryOnConsole); if (!global->Set(info.context, toV8StringInternalized(isolate, "console"), console).FromMaybe(false)) @@ -66,17 +65,12 @@ v8::Local InspectedContext::context() const v8::Isolate* InspectedContext::isolate() const { - return m_debugger->isolate(); + return m_inspector->isolate(); } void InspectedContext::createInjectedScript() { DCHECK(!m_injectedScript); - v8::HandleScope handles(isolate()); - v8::Local localContext = context(); - v8::Local callingContext = isolate()->GetCallingContext(); - if (!callingContext.IsEmpty() && !m_debugger->client()->callingContextCanAccessContext(callingContext, localContext)) - return; m_injectedScript = InjectedScript::create(this); } diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.h index ecff5e4012f..421d3dfe03a 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/InspectedContext.h @@ -15,7 +15,7 @@ namespace blink { class InjectedScript; class InjectedScriptHost; class V8ContextInfo; -class V8DebuggerImpl; +class V8InspectorImpl; class InspectedContext { PROTOCOL_DISALLOW_COPY(InspectedContext); @@ -25,35 +25,33 @@ class InspectedContext { v8::Local context() const; int contextId() const { return m_contextId; } int contextGroupId() const { return m_contextGroupId; } - bool isDefault() const { return m_isDefault; } String16 origin() const { return m_origin; } String16 humanReadableName() const { return m_humanReadableName; } - String16 frameId() const { return m_frameId; } + String16 auxData() const { return m_auxData; } bool isReported() const { return m_reported; } void setReported(bool reported) { m_reported = reported; } v8::Isolate* isolate() const; - V8DebuggerImpl* debugger() const { return m_debugger; } + V8InspectorImpl* inspector() const { return m_inspector; } InjectedScript* getInjectedScript() { return m_injectedScript.get(); } void createInjectedScript(); void discardInjectedScript(); private: - friend class V8DebuggerImpl; - InspectedContext(V8DebuggerImpl*, const V8ContextInfo&, int contextId); + friend class V8InspectorImpl; + InspectedContext(V8InspectorImpl*, const V8ContextInfo&, int contextId); static void weakCallback(const v8::WeakCallbackInfo&); static void consoleWeakCallback(const v8::WeakCallbackInfo&); - V8DebuggerImpl* m_debugger; + V8InspectorImpl* m_inspector; v8::Global m_context; int m_contextId; int m_contextGroupId; - bool m_isDefault; const String16 m_origin; const String16 m_humanReadableName; - const String16 m_frameId; + const String16 m_auxData; bool m_reported; std::unique_ptr m_injectedScript; v8::Global m_console; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Compat.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Compat.h index 0f5b12cbb6c..d623da1a616 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Compat.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Compat.h @@ -22,7 +22,11 @@ class V8_EXPORT MicrotasksScope { }; } // namespace v8 - +#define V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, data, length) \ + v8::Function::New((context), (callback), (data), (length)) +#else +#define V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, data, length) \ + v8::Function::New((context), (callback), (data), (length), v8::ConstructorBehavior::kThrow) #endif // V8_MAJOR_VERSION < 5 || (V8_MAJOR_VERSION == 5 && V8_MINOR_VERSION < 1) #endif // V8Compat_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Console.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Console.cpp index f7e142deead..1bd738a8660 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Console.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Console.cpp @@ -11,13 +11,13 @@ #include "platform/v8_inspector/V8Compat.h" #include "platform/v8_inspector/V8ConsoleMessage.h" #include "platform/v8_inspector/V8DebuggerAgentImpl.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8ProfilerAgentImpl.h" #include "platform/v8_inspector/V8RuntimeAgentImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" namespace blink { @@ -36,7 +36,7 @@ class ConsoleHelper { , m_isolate(info.GetIsolate()) , m_context(info.GetIsolate()->GetCurrentContext()) , m_inspectedContext(nullptr) - , m_debuggerClient(nullptr) + , m_inspectorClient(nullptr) { } @@ -65,15 +65,15 @@ class ConsoleHelper { return m_inspectedContext; } - V8DebuggerClient* ensureDebuggerClient() + V8InspectorClient* ensureDebuggerClient() { - if (m_debuggerClient) - return m_debuggerClient; + if (m_inspectorClient) + return m_inspectorClient; InspectedContext* inspectedContext = ensureInspectedContext(); if (!inspectedContext) return nullptr; - m_debuggerClient = inspectedContext->debugger()->client(); - return m_debuggerClient; + m_inspectorClient = inspectedContext->inspector()->client(); + return m_inspectorClient; } void reportCall(ConsoleAPIType type) @@ -107,9 +107,9 @@ class ConsoleHelper { InspectedContext* inspectedContext = ensureInspectedContext(); if (!inspectedContext) return; - V8DebuggerImpl* debugger = inspectedContext->debugger(); - std::unique_ptr message = V8ConsoleMessage::createForConsoleAPI(debugger->client()->currentTimeMS(), type, arguments, debugger->captureStackTrace(false), inspectedContext); - debugger->ensureConsoleMessageStorage(inspectedContext->contextGroupId())->addMessage(std::move(message)); + V8InspectorImpl* inspector = inspectedContext->inspector(); + std::unique_ptr message = V8ConsoleMessage::createForConsoleAPI(inspector->client()->currentTimeMS(), type, arguments, inspector->debugger()->captureStackTrace(false), inspectedContext); + inspector->ensureConsoleMessageStorage(inspectedContext->contextGroupId())->addMessage(std::move(message)); } void reportDeprecatedCall(const char* id, const String16& message) @@ -233,7 +233,7 @@ class ConsoleHelper { InspectedContext* inspectedContext = ensureInspectedContext(); if (!inspectedContext) return nullptr; - return inspectedContext->debugger()->sessionForContextGroup(inspectedContext->contextGroupId()); + return inspectedContext->inspector()->sessionForContextGroup(inspectedContext->contextGroupId()); } private: @@ -242,7 +242,7 @@ class ConsoleHelper { v8::Local m_context; v8::Local m_console; InspectedContext* m_inspectedContext; - V8DebuggerClient* m_debuggerClient; + V8InspectorClient* m_inspectorClient; bool checkAndSetPrivateFlagOnConsole(const char* name, bool defaultValue) { @@ -271,13 +271,13 @@ void createBoundFunctionProperty(v8::Local context, v8::Local funcName = toV8StringInternalized(context->GetIsolate(), name); v8::Local func; - if (!v8::Function::New(context, callback, console, 0, v8::ConstructorBehavior::kThrow).ToLocal(&func)) + if (!V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, console, 0).ToLocal(&func)) return; func->SetName(funcName); if (description) { v8::Local returnValue = toV8String(context->GetIsolate(), description); v8::Local toStringFunction; - if (v8::Function::New(context, returnDataCallback, returnValue, 0, v8::ConstructorBehavior::kThrow).ToLocal(&toStringFunction)) + if (V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, returnDataCallback, returnValue, 0).ToLocal(&toStringFunction)) func->Set(toV8StringInternalized(context->GetIsolate(), "toString"), toStringFunction); } if (!console->Set(context, funcName, func).FromMaybe(false)) @@ -413,7 +413,7 @@ void V8Console::profileEndCallback(const v8::FunctionCallbackInfo& in static void timeFunction(const v8::FunctionCallbackInfo& info, bool timelinePrefix) { ConsoleHelper helper(info); - if (V8DebuggerClient* client = helper.ensureDebuggerClient()) { + if (V8InspectorClient* client = helper.ensureDebuggerClient()) { String16 protocolTitle = helper.firstArgToString("default"); if (timelinePrefix) protocolTitle = "Timeline '" + protocolTitle + "'"; @@ -429,7 +429,7 @@ static void timeFunction(const v8::FunctionCallbackInfo& info, bool t static void timeEndFunction(const v8::FunctionCallbackInfo& info, bool timelinePrefix) { ConsoleHelper helper(info); - if (V8DebuggerClient* client = helper.ensureDebuggerClient()) { + if (V8InspectorClient* client = helper.ensureDebuggerClient()) { String16 protocolTitle = helper.firstArgToString("default"); if (timelinePrefix) protocolTitle = "Timeline '" + protocolTitle + "'"; @@ -469,13 +469,13 @@ void V8Console::timeEndCallback(const v8::FunctionCallbackInfo& info) void V8Console::timeStampCallback(const v8::FunctionCallbackInfo& info) { ConsoleHelper helper(info); - if (V8DebuggerClient* client = helper.ensureDebuggerClient()) + if (V8InspectorClient* client = helper.ensureDebuggerClient()) client->consoleTimeStamp(helper.firstArgToString(String16())); } void V8Console::memoryGetterCallback(const v8::FunctionCallbackInfo& info) { - if (V8DebuggerClient* client = ConsoleHelper(info).ensureDebuggerClient()) { + if (V8InspectorClient* client = ConsoleHelper(info).ensureDebuggerClient()) { v8::Local memoryValue; if (!client->memoryInfo(info.GetIsolate(), info.GetIsolate()->GetCurrentContext()).ToLocal(&memoryValue)) return; @@ -656,6 +656,7 @@ void V8Console::inspectedObject(const v8::FunctionCallbackInfo& info, v8::Local V8Console::createConsole(InspectedContext* inspectedContext, bool hasMemoryAttribute) { v8::Local context = inspectedContext->context(); + v8::Context::Scope contextScope(context); v8::Isolate* isolate = context->GetIsolate(); v8::MicrotasksScope microtasksScope(isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); @@ -689,7 +690,7 @@ v8::Local V8Console::createConsole(InspectedContext* inspectedContex DCHECK(success); if (hasMemoryAttribute) - console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), v8::Function::New(context, V8Console::memoryGetterCallback, console, 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(), v8::Function::New(context, V8Console::memorySetterCallback, v8::Local(), 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(), static_cast(v8::None), v8::DEFAULT); + console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, V8Console::memoryGetterCallback, console, 0).ToLocalChecked(), V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, V8Console::memorySetterCallback, v8::Local(), 0).ToLocalChecked(), static_cast(v8::None), v8::DEFAULT); console->SetPrivate(context, inspectedContextPrivateKey(isolate), v8::External::New(isolate, inspectedContext)); return console; @@ -731,7 +732,7 @@ v8::Local V8Console::createCommandLineAPI(InspectedContext* inspecte createBoundFunctionProperty(context, commandLineAPI, "$3", V8Console::inspectedObject3); createBoundFunctionProperty(context, commandLineAPI, "$4", V8Console::inspectedObject4); - inspectedContext->debugger()->client()->installAdditionalCommandLineAPI(context, commandLineAPI); + inspectedContext->inspector()->client()->installAdditionalCommandLineAPI(context, commandLineAPI); commandLineAPI->SetPrivate(context, inspectedContextPrivateKey(isolate), v8::External::New(isolate, inspectedContext)); return commandLineAPI; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleAgentImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleAgentImpl.cpp index ab4017532f4..0292dbb4ca6 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleAgentImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleAgentImpl.cpp @@ -5,7 +5,7 @@ #include "platform/v8_inspector/V8ConsoleAgentImpl.h" #include "platform/v8_inspector/V8ConsoleMessage.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" @@ -33,7 +33,7 @@ void V8ConsoleAgentImpl::enable(ErrorString* errorString) return; m_state->setBoolean(ConsoleAgentState::consoleEnabled, true); m_enabled = true; - m_session->debugger()->enableStackCapturingIfNeeded(); + m_session->inspector()->enableStackCapturingIfNeeded(); reportAllMessages(); } @@ -41,7 +41,7 @@ void V8ConsoleAgentImpl::disable(ErrorString* errorString) { if (!m_enabled) return; - m_session->debugger()->disableStackCapturingIfNeeded(); + m_session->inspector()->disableStackCapturingIfNeeded(); m_state->setBoolean(ConsoleAgentState::consoleEnabled, false); m_enabled = false; } @@ -71,7 +71,7 @@ bool V8ConsoleAgentImpl::enabled() void V8ConsoleAgentImpl::reportAllMessages() { - V8ConsoleMessageStorage* storage = m_session->debugger()->ensureConsoleMessageStorage(m_session->contextGroupId()); + V8ConsoleMessageStorage* storage = m_session->inspector()->ensureConsoleMessageStorage(m_session->contextGroupId()); for (const auto& message : storage->messages()) { if (message->origin() == V8MessageOrigin::kConsole) reportMessage(message.get(), false); diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.cpp index 42fe95bdfcd..84bcc3d6e54 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.cpp @@ -6,12 +6,12 @@ #include "platform/v8_inspector/InspectedContext.h" #include "platform/v8_inspector/V8ConsoleAgentImpl.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8RuntimeAgentImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" namespace blink { @@ -191,7 +191,7 @@ V8ConsoleMessage::~V8ConsoleMessage() { } -void V8ConsoleMessage::setLocation(const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr stackTrace, int scriptId) +void V8ConsoleMessage::setLocation(const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr stackTrace, int scriptId) { m_url = url; m_lineNumber = lineNumber; @@ -219,7 +219,7 @@ std::unique_ptr> V8ConsoleMessa { if (!m_arguments.size() || !m_contextId) return nullptr; - InspectedContext* inspectedContext = session->debugger()->getContext(session->contextGroupId(), m_contextId); + InspectedContext* inspectedContext = session->inspector()->getContext(session->contextGroupId(), m_contextId); if (!inspectedContext) return nullptr; @@ -252,9 +252,10 @@ std::unique_ptr> V8ConsoleMessa void V8ConsoleMessage::reportToFrontend(protocol::Runtime::Frontend* frontend, V8InspectorSessionImpl* session, bool generatePreview) const { if (m_origin == V8MessageOrigin::kException) { + std::unique_ptr exception = wrapException(session, generatePreview); // TODO(dgozman): unify with InjectedScript::createExceptionDetails. std::unique_ptr details = protocol::Runtime::ExceptionDetails::create() - .setText(m_message) + .setText(exception ? m_message : m_detailedMessage) .setLineNumber(m_lineNumber ? m_lineNumber - 1 : 0) .setColumnNumber(m_columnNumber ? m_columnNumber - 1 : 0) .setScriptId(m_scriptId ? String16::fromInteger(m_scriptId) : String16()) @@ -262,9 +263,7 @@ void V8ConsoleMessage::reportToFrontend(protocol::Runtime::Frontend* frontend, V if (!m_url.isEmpty()) details->setUrl(m_url); if (m_stackTrace) - details->setStackTrace(m_stackTrace->buildInspectorObject()); - - std::unique_ptr exception = wrapException(session, generatePreview); + details->setStackTrace(m_stackTrace->buildInspectorObjectImpl()); if (exception) frontend->exceptionThrown(m_exceptionId, m_timestamp, std::move(details), std::move(exception), m_contextId); @@ -286,7 +285,7 @@ void V8ConsoleMessage::reportToFrontend(protocol::Runtime::Frontend* frontend, V arguments->addItem(std::move(messageArg)); } } - frontend->consoleAPICalled(consoleAPITypeValue(m_type), std::move(arguments), m_contextId, m_timestamp, m_stackTrace ? m_stackTrace->buildInspectorObject() : nullptr); + frontend->consoleAPICalled(consoleAPITypeValue(m_type), std::move(arguments), m_contextId, m_timestamp, m_stackTrace ? m_stackTrace->buildInspectorObjectImpl() : nullptr); return; } NOTREACHED(); @@ -297,7 +296,7 @@ std::unique_ptr V8ConsoleMessage::wrapException if (!m_arguments.size() || !m_contextId) return nullptr; DCHECK_EQ(1u, m_arguments.size()); - InspectedContext* inspectedContext = session->debugger()->getContext(session->contextGroupId(), m_contextId); + InspectedContext* inspectedContext = session->inspector()->getContext(session->contextGroupId(), m_contextId); if (!inspectedContext) return nullptr; @@ -318,7 +317,7 @@ ConsoleAPIType V8ConsoleMessage::type() const } // static -std::unique_ptr V8ConsoleMessage::createForConsoleAPI(double timestamp, ConsoleAPIType type, const std::vector>& arguments, std::unique_ptr stackTrace, InspectedContext* context) +std::unique_ptr V8ConsoleMessage::createForConsoleAPI(double timestamp, ConsoleAPIType type, const std::vector>& arguments, std::unique_ptr stackTrace, InspectedContext* context) { std::unique_ptr message = wrapUnique(new V8ConsoleMessage(V8MessageOrigin::kConsole, timestamp, String16())); if (stackTrace && !stackTrace->isEmpty()) { @@ -334,31 +333,34 @@ std::unique_ptr V8ConsoleMessage::createForConsoleAPI(double t if (arguments.size()) message->m_message = V8ValueStringBuilder::toString(arguments[0], context->isolate()); - MessageLevel level = LogMessageLevel; + V8ConsoleAPIType clientType = V8ConsoleAPIType::kLog; if (type == ConsoleAPIType::kDebug || type == ConsoleAPIType::kCount || type == ConsoleAPIType::kTimeEnd) - level = DebugMessageLevel; - if (type == ConsoleAPIType::kError || type == ConsoleAPIType::kAssert) - level = ErrorMessageLevel; - if (type == ConsoleAPIType::kWarning) - level = WarningMessageLevel; - if (type == ConsoleAPIType::kInfo) - level = InfoMessageLevel; - context->debugger()->client()->consoleAPIMessage(context->contextGroupId(), level, message->m_message, message->m_url, message->m_lineNumber, message->m_columnNumber, message->m_stackTrace.get()); + clientType = V8ConsoleAPIType::kDebug; + else if (type == ConsoleAPIType::kError || type == ConsoleAPIType::kAssert) + clientType = V8ConsoleAPIType::kError; + else if (type == ConsoleAPIType::kWarning) + clientType = V8ConsoleAPIType::kWarning; + else if (type == ConsoleAPIType::kInfo) + clientType = V8ConsoleAPIType::kInfo; + else if (type == ConsoleAPIType::kClear) + clientType = V8ConsoleAPIType::kClear; + context->inspector()->client()->consoleAPIMessage(context->contextGroupId(), clientType, message->m_message, message->m_url, message->m_lineNumber, message->m_columnNumber, message->m_stackTrace.get()); return message; } // static -std::unique_ptr V8ConsoleMessage::createForException(double timestamp, const String16& messageText, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr stackTrace, int scriptId, v8::Isolate* isolate, int contextId, v8::Local exception, unsigned exceptionId) +std::unique_ptr V8ConsoleMessage::createForException(double timestamp, const String16& detailedMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr stackTrace, int scriptId, v8::Isolate* isolate, const String16& message, int contextId, v8::Local exception, unsigned exceptionId) { - std::unique_ptr message = wrapUnique(new V8ConsoleMessage(V8MessageOrigin::kException, timestamp, messageText)); - message->setLocation(url, lineNumber, columnNumber, std::move(stackTrace), scriptId); - message->m_exceptionId = exceptionId; + std::unique_ptr consoleMessage = wrapUnique(new V8ConsoleMessage(V8MessageOrigin::kException, timestamp, message)); + consoleMessage->setLocation(url, lineNumber, columnNumber, std::move(stackTrace), scriptId); + consoleMessage->m_exceptionId = exceptionId; + consoleMessage->m_detailedMessage = detailedMessage; if (contextId && !exception.IsEmpty()) { - message->m_contextId = contextId; - message->m_arguments.push_back(wrapUnique(new v8::Global(isolate, exception))); + consoleMessage->m_contextId = contextId; + consoleMessage->m_arguments.push_back(wrapUnique(new v8::Global(isolate, exception))); } - return message; + return consoleMessage; } // static @@ -382,8 +384,8 @@ void V8ConsoleMessage::contextDestroyed(int contextId) // ------------------------ V8ConsoleMessageStorage ---------------------------- -V8ConsoleMessageStorage::V8ConsoleMessageStorage(V8DebuggerImpl* debugger, int contextGroupId) - : m_debugger(debugger) +V8ConsoleMessageStorage::V8ConsoleMessageStorage(V8InspectorImpl* inspector, int contextGroupId) + : m_inspector(inspector) , m_contextGroupId(contextGroupId) , m_expiredCount(0) { @@ -392,17 +394,14 @@ V8ConsoleMessageStorage::V8ConsoleMessageStorage(V8DebuggerImpl* debugger, int c V8ConsoleMessageStorage::~V8ConsoleMessageStorage() { clear(); - notifyClear(); } void V8ConsoleMessageStorage::addMessage(std::unique_ptr message) { - if (message->type() == ConsoleAPIType::kClear) { + if (message->type() == ConsoleAPIType::kClear) clear(); - notifyClear(); - } - V8InspectorSessionImpl* session = m_debugger->sessionForContextGroup(m_contextGroupId); + V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup(m_contextGroupId); if (session) { if (message->origin() == V8MessageOrigin::kConsole) session->consoleAgent()->messageAdded(message.get()); @@ -421,7 +420,7 @@ void V8ConsoleMessageStorage::clear() { m_messages.clear(); m_expiredCount = 0; - if (V8InspectorSessionImpl* session = m_debugger->sessionForContextGroup(m_contextGroupId)) + if (V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup(m_contextGroupId)) session->releaseObjectGroup("console"); } @@ -431,10 +430,4 @@ void V8ConsoleMessageStorage::contextDestroyed(int contextId) m_messages[i]->contextDestroyed(contextId); } -void V8ConsoleMessageStorage::notifyClear() -{ - if (V8InspectorSessionImpl* session = m_debugger->sessionForContextGroup(m_contextGroupId)) - session->client()->consoleCleared(); -} - } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.h index 923a84e9269..9c26f5d9e8f 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ConsoleMessage.h @@ -9,17 +9,15 @@ #include "platform/inspector_protocol/String16.h" #include "platform/v8_inspector/protocol/Console.h" #include "platform/v8_inspector/protocol/Runtime.h" -#include "platform/v8_inspector/public/V8ConsoleTypes.h" -#include "platform/v8_inspector/public/V8StackTrace.h" #include #include namespace blink { class InspectedContext; -class V8DebuggerImpl; +class V8InspectorImpl; class V8InspectorSessionImpl; -class V8StackTrace; +class V8StackTraceImpl; enum class V8MessageOrigin { kConsole, kException, kRevokedException }; @@ -33,18 +31,19 @@ class V8ConsoleMessage { double timestamp, ConsoleAPIType, const std::vector>& arguments, - std::unique_ptr, + std::unique_ptr, InspectedContext*); static std::unique_ptr createForException( double timestamp, - const String16& message, + const String16& detailedMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, - std::unique_ptr, + std::unique_ptr, int scriptId, v8::Isolate*, + const String16& message, int contextId, v8::Local exception, unsigned exceptionId); @@ -66,7 +65,7 @@ class V8ConsoleMessage { using Arguments = std::vector>>; std::unique_ptr> wrapArguments(V8InspectorSessionImpl*, bool generatePreview) const; std::unique_ptr wrapException(V8InspectorSessionImpl*, bool generatePreview) const; - void setLocation(const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId); + void setLocation(const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId); V8MessageOrigin m_origin; double m_timestamp; @@ -74,18 +73,19 @@ class V8ConsoleMessage { String16 m_url; unsigned m_lineNumber; unsigned m_columnNumber; - std::unique_ptr m_stackTrace; + std::unique_ptr m_stackTrace; int m_scriptId; int m_contextId; ConsoleAPIType m_type; unsigned m_exceptionId; unsigned m_revokedExceptionId; Arguments m_arguments; + String16 m_detailedMessage; }; class V8ConsoleMessageStorage { public: - V8ConsoleMessageStorage(V8DebuggerImpl*, int contextGroupId); + V8ConsoleMessageStorage(V8InspectorImpl*, int contextGroupId); ~V8ConsoleMessageStorage(); int contextGroupId() { return m_contextGroupId; } @@ -97,9 +97,7 @@ class V8ConsoleMessageStorage { void clear(); private: - void notifyClear(); - - V8DebuggerImpl* m_debugger; + V8InspectorImpl* m_inspector; int m_contextGroupId; int m_expiredCount; std::deque> m_messages; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Debugger.cpp similarity index 53% rename from deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerImpl.cpp rename to deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Debugger.cpp index 4d84b32cece..a7ebd019f94 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Debugger.cpp @@ -1,59 +1,24 @@ -/* - * Copyright (c) 2010-2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "platform/v8_inspector/V8DebuggerImpl.h" - -#include "platform/inspector_protocol/Values.h" -#include "platform/v8_inspector/Atomics.h" +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/v8_inspector/V8Debugger.h" + #include "platform/v8_inspector/DebuggerScript.h" -#include "platform/v8_inspector/InspectedContext.h" #include "platform/v8_inspector/ScriptBreakpoint.h" #include "platform/v8_inspector/V8Compat.h" -#include "platform/v8_inspector/V8ConsoleAgentImpl.h" -#include "platform/v8_inspector/V8ConsoleMessage.h" #include "platform/v8_inspector/V8DebuggerAgentImpl.h" -#include "platform/v8_inspector/V8InjectedScriptHost.h" -#include "platform/v8_inspector/V8InspectorSessionImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InternalValueType.h" -#include "platform/v8_inspector/V8RuntimeAgentImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" -#include +#include "platform/v8_inspector/public/V8InspectorClient.h" namespace blink { namespace { const char stepIntoV8MethodName[] = "stepIntoStatement"; const char stepOutV8MethodName[] = "stepOutOfFunction"; -volatile int s_lastContextId = 0; static const char v8AsyncTaskEventEnqueue[] = "enqueue"; static const char v8AsyncTaskEventWillHandle[] = "willHandle"; static const char v8AsyncTaskEventDidHandle[] = "didHandle"; @@ -67,47 +32,46 @@ inline v8::Local v8Boolean(bool value, v8::Isolate* isolate) static bool inLiveEditScope = false; -v8::MaybeLocal V8DebuggerImpl::callDebuggerMethod(const char* functionName, int argc, v8::Local argv[]) +v8::MaybeLocal V8Debugger::callDebuggerMethod(const char* functionName, int argc, v8::Local argv[]) { v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local debuggerScript = m_debuggerScript.Get(m_isolate); - v8::Local function = v8::Local::Cast(debuggerScript->Get(v8InternalizedString(functionName))); + v8::Local function = v8::Local::Cast(debuggerScript->Get(toV8StringInternalized(m_isolate, functionName))); DCHECK(m_isolate->InContext()); return function->Call(m_isolate->GetCurrentContext(), debuggerScript, argc, argv); } -std::unique_ptr V8Debugger::create(v8::Isolate* isolate, V8DebuggerClient* client) -{ - return wrapUnique(new V8DebuggerImpl(isolate, client)); -} - -V8DebuggerImpl::V8DebuggerImpl(v8::Isolate* isolate, V8DebuggerClient* client) +V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) : m_isolate(isolate) - , m_client(client) - , m_capturingStackTracesCount(0) - , m_lastExceptionId(0) - , m_enabledAgentsCount(0) + , m_inspector(inspector) + , m_lastContextId(0) + , m_enableCount(0) , m_breakpointsActivated(true) , m_runningNestedMessageLoop(false) + , m_ignoreScriptParsedEventsCounter(0) , m_maxAsyncCallStackDepth(0) { } -V8DebuggerImpl::~V8DebuggerImpl() +V8Debugger::~V8Debugger() { } -void V8DebuggerImpl::enable() +void V8Debugger::enable() { + if (m_enableCount++) + return; DCHECK(!enabled()); v8::HandleScope scope(m_isolate); - v8::Debug::SetDebugEventListener(m_isolate, &V8DebuggerImpl::v8DebugEventCallback, v8::External::New(m_isolate, this)); + v8::Debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback, v8::External::New(m_isolate, this)); m_debuggerContext.Reset(m_isolate, v8::Debug::GetDebugContext(m_isolate)); compileDebuggerScript(); } -void V8DebuggerImpl::disable() +void V8Debugger::disable() { + if (--m_enableCount) + return; DCHECK(enabled()); clearBreakpoints(); m_debuggerScript.Reset(); @@ -116,13 +80,13 @@ void V8DebuggerImpl::disable() v8::Debug::SetDebugEventListener(m_isolate, nullptr); } -bool V8DebuggerImpl::enabled() const +bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } // static -int V8DebuggerImpl::contextId(v8::Local context) +int V8Debugger::contextId(v8::Local context) { v8::Local data = context->GetEmbedderData(static_cast(v8::Context::kDebugIdIndex)); if (data.IsEmpty() || !data->IsString()) @@ -140,7 +104,7 @@ int V8DebuggerImpl::contextId(v8::Local context) } // static -int V8DebuggerImpl::getGroupId(v8::Local context) +int V8Debugger::getGroupId(v8::Local context) { v8::Local data = context->GetEmbedderData(static_cast(v8::Context::kDebugIdIndex)); if (data.IsEmpty() || !data->IsString()) @@ -154,43 +118,13 @@ int V8DebuggerImpl::getGroupId(v8::Local context) return dataString.substring(0, commaPos).toInt(); } -void V8DebuggerImpl::debuggerAgentEnabled() -{ - if (!m_enabledAgentsCount++) - enable(); -} - -void V8DebuggerImpl::debuggerAgentDisabled() -{ - if (!--m_enabledAgentsCount) - disable(); -} - -V8DebuggerAgentImpl* V8DebuggerImpl::findEnabledDebuggerAgent(int contextGroupId) -{ - if (!contextGroupId) - return nullptr; - SessionMap::iterator it = m_sessions.find(contextGroupId); - if (it == m_sessions.end()) - return nullptr; - V8DebuggerAgentImpl* agent = it->second->debuggerAgent(); - if (!agent->enabled()) - return nullptr; - return agent; -} - -V8DebuggerAgentImpl* V8DebuggerImpl::findEnabledDebuggerAgent(v8::Local context) -{ - return findEnabledDebuggerAgent(getGroupId(context)); -} - -void V8DebuggerImpl::getCompiledScripts(int contextGroupId, std::vector>& result) +void V8Debugger::getCompiledScripts(int contextGroupId, std::vector>& result) { v8::HandleScope scope(m_isolate); v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local debuggerScript = m_debuggerScript.Get(m_isolate); DCHECK(!debuggerScript->IsUndefined()); - v8::Local getScriptsFunction = v8::Local::Cast(debuggerScript->Get(v8InternalizedString("getScripts"))); + v8::Local getScriptsFunction = v8::Local::Cast(debuggerScript->Get(toV8StringInternalized(m_isolate, "getScripts"))); v8::Local argv[] = { v8::Integer::New(m_isolate, contextGroupId) }; v8::Local value; if (!getScriptsFunction->Call(debuggerContext(), debuggerScript, PROTOCOL_ARRAY_LENGTH(argv), argv).ToLocal(&value)) @@ -204,49 +138,49 @@ void V8DebuggerImpl::getCompiledScripts(int contextGroupId, std::vector info = v8::Object::New(m_isolate); - info->Set(v8InternalizedString("sourceID"), toV8String(m_isolate, sourceID)); - info->Set(v8InternalizedString("lineNumber"), v8::Integer::New(m_isolate, scriptBreakpoint.lineNumber)); - info->Set(v8InternalizedString("columnNumber"), v8::Integer::New(m_isolate, scriptBreakpoint.columnNumber)); - info->Set(v8InternalizedString("interstatementLocation"), v8Boolean(interstatementLocation, m_isolate)); - info->Set(v8InternalizedString("condition"), toV8String(m_isolate, scriptBreakpoint.condition)); + info->Set(toV8StringInternalized(m_isolate, "sourceID"), toV8String(m_isolate, sourceID)); + info->Set(toV8StringInternalized(m_isolate, "lineNumber"), v8::Integer::New(m_isolate, scriptBreakpoint.lineNumber)); + info->Set(toV8StringInternalized(m_isolate, "columnNumber"), v8::Integer::New(m_isolate, scriptBreakpoint.columnNumber)); + info->Set(toV8StringInternalized(m_isolate, "interstatementLocation"), v8Boolean(interstatementLocation, m_isolate)); + info->Set(toV8StringInternalized(m_isolate, "condition"), toV8String(m_isolate, scriptBreakpoint.condition)); - v8::Local setBreakpointFunction = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("setBreakpoint"))); + v8::Local setBreakpointFunction = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(toV8StringInternalized(m_isolate, "setBreakpoint"))); v8::Local breakpointId = v8::Debug::Call(debuggerContext(), setBreakpointFunction, info).ToLocalChecked(); if (!breakpointId->IsString()) return ""; - *actualLineNumber = info->Get(v8InternalizedString("lineNumber"))->Int32Value(); - *actualColumnNumber = info->Get(v8InternalizedString("columnNumber"))->Int32Value(); + *actualLineNumber = info->Get(toV8StringInternalized(m_isolate, "lineNumber"))->Int32Value(); + *actualColumnNumber = info->Get(toV8StringInternalized(m_isolate, "columnNumber"))->Int32Value(); return toProtocolString(breakpointId.As()); } -void V8DebuggerImpl::removeBreakpoint(const String16& breakpointId) +void V8Debugger::removeBreakpoint(const String16& breakpointId) { v8::HandleScope scope(m_isolate); v8::Context::Scope contextScope(debuggerContext()); v8::Local info = v8::Object::New(m_isolate); - info->Set(v8InternalizedString("breakpointId"), toV8String(m_isolate, breakpointId)); + info->Set(toV8StringInternalized(m_isolate, "breakpointId"), toV8String(m_isolate, breakpointId)); - v8::Local removeBreakpointFunction = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("removeBreakpoint"))); + v8::Local removeBreakpointFunction = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(toV8StringInternalized(m_isolate, "removeBreakpoint"))); v8::Debug::Call(debuggerContext(), removeBreakpointFunction, info).ToLocalChecked(); } -void V8DebuggerImpl::clearBreakpoints() +void V8Debugger::clearBreakpoints() { v8::HandleScope scope(m_isolate); v8::Context::Scope contextScope(debuggerContext()); - v8::Local clearBreakpoints = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("clearBreakpoints"))); + v8::Local clearBreakpoints = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(toV8StringInternalized(m_isolate, "clearBreakpoints"))); v8::Debug::Call(debuggerContext(), clearBreakpoints).ToLocalChecked(); } -void V8DebuggerImpl::setBreakpointsActivated(bool activated) +void V8Debugger::setBreakpointsActivated(bool activated) { if (!enabled()) { NOTREACHED(); @@ -256,14 +190,14 @@ void V8DebuggerImpl::setBreakpointsActivated(bool activated) v8::Context::Scope contextScope(debuggerContext()); v8::Local info = v8::Object::New(m_isolate); - info->Set(v8InternalizedString("enabled"), v8::Boolean::New(m_isolate, activated)); - v8::Local setBreakpointsActivated = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("setBreakpointsActivated"))); + info->Set(toV8StringInternalized(m_isolate, "enabled"), v8::Boolean::New(m_isolate, activated)); + v8::Local setBreakpointsActivated = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(toV8StringInternalized(m_isolate, "setBreakpointsActivated"))); v8::Debug::Call(debuggerContext(), setBreakpointsActivated, info).ToLocalChecked(); m_breakpointsActivated = activated; } -V8DebuggerImpl::PauseOnExceptionsState V8DebuggerImpl::getPauseOnExceptionsState() +V8Debugger::PauseOnExceptionsState V8Debugger::getPauseOnExceptionsState() { DCHECK(enabled()); v8::HandleScope scope(m_isolate); @@ -271,10 +205,10 @@ V8DebuggerImpl::PauseOnExceptionsState V8DebuggerImpl::getPauseOnExceptionsState v8::Local argv[] = { v8::Undefined(m_isolate) }; v8::Local result = callDebuggerMethod("pauseOnExceptionsState", 0, argv).ToLocalChecked(); - return static_cast(result->Int32Value()); + return static_cast(result->Int32Value()); } -void V8DebuggerImpl::setPauseOnExceptionsState(PauseOnExceptionsState pauseOnExceptionsState) +void V8Debugger::setPauseOnExceptionsState(PauseOnExceptionsState pauseOnExceptionsState) { DCHECK(enabled()); v8::HandleScope scope(m_isolate); @@ -284,7 +218,7 @@ void V8DebuggerImpl::setPauseOnExceptionsState(PauseOnExceptionsState pauseOnExc callDebuggerMethod("setPauseOnExceptionsState", 1, argv); } -void V8DebuggerImpl::setPauseOnNextStatement(bool pause) +void V8Debugger::setPauseOnNextStatement(bool pause) { if (m_runningNestedMessageLoop) return; @@ -294,14 +228,14 @@ void V8DebuggerImpl::setPauseOnNextStatement(bool pause) v8::Debug::CancelDebugBreak(m_isolate); } -bool V8DebuggerImpl::canBreakProgram() +bool V8Debugger::canBreakProgram() { if (!m_breakpointsActivated) return false; return m_isolate->InContext(); } -void V8DebuggerImpl::breakProgram() +void V8Debugger::breakProgram() { if (isPaused()) { DCHECK(!m_runningNestedMessageLoop); @@ -316,20 +250,20 @@ void V8DebuggerImpl::breakProgram() v8::HandleScope scope(m_isolate); v8::Local breakFunction; - if (!v8::Function::New(m_isolate->GetCurrentContext(), &V8DebuggerImpl::breakProgramCallback, v8::External::New(m_isolate, this), 0, v8::ConstructorBehavior::kThrow).ToLocal(&breakFunction)) + if (!V8_FUNCTION_NEW_REMOVE_PROTOTYPE(m_isolate->GetCurrentContext(), &V8Debugger::breakProgramCallback, v8::External::New(m_isolate, this), 0).ToLocal(&breakFunction)) return; v8::Debug::Call(debuggerContext(), breakFunction).ToLocalChecked(); } -void V8DebuggerImpl::continueProgram() +void V8Debugger::continueProgram() { if (isPaused()) - m_client->quitMessageLoopOnPause(); + m_inspector->client()->quitMessageLoopOnPause(); m_pausedContext.Clear(); m_executionState.Clear(); } -void V8DebuggerImpl::stepIntoStatement() +void V8Debugger::stepIntoStatement() { DCHECK(isPaused()); DCHECK(!m_executionState.IsEmpty()); @@ -339,7 +273,7 @@ void V8DebuggerImpl::stepIntoStatement() continueProgram(); } -void V8DebuggerImpl::stepOverStatement() +void V8Debugger::stepOverStatement() { DCHECK(isPaused()); DCHECK(!m_executionState.IsEmpty()); @@ -349,7 +283,7 @@ void V8DebuggerImpl::stepOverStatement() continueProgram(); } -void V8DebuggerImpl::stepOutOfFunction() +void V8Debugger::stepOutOfFunction() { DCHECK(isPaused()); DCHECK(!m_executionState.IsEmpty()); @@ -359,7 +293,7 @@ void V8DebuggerImpl::stepOutOfFunction() continueProgram(); } -void V8DebuggerImpl::clearStepping() +void V8Debugger::clearStepping() { DCHECK(enabled()); v8::HandleScope scope(m_isolate); @@ -369,7 +303,7 @@ void V8DebuggerImpl::clearStepping() callDebuggerMethod("clearStepping", 0, argv); } -bool V8DebuggerImpl::setScriptSource(const String16& sourceID, v8::Local newSource, bool preview, ErrorString* error, Maybe* exceptionDetails, JavaScriptCallFrames* newCallFrames, Maybe* stackChanged) +bool V8Debugger::setScriptSource(const String16& sourceID, v8::Local newSource, bool preview, ErrorString* error, Maybe* exceptionDetails, JavaScriptCallFrames* newCallFrames, Maybe* stackChanged) { class EnableLiveEditScope { public: @@ -441,13 +375,13 @@ bool V8DebuggerImpl::setScriptSource(const String16& sourceID, v8::LocalInContext()) return JavaScriptCallFrames(); v8::Local currentCallFramesV8; if (m_executionState.IsEmpty()) { - v8::Local currentCallFramesFunction = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("currentCallFrames"))); + v8::Local currentCallFramesFunction = v8::Local::Cast(m_debuggerScript.Get(m_isolate)->Get(toV8StringInternalized(m_isolate, "currentCallFrames"))); currentCallFramesV8 = v8::Debug::Call(debuggerContext(), currentCallFramesFunction, v8::Integer::New(m_isolate, limit)).ToLocalChecked(); } else { v8::Local argv[] = { m_executionState, v8::Integer::New(m_isolate, limit) }; @@ -470,29 +404,31 @@ JavaScriptCallFrames V8DebuggerImpl::currentCallFrames(int limit) return callFrames; } -static V8DebuggerImpl* toV8DebuggerImpl(v8::Local data) +static V8Debugger* toV8Debugger(v8::Local data) { void* p = v8::Local::Cast(data)->Value(); - return static_cast(p); + return static_cast(p); } -void V8DebuggerImpl::breakProgramCallback(const v8::FunctionCallbackInfo& info) +void V8Debugger::breakProgramCallback(const v8::FunctionCallbackInfo& info) { DCHECK_EQ(info.Length(), 2); - V8DebuggerImpl* thisPtr = toV8DebuggerImpl(info.Data()); + V8Debugger* thisPtr = toV8Debugger(info.Data()); + if (!thisPtr->enabled()) + return; v8::Local pausedContext = thisPtr->m_isolate->GetCurrentContext(); v8::Local exception; v8::Local hitBreakpoints; thisPtr->handleProgramBreak(pausedContext, v8::Local::Cast(info[0]), exception, hitBreakpoints); } -void V8DebuggerImpl::handleProgramBreak(v8::Local pausedContext, v8::Local executionState, v8::Local exception, v8::Local hitBreakpointNumbers, bool isPromiseRejection) +void V8Debugger::handleProgramBreak(v8::Local pausedContext, v8::Local executionState, v8::Local exception, v8::Local hitBreakpointNumbers, bool isPromiseRejection) { // Don't allow nested breaks. if (m_runningNestedMessageLoop) return; - V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(pausedContext); + V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(getGroupId(pausedContext)); if (!agent) return; @@ -513,9 +449,9 @@ void V8DebuggerImpl::handleProgramBreak(v8::Local pausedContext, v8 m_runningNestedMessageLoop = true; int groupId = getGroupId(pausedContext); DCHECK(groupId); - m_client->runMessageLoopOnPause(groupId); + m_inspector->client()->runMessageLoopOnPause(groupId); // The agent may have been removed in the nested loop. - agent = findEnabledDebuggerAgent(pausedContext); + agent = m_inspector->enabledDebuggerAgentForGroup(getGroupId(pausedContext)); if (agent) agent->didContinue(); m_runningNestedMessageLoop = false; @@ -535,21 +471,21 @@ void V8DebuggerImpl::handleProgramBreak(v8::Local pausedContext, v8 } } -void V8DebuggerImpl::v8DebugEventCallback(const v8::Debug::EventDetails& eventDetails) +void V8Debugger::v8DebugEventCallback(const v8::Debug::EventDetails& eventDetails) { - V8DebuggerImpl* thisPtr = toV8DebuggerImpl(eventDetails.GetCallbackData()); + V8Debugger* thisPtr = toV8Debugger(eventDetails.GetCallbackData()); thisPtr->handleV8DebugEvent(eventDetails); } -v8::Local V8DebuggerImpl::callInternalGetterFunction(v8::Local object, const char* functionName) +v8::Local V8Debugger::callInternalGetterFunction(v8::Local object, const char* functionName) { v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); - v8::Local getterValue = object->Get(v8InternalizedString(functionName)); + v8::Local getterValue = object->Get(toV8StringInternalized(m_isolate, functionName)); DCHECK(!getterValue.IsEmpty() && getterValue->IsFunction()); return v8::Local::Cast(getterValue)->Call(m_isolate->GetCurrentContext(), object, 0, 0).ToLocalChecked(); } -void V8DebuggerImpl::handleV8DebugEvent(const v8::Debug::EventDetails& eventDetails) +void V8Debugger::handleV8DebugEvent(const v8::Debug::EventDetails& eventDetails) { if (!enabled()) return; @@ -566,10 +502,10 @@ void V8DebuggerImpl::handleV8DebugEvent(const v8::Debug::EventDetails& eventDeta return; } - V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(eventContext); + V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(getGroupId(eventContext)); if (agent) { v8::HandleScope scope(m_isolate); - if (event == v8::AfterCompile || event == v8::CompileError) { + if (m_ignoreScriptParsedEventsCounter == 0 && (event == v8::AfterCompile || event == v8::CompileError)) { v8::Context::Scope contextScope(debuggerContext()); v8::Local argv[] = { eventDetails.GetEventData() }; v8::Local value = callDebuggerMethod("getAfterCompileScript", 1, argv).ToLocalChecked(); @@ -591,7 +527,7 @@ void V8DebuggerImpl::handleV8DebugEvent(const v8::Debug::EventDetails& eventDeta } } -void V8DebuggerImpl::handleV8AsyncTaskEvent(v8::Local context, v8::Local executionState, v8::Local eventData) +void V8Debugger::handleV8AsyncTaskEvent(v8::Local context, v8::Local executionState, v8::Local eventData) { if (!m_maxAsyncCallStackDepth) return; @@ -611,14 +547,14 @@ void V8DebuggerImpl::handleV8AsyncTaskEvent(v8::Local context, v8:: NOTREACHED(); } -V8StackTraceImpl* V8DebuggerImpl::currentAsyncCallChain() +V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { if (!m_currentStacks.size()) return nullptr; return m_currentStacks.back().get(); } -void V8DebuggerImpl::compileDebuggerScript() +void V8Debugger::compileDebuggerScript() { if (!m_debuggerScript.IsEmpty()) { NOTREACHED(); @@ -630,24 +566,21 @@ void V8DebuggerImpl::compileDebuggerScript() v8::Local scriptValue = v8::String::NewFromUtf8(m_isolate, DebuggerScript_js, v8::NewStringType::kInternalized, sizeof(DebuggerScript_js)).ToLocalChecked(); v8::Local value; - if (!compileAndRunInternalScript(debuggerContext(), scriptValue).ToLocal(&value)) + if (!m_inspector->compileAndRunInternalScript(debuggerContext(), scriptValue).ToLocal(&value)) { + NOTREACHED(); return; + } DCHECK(value->IsObject()); m_debuggerScript.Reset(m_isolate, value.As()); } -v8::Local V8DebuggerImpl::debuggerContext() const +v8::Local V8Debugger::debuggerContext() const { DCHECK(!m_debuggerContext.IsEmpty()); return m_debuggerContext.Get(m_isolate); } -v8::Local V8DebuggerImpl::v8InternalizedString(const char* str) const -{ - return v8::String::NewFromUtf8(m_isolate, str, v8::NewStringType::kInternalized).ToLocalChecked(); -} - -v8::MaybeLocal V8DebuggerImpl::functionScopes(v8::Local function) +v8::MaybeLocal V8Debugger::functionScopes(v8::Local function) { if (!enabled()) { NOTREACHED(); @@ -668,7 +601,7 @@ v8::MaybeLocal V8DebuggerImpl::functionScopes(v8::Local return scopes; } -v8::MaybeLocal V8DebuggerImpl::internalProperties(v8::Local context, v8::Local value) +v8::MaybeLocal V8Debugger::internalProperties(v8::Local context, v8::Local value) { v8::Local properties; if (!v8::Debug::GetInternalProperties(m_isolate, value).ToLocal(&properties)) @@ -677,11 +610,11 @@ v8::MaybeLocal V8DebuggerImpl::internalProperties(v8::Local function = value.As(); v8::Local location = functionLocation(context, function); if (location->IsObject()) { - properties->Set(properties->Length(), v8InternalizedString("[[FunctionLocation]]")); + properties->Set(properties->Length(), toV8StringInternalized(m_isolate, "[[FunctionLocation]]")); properties->Set(properties->Length(), location); } if (function->IsGeneratorFunction()) { - properties->Set(properties->Length(), v8InternalizedString("[[IsGenerator]]")); + properties->Set(properties->Length(), toV8StringInternalized(m_isolate, "[[IsGenerator]]")); properties->Set(properties->Length(), v8::True(m_isolate)); } } @@ -690,14 +623,14 @@ v8::MaybeLocal V8DebuggerImpl::internalProperties(v8::LocalIsMap() || value->IsWeakMap() || value->IsSet() || value->IsWeakSet() || value->IsSetIterator() || value->IsMapIterator()) { v8::Local entries = collectionEntries(context, v8::Local::Cast(value)); if (entries->IsArray()) { - properties->Set(properties->Length(), v8InternalizedString("[[Entries]]")); + properties->Set(properties->Length(), toV8StringInternalized(m_isolate, "[[Entries]]")); properties->Set(properties->Length(), entries); } } if (value->IsGeneratorObject()) { v8::Local location = generatorObjectLocation(v8::Local::Cast(value)); if (location->IsObject()) { - properties->Set(properties->Length(), v8InternalizedString("[[GeneratorLocation]]")); + properties->Set(properties->Length(), toV8StringInternalized(m_isolate, "[[GeneratorLocation]]")); properties->Set(properties->Length(), location); } } @@ -706,14 +639,14 @@ v8::MaybeLocal V8DebuggerImpl::internalProperties(v8::Local boundFunction = function->GetBoundFunction(); v8::Local scopes; if (boundFunction->IsUndefined() && functionScopes(function).ToLocal(&scopes)) { - properties->Set(properties->Length(), v8InternalizedString("[[Scopes]]")); + properties->Set(properties->Length(), toV8StringInternalized(m_isolate, "[[Scopes]]")); properties->Set(properties->Length(), scopes); } } return properties; } -v8::Local V8DebuggerImpl::collectionEntries(v8::Local context, v8::Local object) +v8::Local V8Debugger::collectionEntries(v8::Local context, v8::Local object) { if (!enabled()) { NOTREACHED(); @@ -731,7 +664,7 @@ v8::Local V8DebuggerImpl::collectionEntries(v8::Local co return entries; } -v8::Local V8DebuggerImpl::generatorObjectLocation(v8::Local object) +v8::Local V8Debugger::generatorObjectLocation(v8::Local object) { if (!enabled()) { NOTREACHED(); @@ -747,7 +680,7 @@ v8::Local V8DebuggerImpl::generatorObjectLocation(v8::Local V8DebuggerImpl::functionLocation(v8::Local context, v8::Local function) +v8::Local V8Debugger::functionLocation(v8::Local context, v8::Local function) { int scriptId = function->ScriptId(); if (scriptId == v8::UnboundScript::kNoScriptId) @@ -757,193 +690,39 @@ v8::Local V8DebuggerImpl::functionLocation(v8::Local con if (lineNumber == v8::Function::kLineOffsetNotFound || columnNumber == v8::Function::kLineOffsetNotFound) return v8::Null(m_isolate); v8::Local location = v8::Object::New(m_isolate); - if (!location->Set(context, v8InternalizedString("scriptId"), toV8String(m_isolate, String16::fromInteger(scriptId))).FromMaybe(false)) + if (!location->Set(context, toV8StringInternalized(m_isolate, "scriptId"), toV8String(m_isolate, String16::fromInteger(scriptId))).FromMaybe(false)) return v8::Null(m_isolate); - if (!location->Set(context, v8InternalizedString("lineNumber"), v8::Integer::New(m_isolate, lineNumber)).FromMaybe(false)) + if (!location->Set(context, toV8StringInternalized(m_isolate, "lineNumber"), v8::Integer::New(m_isolate, lineNumber)).FromMaybe(false)) return v8::Null(m_isolate); - if (!location->Set(context, v8InternalizedString("columnNumber"), v8::Integer::New(m_isolate, columnNumber)).FromMaybe(false)) + if (!location->Set(context, toV8StringInternalized(m_isolate, "columnNumber"), v8::Integer::New(m_isolate, columnNumber)).FromMaybe(false)) return v8::Null(m_isolate); if (!markAsInternal(context, location, V8InternalValueType::kLocation)) return v8::Null(m_isolate); return location; } -bool V8DebuggerImpl::isPaused() +bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } -v8::MaybeLocal V8DebuggerImpl::runCompiledScript(v8::Local context, v8::Local script) -{ - // TODO(dgozman): get rid of this check. - if (!m_client->isExecutionAllowed()) - return v8::MaybeLocal(); - - v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicrotasks); - int groupId = getGroupId(context); - if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) - agent->willExecuteScript(script->GetUnboundScript()->GetId()); - v8::MaybeLocal result = script->Run(context); - // Get agent from the map again, since it could have detached during script execution. - if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) - agent->didExecuteScript(); - return result; -} - -v8::MaybeLocal V8DebuggerImpl::callFunction(v8::Local function, v8::Local context, v8::Local receiver, int argc, v8::Local info[]) -{ - // TODO(dgozman): get rid of this check. - if (!m_client->isExecutionAllowed()) - return v8::MaybeLocal(); - - v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicrotasks); - int groupId = getGroupId(context); - if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) - agent->willExecuteScript(function->ScriptId()); - v8::MaybeLocal result = function->Call(context, receiver, argc, info); - // Get agent from the map again, since it could have detached during script execution. - if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) - agent->didExecuteScript(); - return result; -} - -v8::MaybeLocal V8DebuggerImpl::compileAndRunInternalScript(v8::Local context, v8::Local source) -{ - v8::Local script = compileInternalScript(context, source, String()); - if (script.IsEmpty()) - return v8::MaybeLocal(); - v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); - return script->Run(context); -} - -v8::Local V8DebuggerImpl::compileInternalScript(v8::Local context, v8::Local code, const String16& fileName) -{ - // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at - // 1, whereas v8 starts at 0. - v8::ScriptOrigin origin( - toV8String(m_isolate, fileName), - v8::Integer::New(m_isolate, 0), - v8::Integer::New(m_isolate, 0), - v8::False(m_isolate), // sharable - v8::Local(), - v8::True(m_isolate), // internal - toV8String(m_isolate, String16()), // sourceMap - v8::True(m_isolate)); // opaqueresource - v8::ScriptCompiler::Source source(code, origin); - v8::Local script; - if (!v8::ScriptCompiler::Compile(context, &source, v8::ScriptCompiler::kNoCompileOptions).ToLocal(&script)) - return v8::Local(); - return script; -} - -void V8DebuggerImpl::enableStackCapturingIfNeeded() -{ - if (!m_capturingStackTracesCount) - V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate, true); - ++m_capturingStackTracesCount; -} - -void V8DebuggerImpl::disableStackCapturingIfNeeded() -{ - if (!(--m_capturingStackTracesCount)) - V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate, false); -} - -V8ConsoleMessageStorage* V8DebuggerImpl::ensureConsoleMessageStorage(int contextGroupId) -{ - ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGroupId); - if (storageIt == m_consoleStorageMap.end()) - storageIt = m_consoleStorageMap.insert(std::make_pair(contextGroupId, wrapUnique(new V8ConsoleMessageStorage(this, contextGroupId)))).first; - return storageIt->second.get(); -} - -std::unique_ptr V8DebuggerImpl::createStackTrace(v8::Local stackTrace) +std::unique_ptr V8Debugger::createStackTrace(v8::Local stackTrace) { int contextGroupId = m_isolate->InContext() ? getGroupId(m_isolate->GetCurrentContext()) : 0; return V8StackTraceImpl::create(this, contextGroupId, stackTrace, V8StackTraceImpl::maxCallStackSizeToCapture); } -std::unique_ptr V8DebuggerImpl::connect(int contextGroupId, protocol::FrontendChannel* channel, V8InspectorSessionClient* client, const String16* state) -{ - DCHECK(m_sessions.find(contextGroupId) == m_sessions.cend()); - std::unique_ptr session = - V8InspectorSessionImpl::create(this, contextGroupId, channel, client, state); - m_sessions[contextGroupId] = session.get(); - return std::move(session); -} - -void V8DebuggerImpl::disconnect(V8InspectorSessionImpl* session) -{ - DCHECK(m_sessions.find(session->contextGroupId()) != m_sessions.end()); - m_sessions.erase(session->contextGroupId()); -} - -InspectedContext* V8DebuggerImpl::getContext(int groupId, int contextId) const -{ - ContextsByGroupMap::const_iterator contextGroupIt = m_contexts.find(groupId); - if (contextGroupIt == m_contexts.end()) - return nullptr; - - ContextByIdMap::iterator contextIt = contextGroupIt->second->find(contextId); - if (contextIt == contextGroupIt->second->end()) - return nullptr; - - return contextIt->second.get(); -} - -void V8DebuggerImpl::contextCreated(const V8ContextInfo& info) +int V8Debugger::markContext(const V8ContextInfo& info) { DCHECK(info.context->GetIsolate() == m_isolate); - // TODO(dgozman): make s_lastContextId non-static. - int contextId = atomicIncrement(&s_lastContextId); - String16 debugData = String16::fromInteger(info.contextGroupId) + "," + String16::fromInteger(contextId) + "," + (info.isDefault ? "default" : "nondefault"); - v8::HandleScope scope(m_isolate); + int contextId = ++m_lastContextId; + String16 debugData = String16::fromInteger(info.contextGroupId) + "," + String16::fromInteger(contextId) + "," + info.auxData; v8::Context::Scope contextScope(info.context); info.context->SetEmbedderData(static_cast(v8::Context::kDebugIdIndex), toV8String(m_isolate, debugData)); - - ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId); - if (contextIt == m_contexts.end()) - contextIt = m_contexts.insert(std::make_pair(info.contextGroupId, wrapUnique(new ContextByIdMap()))).first; - - const auto& contextById = contextIt->second; - - DCHECK(contextById->find(contextId) == contextById->cend()); - InspectedContext* context = new InspectedContext(this, info, contextId); - (*contextById)[contextId] = wrapUnique(context); - SessionMap::iterator sessionIt = m_sessions.find(info.contextGroupId); - if (sessionIt != m_sessions.end()) - sessionIt->second->runtimeAgent()->reportExecutionContextCreated(context); + return contextId; } -void V8DebuggerImpl::contextDestroyed(v8::Local context) -{ - int contextId = V8DebuggerImpl::contextId(context); - int contextGroupId = getGroupId(context); - - ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGroupId); - if (storageIt != m_consoleStorageMap.end()) - storageIt->second->contextDestroyed(contextId); - - InspectedContext* inspectedContext = getContext(contextGroupId, contextId); - if (!inspectedContext) - return; - - SessionMap::iterator iter = m_sessions.find(contextGroupId); - if (iter != m_sessions.end()) - iter->second->runtimeAgent()->reportExecutionContextDestroyed(inspectedContext); - discardInspectedContext(contextGroupId, contextId); -} - -void V8DebuggerImpl::resetContextGroup(int contextGroupId) -{ - m_consoleStorageMap.erase(contextGroupId); - SessionMap::iterator session = m_sessions.find(contextGroupId); - if (session != m_sessions.end()) - session->second->reset(); - m_contexts.erase(contextGroupId); -} - -void V8DebuggerImpl::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) +void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { if (depth <= 0) m_maxAsyncCallStackDepthMap.erase(agent); @@ -958,18 +737,12 @@ void V8DebuggerImpl::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int dept if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return; - - if (maxAsyncCallStackDepth && !m_maxAsyncCallStackDepth) - m_client->enableAsyncInstrumentation(); - else if (!maxAsyncCallStackDepth && m_maxAsyncCallStackDepth) - m_client->disableAsyncInstrumentation(); - m_maxAsyncCallStackDepth = maxAsyncCallStackDepth; if (!maxAsyncCallStackDepth) allAsyncTasksCanceled(); } -void V8DebuggerImpl::asyncTaskScheduled(const String16& taskName, void* task, bool recurring) +void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, bool recurring) { if (!m_maxAsyncCallStackDepth) return; @@ -983,7 +756,7 @@ void V8DebuggerImpl::asyncTaskScheduled(const String16& taskName, void* task, bo } } -void V8DebuggerImpl::asyncTaskCanceled(void* task) +void V8Debugger::asyncTaskCanceled(void* task) { if (!m_maxAsyncCallStackDepth) return; @@ -991,12 +764,10 @@ void V8DebuggerImpl::asyncTaskCanceled(void* task) m_recurringTasks.erase(task); } -void V8DebuggerImpl::asyncTaskStarted(void* task) +void V8Debugger::asyncTaskStarted(void* task) { - // Not enabled, return. if (!m_maxAsyncCallStackDepth) return; - m_currentTasks.push_back(task); AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(task); // Needs to support following order of events: @@ -1012,7 +783,7 @@ void V8DebuggerImpl::asyncTaskStarted(void* task) m_currentStacks.push_back(std::move(stack)); } -void V8DebuggerImpl::asyncTaskFinished(void* task) +void V8Debugger::asyncTaskFinished(void* task) { if (!m_maxAsyncCallStackDepth) return; @@ -1028,7 +799,7 @@ void V8DebuggerImpl::asyncTaskFinished(void* task) m_asyncTaskStacks.erase(task); } -void V8DebuggerImpl::allAsyncTasksCanceled() +void V8Debugger::allAsyncTasksCanceled() { m_asyncTaskStacks.clear(); m_recurringTasks.clear(); @@ -1036,71 +807,18 @@ void V8DebuggerImpl::allAsyncTasksCanceled() m_currentTasks.clear(); } -void V8DebuggerImpl::willExecuteScript(v8::Local context, int scriptId) -{ - if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(context)) - agent->willExecuteScript(scriptId); -} - -void V8DebuggerImpl::didExecuteScript(v8::Local context) -{ - if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(context)) - agent->didExecuteScript(); -} - -void V8DebuggerImpl::idleStarted() -{ - m_isolate->GetCpuProfiler()->SetIdle(true); -} - -void V8DebuggerImpl::idleFinished() -{ - m_isolate->GetCpuProfiler()->SetIdle(false); -} - -void V8DebuggerImpl::logToConsole(v8::Local context, v8::Local arg1, v8::Local arg2) -{ - int contextGroupId = getGroupId(context); - InspectedContext* inspectedContext = getContext(contextGroupId, contextId(context)); - if (!inspectedContext) - return; - std::vector> arguments; - if (!arg1.IsEmpty()) - arguments.push_back(arg1); - if (!arg2.IsEmpty()) - arguments.push_back(arg2); - ensureConsoleMessageStorage(contextGroupId)->addMessage(V8ConsoleMessage::createForConsoleAPI(m_client->currentTimeMS(), ConsoleAPIType::kLog, arguments, captureStackTrace(false), inspectedContext)); -} - -void V8DebuggerImpl::exceptionThrown(int contextGroupId, const String16& errorMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr stackTrace, int scriptId) +void V8Debugger::muteScriptParsedEvents() { - unsigned exceptionId = ++m_lastExceptionId; - std::unique_ptr consoleMessage = V8ConsoleMessage::createForException(m_client->currentTimeMS(), errorMessage, url, lineNumber, columnNumber, std::move(stackTrace), scriptId, m_isolate, 0, v8::Local(), exceptionId); - ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMessage)); + ++m_ignoreScriptParsedEventsCounter; } -unsigned V8DebuggerImpl::promiseRejected(v8::Local context, const String16& errorMessage, v8::Local exception, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr stackTrace, int scriptId) +void V8Debugger::unmuteScriptParsedEvents() { - int contextGroupId = getGroupId(context); - if (!contextGroupId) - return 0; - unsigned exceptionId = ++m_lastExceptionId; - std::unique_ptr consoleMessage = V8ConsoleMessage::createForException(m_client->currentTimeMS(), errorMessage, url, lineNumber, columnNumber, std::move(stackTrace), scriptId, m_isolate, contextId(context), exception, exceptionId); - ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMessage)); - return exceptionId; -} - -void V8DebuggerImpl::promiseRejectionRevoked(v8::Local context, unsigned promiseRejectionId) -{ - int contextGroupId = getGroupId(context); - if (!contextGroupId) - return; - - std::unique_ptr consoleMessage = V8ConsoleMessage::createForRevokedException(m_client->currentTimeMS(), "Handler added to rejected promise", promiseRejectionId); - ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMessage)); + --m_ignoreScriptParsedEventsCounter; + DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); } -std::unique_ptr V8DebuggerImpl::captureStackTrace(bool fullStack) +std::unique_ptr V8Debugger::captureStackTrace(bool fullStack) { if (!m_isolate->InContext()) return nullptr; @@ -1111,41 +829,10 @@ std::unique_ptr V8DebuggerImpl::captureStackTrace(bool fullStack) return nullptr; size_t stackSize = fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; - SessionMap::iterator sessionIt = m_sessions.find(contextGroupId); - if (sessionIt != m_sessions.end() && sessionIt->second->runtimeAgent()->enabled()) + if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; return V8StackTraceImpl::capture(this, contextGroupId, stackSize); } -v8::Local V8DebuggerImpl::regexContext() -{ - if (m_regexContext.IsEmpty()) - m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate)); - return m_regexContext.Get(m_isolate); -} - -void V8DebuggerImpl::discardInspectedContext(int contextGroupId, int contextId) -{ - if (!getContext(contextGroupId, contextId)) - return; - m_contexts[contextGroupId]->erase(contextId); - if (m_contexts[contextGroupId]->empty()) - m_contexts.erase(contextGroupId); -} - -const V8DebuggerImpl::ContextByIdMap* V8DebuggerImpl::contextGroup(int contextGroupId) -{ - ContextsByGroupMap::iterator iter = m_contexts.find(contextGroupId); - return iter == m_contexts.end() ? nullptr : iter->second.get(); -} - -V8InspectorSessionImpl* V8DebuggerImpl::sessionForContextGroup(int contextGroupId) -{ - if (!contextGroupId) - return nullptr; - SessionMap::iterator iter = m_sessions.find(contextGroupId); - return iter == m_sessions.end() ? nullptr : iter->second; -} - } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Debugger.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Debugger.h new file mode 100644 index 00000000000..3ec68a8708b --- /dev/null +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Debugger.h @@ -0,0 +1,131 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8Debugger_h +#define V8Debugger_h + +#include "platform/inspector_protocol/Allocator.h" +#include "platform/inspector_protocol/Maybe.h" +#include "platform/inspector_protocol/Platform.h" +#include "platform/v8_inspector/JavaScriptCallFrame.h" +#include "platform/v8_inspector/V8DebuggerScript.h" +#include "platform/v8_inspector/protocol/Runtime.h" +#include "platform/v8_inspector/public/V8ContextInfo.h" + +#include +#include +#include + +namespace blink { + +struct ScriptBreakpoint; +class V8DebuggerAgentImpl; +class V8InspectorImpl; +class V8StackTraceImpl; + +class V8Debugger { + PROTOCOL_DISALLOW_COPY(V8Debugger); +public: + V8Debugger(v8::Isolate*, V8InspectorImpl*); + ~V8Debugger(); + + static int contextId(v8::Local); + static int getGroupId(v8::Local); + int markContext(const V8ContextInfo&); + + bool enabled() const; + + String16 setBreakpoint(const String16& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation); + void removeBreakpoint(const String16& breakpointId); + void setBreakpointsActivated(bool); + bool breakpointsActivated() const { return m_breakpointsActivated; } + + enum PauseOnExceptionsState { + DontPauseOnExceptions, + PauseOnAllExceptions, + PauseOnUncaughtExceptions + }; + PauseOnExceptionsState getPauseOnExceptionsState(); + void setPauseOnExceptionsState(PauseOnExceptionsState); + void setPauseOnNextStatement(bool); + bool canBreakProgram(); + void breakProgram(); + void continueProgram(); + void stepIntoStatement(); + void stepOverStatement(); + void stepOutOfFunction(); + void clearStepping(); + + bool setScriptSource(const String16& sourceID, v8::Local newSource, bool preview, ErrorString*, protocol::Maybe*, JavaScriptCallFrames* newCallFrames, protocol::Maybe* stackChanged); + JavaScriptCallFrames currentCallFrames(int limit = 0); + + // Each script inherits debug data from v8::Context where it has been compiled. + // Only scripts whose debug data matches |contextGroupId| will be reported. + // Passing 0 will result in reporting all scripts. + void getCompiledScripts(int contextGroupId, std::vector>&); + void enable(); + void disable(); + + bool isPaused(); + v8::Local pausedContext() { return m_pausedContext; } + + int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; } + V8StackTraceImpl* currentAsyncCallChain(); + void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int); + std::unique_ptr createStackTrace(v8::Local); + std::unique_ptr captureStackTrace(bool fullStack); + + v8::MaybeLocal functionScopes(v8::Local); + v8::MaybeLocal internalProperties(v8::Local, v8::Local); + + void asyncTaskScheduled(const String16& taskName, void* task, bool recurring); + void asyncTaskCanceled(void* task); + void asyncTaskStarted(void* task); + void asyncTaskFinished(void* task); + void allAsyncTasksCanceled(); + + void muteScriptParsedEvents(); + void unmuteScriptParsedEvents(); + +private: + void compileDebuggerScript(); + v8::MaybeLocal callDebuggerMethod(const char* functionName, int argc, v8::Local argv[]); + v8::Local debuggerContext() const; + void clearBreakpoints(); + + static void breakProgramCallback(const v8::FunctionCallbackInfo&); + void handleProgramBreak(v8::Local pausedContext, v8::Local executionState, v8::Local exception, v8::Local hitBreakpoints, bool isPromiseRejection = false); + static void v8DebugEventCallback(const v8::Debug::EventDetails&); + v8::Local callInternalGetterFunction(v8::Local, const char* functionName); + void handleV8DebugEvent(const v8::Debug::EventDetails&); + void handleV8AsyncTaskEvent(v8::Local, v8::Local executionState, v8::Local eventData); + + v8::Local collectionEntries(v8::Local, v8::Local); + v8::Local generatorObjectLocation(v8::Local); + v8::Local functionLocation(v8::Local, v8::Local); + + v8::Isolate* m_isolate; + V8InspectorImpl* m_inspector; + int m_lastContextId; + int m_enableCount; + bool m_breakpointsActivated; + v8::Global m_debuggerScript; + v8::Global m_debuggerContext; + v8::Local m_executionState; + v8::Local m_pausedContext; + bool m_runningNestedMessageLoop; + int m_ignoreScriptParsedEventsCounter; + + using AsyncTaskToStackTrace = protocol::HashMap>; + AsyncTaskToStackTrace m_asyncTaskStacks; + protocol::HashSet m_recurringTasks; + int m_maxAsyncCallStackDepth; + std::vector m_currentTasks; + std::vector> m_currentStacks; + protocol::HashMap m_maxAsyncCallStackDepthMap; +}; + +} // namespace blink + +#endif // V8Debugger_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.cpp index 2b232efc2e7..584c0164e03 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.cpp @@ -4,6 +4,7 @@ #include "platform/v8_inspector/V8DebuggerAgentImpl.h" +#include "platform/inspector_protocol/Parser.h" #include "platform/inspector_protocol/String16.h" #include "platform/inspector_protocol/Values.h" #include "platform/v8_inspector/InjectedScript.h" @@ -11,14 +12,15 @@ #include "platform/v8_inspector/JavaScriptCallFrame.h" #include "platform/v8_inspector/RemoteObjectId.h" #include "platform/v8_inspector/ScriptBreakpoint.h" +#include "platform/v8_inspector/V8Debugger.h" +#include "platform/v8_inspector/V8DebuggerScript.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8Regex.h" #include "platform/v8_inspector/V8RuntimeAgentImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8ContentSearchUtil.h" -#include "platform/v8_inspector/public/V8Debugger.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" #include @@ -51,6 +53,7 @@ static const char skipAllPauses[] = "skipAllPauses"; } // namespace DebuggerAgentState; static const int maxSkipStepFrameCount = 128; +static const char backtraceObjectGroup[] = "backtrace"; static String16 breakpointIdSuffix(V8DebuggerAgentImpl::BreakpointSource source) { @@ -93,12 +96,13 @@ static std::unique_ptr buildProtocolLocation(const } V8DebuggerAgentImpl::V8DebuggerAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state) - : m_debugger(session->debugger()) + : m_inspector(session->inspector()) + , m_debugger(m_inspector->debugger()) , m_session(session) , m_enabled(false) , m_state(state) , m_frontend(frontendChannel) - , m_isolate(m_debugger->isolate()) + , m_isolate(m_inspector->isolate()) , m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other) , m_scheduledDebuggerStep(NoStep) , m_skipNextDebuggerStepOut(false) @@ -127,19 +131,19 @@ bool V8DebuggerAgentImpl::checkEnabled(ErrorString* errorString) void V8DebuggerAgentImpl::enable() { - // debugger().addListener may result in reporting all parsed scripts to + // m_inspector->addListener may result in reporting all parsed scripts to // the agent so it should already be in enabled state by then. m_enabled = true; m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); - debugger().debuggerAgentEnabled(); + m_debugger->enable(); std::vector> compiledScripts; - debugger().getCompiledScripts(m_session->contextGroupId(), compiledScripts); + m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts); for (size_t i = 0; i < compiledScripts.size(); i++) didParseSource(std::move(compiledScripts[i]), true); // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends - debugger().setBreakpointsActivated(true); + m_debugger->setBreakpointsActivated(true); } bool V8DebuggerAgentImpl::enabled() @@ -152,7 +156,7 @@ void V8DebuggerAgentImpl::enable(ErrorString* errorString) if (enabled()) return; - if (!m_session->client()->canExecuteScripts()) { + if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId())) { *errorString = "Script execution is prohibited"; return; } @@ -166,12 +170,12 @@ void V8DebuggerAgentImpl::disable(ErrorString*) return; m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, protocol::DictionaryValue::create()); - m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, V8DebuggerImpl::DontPauseOnExceptions); + m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, V8Debugger::DontPauseOnExceptions); m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0); if (!m_pausedContext.IsEmpty()) - debugger().continueProgram(); - debugger().debuggerAgentDisabled(); + m_debugger->continueProgram(); + m_debugger->disable(); m_pausedContext.Reset(); JavaScriptCallFrames emptyCallFrames; m_pausedCallFrames.swap(emptyCallFrames); @@ -200,13 +204,13 @@ void V8DebuggerAgentImpl::restore() DCHECK(!m_enabled); if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false)) return; - if (!m_session->client()->canExecuteScripts()) + if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId())) return; enable(); ErrorString error; - int pauseState = V8DebuggerImpl::DontPauseOnExceptions; + int pauseState = V8Debugger::DontPauseOnExceptions; m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState); setPauseOnExceptionsImpl(&error, pauseState); DCHECK(error.isEmpty()); @@ -228,7 +232,7 @@ void V8DebuggerAgentImpl::setBreakpointsActive(ErrorString* errorString, bool ac { if (!checkEnabled(errorString)) return; - debugger().setBreakpointsActivated(active); + m_debugger->setBreakpointsActivated(active); } void V8DebuggerAgentImpl::setSkipAllPauses(ErrorString*, bool skipped) @@ -248,10 +252,10 @@ static std::unique_ptr buildObjectForBreakpointCookie return breakpointObject; } -static bool matches(V8DebuggerImpl* debugger, const String16& url, const String16& pattern, bool isRegex) +static bool matches(V8InspectorImpl* inspector, const String16& url, const String16& pattern, bool isRegex) { if (isRegex) { - V8Regex regex(debugger, pattern, true); + V8Regex regex(inspector, pattern, true); return regex.match(url) != -1; } return url == pattern; @@ -300,7 +304,7 @@ void V8DebuggerAgentImpl::setBreakpointByUrl(ErrorString* errorString, ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); for (const auto& script : m_scripts) { - if (!matches(m_debugger, script.second->sourceURL(), url, isRegex)) + if (!matches(m_inspector, script.second->sourceURL(), url, isRegex)) continue; std::unique_ptr location = resolveBreakpoint(breakpointId, script.first, breakpoint, UserBreakpointSource); if (location) @@ -366,7 +370,7 @@ void V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) for (size_t i = 0; i < ids.size(); ++i) { const String16& debuggerBreakpointId = ids[i]; - debugger().removeBreakpoint(debuggerBreakpointId); + m_debugger->removeBreakpoint(debuggerBreakpointId); m_serverBreakpoints.erase(debuggerBreakpointId); } m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId); @@ -379,7 +383,7 @@ void V8DebuggerAgentImpl::continueToLocation(ErrorString* errorString, if (!checkEnabled(errorString)) return; if (!m_continueToLocationBreakpointId.isEmpty()) { - debugger().removeBreakpoint(m_continueToLocationBreakpointId); + m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); m_continueToLocationBreakpointId = ""; } @@ -391,7 +395,7 @@ void V8DebuggerAgentImpl::continueToLocation(ErrorString* errorString, return; ScriptBreakpoint breakpoint(lineNumber, columnNumber, ""); - m_continueToLocationBreakpointId = debugger().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber, interstateLocationOpt.fromMaybe(false)); + m_continueToLocationBreakpointId = m_debugger->setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber, interstateLocationOpt.fromMaybe(false)); resume(errorString); } @@ -399,7 +403,7 @@ void V8DebuggerAgentImpl::getBacktrace(ErrorString* errorString, std::unique_ptr { if (!assertPaused(errorString)) return; - JavaScriptCallFrames frames = debugger().currentCallFrames(); + JavaScriptCallFrames frames = m_debugger->currentCallFrames(); m_pausedCallFrames.swap(frames); *callFrames = currentCallFrames(errorString); if (!*callFrames) @@ -410,7 +414,7 @@ void V8DebuggerAgentImpl::getBacktrace(ErrorString* errorString, std::unique_ptr bool V8DebuggerAgentImpl::isCurrentCallStackEmptyOrBlackboxed() { DCHECK(enabled()); - JavaScriptCallFrames callFrames = debugger().currentCallFrames(); + JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(); for (size_t index = 0; index < callFrames.size(); ++index) { if (!isCallFrameWithUnknownScriptOrBlackboxed(callFrames[index].get())) return false; @@ -498,7 +502,7 @@ std::unique_ptr V8DebuggerAgentImpl::resolveBreakp int actualLineNumber; int actualColumnNumber; - String16 debuggerBreakpointId = debugger().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false); + String16 debuggerBreakpointId = m_debugger->setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false); if (debuggerBreakpointId.isEmpty()) return nullptr; @@ -516,10 +520,15 @@ void V8DebuggerAgentImpl::searchInContent(ErrorString* error, const String16& sc { v8::HandleScope handles(m_isolate); ScriptsMap::iterator it = m_scripts.find(scriptId); - if (it != m_scripts.end()) - *results = V8ContentSearchUtil::searchInTextByLines(m_session, toProtocolString(it->second->source(m_isolate)), query, optionalCaseSensitive.fromMaybe(false), optionalIsRegex.fromMaybe(false)); - else + if (it == m_scripts.end()) { *error = String16("No script for id: " + scriptId); + return; + } + + std::vector> matches = searchInTextByLinesImpl(m_session, toProtocolString(it->second->source(m_isolate)), query, optionalCaseSensitive.fromMaybe(false), optionalIsRegex.fromMaybe(false)); + *results = protocol::Array::create(); + for (size_t i = 0; i < matches.size(); ++i) + (*results)->addItem(std::move(matches[i])); } void V8DebuggerAgentImpl::setScriptSource(ErrorString* errorString, @@ -536,7 +545,7 @@ void V8DebuggerAgentImpl::setScriptSource(ErrorString* errorString, v8::HandleScope handles(m_isolate); v8::Local newSource = toV8String(m_isolate, newContent); - if (!debugger().setScriptSource(scriptId, newSource, preview.fromMaybe(false), errorString, optOutCompileError, &m_pausedCallFrames, stackChanged)) + if (!m_debugger->setScriptSource(scriptId, newSource, preview.fromMaybe(false), errorString, optOutCompileError, &m_pausedCallFrames, stackChanged)) return; ScriptsMap::iterator it = m_scripts.find(scriptId); @@ -557,7 +566,7 @@ void V8DebuggerAgentImpl::restartFrame(ErrorString* errorString, { if (!assertPaused(errorString)) return; - InjectedScript::CallFrameScope scope(errorString, m_debugger, m_session->contextGroupId(), callFrameId); + InjectedScript::CallFrameScope scope(errorString, m_inspector, m_session->contextGroupId(), callFrameId); if (!scope.initialize()) return; if (scope.frameOrdinal() >= m_pausedCallFrames.size()) { @@ -571,7 +580,7 @@ void V8DebuggerAgentImpl::restartFrame(ErrorString* errorString, *errorString = "Internal error"; return; } - JavaScriptCallFrames frames = debugger().currentCallFrames(); + JavaScriptCallFrames frames = m_debugger->currentCallFrames(); m_pausedCallFrames.swap(frames); *newCallFrames = currentCallFrames(errorString); @@ -595,48 +604,48 @@ void V8DebuggerAgentImpl::getScriptSource(ErrorString* error, const String16& sc void V8DebuggerAgentImpl::schedulePauseOnNextStatement(const String16& breakReason, std::unique_ptr data) { - if (!enabled() || m_scheduledDebuggerStep == StepInto || m_javaScriptPauseScheduled || debugger().isPaused() || !debugger().breakpointsActivated()) + if (!enabled() || m_scheduledDebuggerStep == StepInto || m_javaScriptPauseScheduled || m_debugger->isPaused() || !m_debugger->breakpointsActivated()) return; m_breakReason = breakReason; m_breakAuxData = std::move(data); m_pausingOnNativeEvent = true; m_skipNextDebuggerStepOut = false; - debugger().setPauseOnNextStatement(true); + m_debugger->setPauseOnNextStatement(true); } void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { DCHECK(enabled()); - if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || debugger().isPaused()) + if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || m_debugger->isPaused()) return; clearBreakDetails(); m_pausingOnNativeEvent = false; m_skippedStepFrameCount = 0; m_recursionLevelForStepFrame = 0; - debugger().setPauseOnNextStatement(true); + m_debugger->setPauseOnNextStatement(true); } void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { - if (m_javaScriptPauseScheduled || debugger().isPaused()) + if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return; clearBreakDetails(); m_pausingOnNativeEvent = false; - debugger().setPauseOnNextStatement(false); + m_debugger->setPauseOnNextStatement(false); } void V8DebuggerAgentImpl::pause(ErrorString* errorString) { if (!checkEnabled(errorString)) return; - if (m_javaScriptPauseScheduled || debugger().isPaused()) + if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return; clearBreakDetails(); m_javaScriptPauseScheduled = true; m_scheduledDebuggerStep = NoStep; m_skippedStepFrameCount = 0; m_steppingFromFramework = false; - debugger().setPauseOnNextStatement(true); + m_debugger->setPauseOnNextStatement(true); } void V8DebuggerAgentImpl::resume(ErrorString* errorString) @@ -645,8 +654,8 @@ void V8DebuggerAgentImpl::resume(ErrorString* errorString) return; m_scheduledDebuggerStep = NoStep; m_steppingFromFramework = false; - m_session->releaseObjectGroup(V8InspectorSession::backtraceObjectGroup); - debugger().continueProgram(); + m_session->releaseObjectGroup(backtraceObjectGroup); + m_debugger->continueProgram(); } void V8DebuggerAgentImpl::stepOver(ErrorString* errorString) @@ -661,8 +670,8 @@ void V8DebuggerAgentImpl::stepOver(ErrorString* errorString) } m_scheduledDebuggerStep = StepOver; m_steppingFromFramework = isTopPausedCallFrameBlackboxed(); - m_session->releaseObjectGroup(V8InspectorSession::backtraceObjectGroup); - debugger().stepOverStatement(); + m_session->releaseObjectGroup(backtraceObjectGroup); + m_debugger->stepOverStatement(); } void V8DebuggerAgentImpl::stepInto(ErrorString* errorString) @@ -671,8 +680,8 @@ void V8DebuggerAgentImpl::stepInto(ErrorString* errorString) return; m_scheduledDebuggerStep = StepInto; m_steppingFromFramework = isTopPausedCallFrameBlackboxed(); - m_session->releaseObjectGroup(V8InspectorSession::backtraceObjectGroup); - debugger().stepIntoStatement(); + m_session->releaseObjectGroup(backtraceObjectGroup); + m_debugger->stepIntoStatement(); } void V8DebuggerAgentImpl::stepOut(ErrorString* errorString) @@ -683,21 +692,21 @@ void V8DebuggerAgentImpl::stepOut(ErrorString* errorString) m_skipNextDebuggerStepOut = false; m_recursionLevelForStepOut = 1; m_steppingFromFramework = isTopPausedCallFrameBlackboxed(); - m_session->releaseObjectGroup(V8InspectorSession::backtraceObjectGroup); - debugger().stepOutOfFunction(); + m_session->releaseObjectGroup(backtraceObjectGroup); + m_debugger->stepOutOfFunction(); } void V8DebuggerAgentImpl::setPauseOnExceptions(ErrorString* errorString, const String16& stringPauseState) { if (!checkEnabled(errorString)) return; - V8DebuggerImpl::PauseOnExceptionsState pauseState; + V8Debugger::PauseOnExceptionsState pauseState; if (stringPauseState == "none") { - pauseState = V8DebuggerImpl::DontPauseOnExceptions; + pauseState = V8Debugger::DontPauseOnExceptions; } else if (stringPauseState == "all") { - pauseState = V8DebuggerImpl::PauseOnAllExceptions; + pauseState = V8Debugger::PauseOnAllExceptions; } else if (stringPauseState == "uncaught") { - pauseState = V8DebuggerImpl::PauseOnUncaughtExceptions; + pauseState = V8Debugger::PauseOnUncaughtExceptions; } else { *errorString = "Unknown pause on exceptions mode: " + stringPauseState; return; @@ -707,8 +716,8 @@ void V8DebuggerAgentImpl::setPauseOnExceptions(ErrorString* errorString, const S void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState) { - debugger().setPauseOnExceptionsState(static_cast(pauseState)); - if (debugger().getPauseOnExceptionsState() != pauseState) + m_debugger->setPauseOnExceptionsState(static_cast(pauseState)); + if (m_debugger->getPauseOnExceptionsState() != pauseState) *errorString = "Internal error. Could not change pause on exceptions state"; else m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState); @@ -728,7 +737,7 @@ void V8DebuggerAgentImpl::evaluateOnCallFrame(ErrorString* errorString, { if (!assertPaused(errorString)) return; - InjectedScript::CallFrameScope scope(errorString, m_debugger, m_session->contextGroupId(), callFrameId); + InjectedScript::CallFrameScope scope(errorString, m_inspector, m_session->contextGroupId(), callFrameId); if (!scope.initialize()) return; if (scope.frameOrdinal() >= m_pausedCallFrames.size()) { @@ -767,7 +776,7 @@ void V8DebuggerAgentImpl::setVariableValue(ErrorString* errorString, return; if (!assertPaused(errorString)) return; - InjectedScript::CallFrameScope scope(errorString, m_debugger, m_session->contextGroupId(), callFrameId); + InjectedScript::CallFrameScope scope(errorString, m_inspector, m_session->contextGroupId(), callFrameId); if (!scope.initialize()) return; @@ -818,7 +827,7 @@ void V8DebuggerAgentImpl::setBlackboxPatterns(ErrorString* errorString, std::uni bool V8DebuggerAgentImpl::setBlackboxPattern(ErrorString* errorString, const String16& pattern) { - std::unique_ptr regex(new V8Regex(m_debugger, pattern, true /** caseSensitive */, false /** multiline */)); + std::unique_ptr regex(new V8Regex(m_inspector, pattern, true /** caseSensitive */, false /** multiline */)); if (!regex->isValid()) { *errorString = "Pattern parser error: " + regex->errorMessage(); return false; @@ -873,9 +882,6 @@ void V8DebuggerAgentImpl::willExecuteScript(int scriptId) // Fast return. if (m_scheduledDebuggerStep != StepInto) return; - // Skip unknown scripts (e.g. InjectedScript). - if (m_scripts.find(String16::fromInteger(scriptId)) == m_scripts.end()) - return; schedulePauseOnNextStatementIfSteppingInto(); } @@ -886,9 +892,9 @@ void V8DebuggerAgentImpl::didExecuteScript() void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) { - if (m_javaScriptPauseScheduled && !m_skipAllPauses && !debugger().isPaused()) { + if (m_javaScriptPauseScheduled && !m_skipAllPauses && !m_debugger->isPaused()) { // Do not ever loose user's pause request until we have actually paused. - debugger().setPauseOnNextStatement(true); + m_debugger->setPauseOnNextStatement(true); } if (m_scheduledDebuggerStep == StepOut) { m_recursionLevelForStepOut += step; @@ -910,7 +916,7 @@ void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) // from the old StepFrame. m_skippedStepFrameCount = 0; if (m_scheduledDebuggerStep == NoStep) - debugger().clearStepping(); + m_debugger->clearStepping(); else if (m_scheduledDebuggerStep == StepOut) m_skipNextDebuggerStepOut = true; } @@ -947,12 +953,12 @@ std::unique_ptr> V8DebuggerAgentImpl::currentCallFrames(ErrorSt if (hasInternalError(errorString, !details->Get(debuggerContext, toV8StringInternalized(m_isolate, "scopeChain")).ToLocal(&scopeChain) || !scopeChain->IsArray())) return Array::create(); v8::Local scopeChainArray = scopeChain.As(); - if (!injectedScript->wrapPropertyInArray(errorString, scopeChainArray, toV8StringInternalized(m_isolate, "object"), V8InspectorSession::backtraceObjectGroup)) + if (!injectedScript->wrapPropertyInArray(errorString, scopeChainArray, toV8StringInternalized(m_isolate, "object"), backtraceObjectGroup)) return Array::create(); - if (!injectedScript->wrapObjectProperty(errorString, details, toV8StringInternalized(m_isolate, "this"), V8InspectorSession::backtraceObjectGroup)) + if (!injectedScript->wrapObjectProperty(errorString, details, toV8StringInternalized(m_isolate, "this"), backtraceObjectGroup)) return Array::create(); if (details->Has(debuggerContext, toV8StringInternalized(m_isolate, "returnValue")).FromMaybe(false)) { - if (!injectedScript->wrapObjectProperty(errorString, details, toV8StringInternalized(m_isolate, "returnValue"), V8InspectorSession::backtraceObjectGroup)) + if (!injectedScript->wrapObjectProperty(errorString, details, toV8StringInternalized(m_isolate, "returnValue"), backtraceObjectGroup)) return Array::create(); } } else { @@ -992,17 +998,19 @@ void V8DebuggerAgentImpl::didParseSource(std::unique_ptr scrip String16 scriptSource = toProtocolString(script->source(m_isolate)); bool isDeprecatedSourceURL = false; if (!success) - script->setSourceURL(V8ContentSearchUtil::findSourceURL(scriptSource, false, &isDeprecatedSourceURL)); + script->setSourceURL(findSourceURL(scriptSource, false, &isDeprecatedSourceURL)); else if (script->hasSourceURL()) - V8ContentSearchUtil::findSourceURL(scriptSource, false, &isDeprecatedSourceURL); + findSourceURL(scriptSource, false, &isDeprecatedSourceURL); bool isDeprecatedSourceMappingURL = false; if (!success) - script->setSourceMappingURL(V8ContentSearchUtil::findSourceMapURL(scriptSource, false, &isDeprecatedSourceMappingURL)); + script->setSourceMappingURL(findSourceMapURL(scriptSource, false, &isDeprecatedSourceMappingURL)); else if (!script->sourceMappingURL().isEmpty()) - V8ContentSearchUtil::findSourceMapURL(scriptSource, false, &isDeprecatedSourceMappingURL); + findSourceMapURL(scriptSource, false, &isDeprecatedSourceMappingURL); - bool isContentScript = script->isContentScript(); + std::unique_ptr executionContextAuxData; + if (!script->executionContextAuxData().isEmpty()) + executionContextAuxData = protocol::DictionaryValue::cast(parseJSON(script->executionContextAuxData())); bool isInternalScript = script->isInternalScript(); bool isLiveEdit = script->isLiveEdit(); bool hasSourceURL = script->hasSourceURL(); @@ -1011,15 +1019,15 @@ void V8DebuggerAgentImpl::didParseSource(std::unique_ptr scrip bool deprecatedCommentWasUsed = isDeprecatedSourceURL || isDeprecatedSourceMappingURL; const Maybe& sourceMapURLParam = script->sourceMappingURL(); - const bool* isContentScriptParam = isContentScript ? &isContentScript : nullptr; + const Maybe& executionContextAuxDataParam(std::move(executionContextAuxData)); const bool* isInternalScriptParam = isInternalScript ? &isInternalScript : nullptr; const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr; const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr; const bool* deprecatedCommentWasUsedParam = deprecatedCommentWasUsed ? &deprecatedCommentWasUsed : nullptr; if (success) - m_frontend.scriptParsed(scriptId, scriptURL, script->startLine(), script->startColumn(), script->endLine(), script->endColumn(), script->executionContextId(), script->hash(), isContentScriptParam, isInternalScriptParam, isLiveEditParam, sourceMapURLParam, hasSourceURLParam, deprecatedCommentWasUsedParam); + m_frontend.scriptParsed(scriptId, scriptURL, script->startLine(), script->startColumn(), script->endLine(), script->endColumn(), script->executionContextId(), script->hash(), executionContextAuxDataParam, isInternalScriptParam, isLiveEditParam, sourceMapURLParam, hasSourceURLParam, deprecatedCommentWasUsedParam); else - m_frontend.scriptFailedToParse(scriptId, scriptURL, script->startLine(), script->startColumn(), script->endLine(), script->endColumn(), script->executionContextId(), script->hash(), isContentScriptParam, isInternalScriptParam, sourceMapURLParam, hasSourceURLParam, deprecatedCommentWasUsedParam); + m_frontend.scriptFailedToParse(scriptId, scriptURL, script->startLine(), script->startColumn(), script->endLine(), script->endColumn(), script->executionContextId(), script->hash(), executionContextAuxDataParam, isInternalScriptParam, sourceMapURLParam, hasSourceURLParam, deprecatedCommentWasUsedParam); m_scripts[scriptId] = std::move(script); @@ -1037,7 +1045,7 @@ void V8DebuggerAgentImpl::didParseSource(std::unique_ptr scrip breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); String16 url; breakpointObject->getString(DebuggerAgentState::url, &url); - if (!matches(m_debugger, scriptURL, url, isRegex)) + if (!matches(m_inspector, scriptURL, url, isRegex)) continue; ScriptBreakpoint breakpoint; breakpointObject->getInteger(DebuggerAgentState::lineNumber, &breakpoint.lineNumber); @@ -1051,9 +1059,16 @@ void V8DebuggerAgentImpl::didParseSource(std::unique_ptr scrip V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::Local context, v8::Local exception, const std::vector& hitBreakpoints, bool isPromiseRejection) { - JavaScriptCallFrames callFrames = debugger().currentCallFrames(1); + JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1); JavaScriptCallFrame* topCallFrame = !callFrames.empty() ? callFrames.begin()->get() : nullptr; + // Skip pause in internal scripts (e.g. InjectedScriptSource.js). + if (topCallFrame) { + ScriptsMap::iterator it = m_scripts.find(String16::fromInteger(topCallFrame->sourceID())); + if (it != m_scripts.end() && it->second->isInternalScript()) + return RequestStepFrame; + } + V8DebuggerAgentImpl::SkipPauseRequest result; if (m_skipAllPauses) result = RequestContinue; @@ -1074,18 +1089,18 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::LocalcurrentCallFrames(); m_pausedCallFrames.swap(frames); m_pausedContext.Reset(m_isolate, context); v8::HandleScope handles(m_isolate); if (!exception.IsEmpty()) { ErrorString ignored; - InjectedScript* injectedScript = m_session->findInjectedScript(&ignored, V8DebuggerImpl::contextId(context)); + InjectedScript* injectedScript = m_session->findInjectedScript(&ignored, V8Debugger::contextId(context)); if (injectedScript) { m_breakReason = isPromiseRejection ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection : protocol::Debugger::Paused::ReasonEnum::Exception; ErrorString errorString; - auto obj = injectedScript->wrapObject(&errorString, exception, V8InspectorSession::backtraceObjectGroup); + auto obj = injectedScript->wrapObject(&errorString, exception, backtraceObjectGroup); m_breakAuxData = obj ? obj->serialize() : nullptr; // m_breakAuxData might be null after this. } @@ -1115,7 +1130,7 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::LocalremoveBreakpoint(m_continueToLocationBreakpointId); m_continueToLocationBreakpointId = ""; } return result; @@ -1132,19 +1147,19 @@ void V8DebuggerAgentImpl::didContinue() void V8DebuggerAgentImpl::breakProgram(const String16& breakReason, std::unique_ptr data) { - if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() || isCurrentCallStackEmptyOrBlackboxed() || !debugger().breakpointsActivated()) + if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() || isCurrentCallStackEmptyOrBlackboxed() || !m_debugger->breakpointsActivated()) return; m_breakReason = breakReason; m_breakAuxData = std::move(data); m_scheduledDebuggerStep = NoStep; m_steppingFromFramework = false; m_pausingOnNativeEvent = false; - debugger().breakProgram(); + m_debugger->breakProgram(); } void V8DebuggerAgentImpl::breakProgramOnException(const String16& breakReason, std::unique_ptr data) { - if (!enabled() || m_debugger->getPauseOnExceptionsState() == V8DebuggerImpl::DontPauseOnExceptions) + if (!enabled() || m_debugger->getPauseOnExceptionsState() == V8Debugger::DontPauseOnExceptions) return; breakProgram(breakReason, std::move(data)); } diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.h index b6aea619e10..e777f3b2cd8 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerAgentImpl.h @@ -7,15 +7,19 @@ #include "platform/inspector_protocol/Collections.h" #include "platform/inspector_protocol/String16.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/JavaScriptCallFrame.h" #include "platform/v8_inspector/protocol/Debugger.h" #include namespace blink { +struct ScriptBreakpoint; class JavaScriptCallFrame; class PromiseTracker; +class V8Debugger; +class V8DebuggerScript; +class V8InspectorImpl; class V8InspectorSessionImpl; class V8Regex; class V8StackTraceImpl; @@ -122,7 +126,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { std::unique_ptr> positions) override; bool enabled(); - V8DebuggerImpl& debugger() { return *m_debugger; } void setBreakpointAt(const String16& scriptId, int lineNumber, int columnNumber, BreakpointSource, const String16& condition = String16()); void removeBreakpointAt(const String16& scriptId, int lineNumber, int columnNumber, BreakpointSource); @@ -133,7 +136,7 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { void reset(); - // Interface for V8DebuggerImpl + // Interface for V8InspectorImpl SkipPauseRequest didPause(v8::Local, v8::Local exception, const std::vector& hitBreakpoints, bool isPromiseRejection); void didContinue(); void didParseSource(std::unique_ptr, bool success); @@ -184,7 +187,8 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { StepOut }; - V8DebuggerImpl* m_debugger; + V8InspectorImpl* m_inspector; + V8Debugger* m_debugger; V8InspectorSessionImpl* m_session; bool m_enabled; protocol::DictionaryValue* m_state; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerImpl.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerImpl.h deleted file mode 100644 index 0be86bfb28a..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerImpl.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2010, Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef V8DebuggerImpl_h -#define V8DebuggerImpl_h - -#include "platform/inspector_protocol/Collections.h" -#include "platform/inspector_protocol/Maybe.h" -#include "platform/inspector_protocol/Platform.h" -#include "platform/v8_inspector/JavaScriptCallFrame.h" -#include "platform/v8_inspector/V8DebuggerScript.h" -#include "platform/v8_inspector/protocol/Debugger.h" -#include "platform/v8_inspector/public/V8Debugger.h" - -#include -#include -#include - -#include - -namespace blink { - -using protocol::Maybe; - -struct ScriptBreakpoint; -class InspectedContext; -class V8ConsoleMessageStorage; -class V8DebuggerAgentImpl; -class V8InspectorSessionImpl; -class V8RuntimeAgentImpl; -class V8StackTraceImpl; - -class V8DebuggerImpl : public V8Debugger { - PROTOCOL_DISALLOW_COPY(V8DebuggerImpl); -public: - V8DebuggerImpl(v8::Isolate*, V8DebuggerClient*); - ~V8DebuggerImpl() override; - - static int contextId(v8::Local); - static int getGroupId(v8::Local); - - bool enabled() const; - - String16 setBreakpoint(const String16& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation); - void removeBreakpoint(const String16& breakpointId); - void setBreakpointsActivated(bool); - bool breakpointsActivated() const { return m_breakpointsActivated; } - - enum PauseOnExceptionsState { - DontPauseOnExceptions, - PauseOnAllExceptions, - PauseOnUncaughtExceptions - }; - PauseOnExceptionsState getPauseOnExceptionsState(); - void setPauseOnExceptionsState(PauseOnExceptionsState); - void setPauseOnNextStatement(bool); - bool canBreakProgram(); - void breakProgram(); - void continueProgram(); - void stepIntoStatement(); - void stepOverStatement(); - void stepOutOfFunction(); - void clearStepping(); - - bool setScriptSource(const String16& sourceID, v8::Local newSource, bool preview, ErrorString*, Maybe*, JavaScriptCallFrames* newCallFrames, Maybe* stackChanged); - JavaScriptCallFrames currentCallFrames(int limit = 0); - - // Each script inherits debug data from v8::Context where it has been compiled. - // Only scripts whose debug data matches |contextGroupId| will be reported. - // Passing 0 will result in reporting all scripts. - void getCompiledScripts(int contextGroupId, std::vector>&); - void debuggerAgentEnabled(); - void debuggerAgentDisabled(); - - bool isPaused(); - v8::Local pausedContext() { return m_pausedContext; } - int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; } - V8StackTraceImpl* currentAsyncCallChain(); - void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int); - - v8::MaybeLocal functionScopes(v8::Local); - v8::MaybeLocal internalProperties(v8::Local, v8::Local); - - v8::Isolate* isolate() const { return m_isolate; } - V8DebuggerClient* client() { return m_client; } - - v8::MaybeLocal runCompiledScript(v8::Local, v8::Local); - v8::MaybeLocal callFunction(v8::Local, v8::Local, v8::Local receiver, int argc, v8::Local info[]); - v8::MaybeLocal compileAndRunInternalScript(v8::Local, v8::Local); - v8::Local compileInternalScript(v8::Local, v8::Local, const String16& fileName); - v8::Local regexContext(); - - void enableStackCapturingIfNeeded(); - void disableStackCapturingIfNeeded(); - V8ConsoleMessageStorage* ensureConsoleMessageStorage(int contextGroupId); - - // V8Debugger implementation - std::unique_ptr connect(int contextGroupId, protocol::FrontendChannel*, V8InspectorSessionClient*, const String16* state) override; - void contextCreated(const V8ContextInfo&) override; - void contextDestroyed(v8::Local) override; - void resetContextGroup(int contextGroupId) override; - void willExecuteScript(v8::Local, int scriptId) override; - void didExecuteScript(v8::Local) override; - void idleStarted() override; - void idleFinished() override; - void logToConsole(v8::Local, v8::Local arg1, v8::Local arg2) override; - void exceptionThrown(int contextGroupId, const String16& errorMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId) override; - unsigned promiseRejected(v8::Local, const String16& errorMessage, v8::Local exception, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId) override; - void promiseRejectionRevoked(v8::Local, unsigned promiseRejectionId) override; - std::unique_ptr createStackTrace(v8::Local) override; - std::unique_ptr captureStackTrace(bool fullStack) override; - void asyncTaskScheduled(const String16& taskName, void* task, bool recurring) override; - void asyncTaskCanceled(void* task) override; - void asyncTaskStarted(void* task) override; - void asyncTaskFinished(void* task) override; - void allAsyncTasksCanceled() override; - - using ContextByIdMap = protocol::HashMap>; - void discardInspectedContext(int contextGroupId, int contextId); - const ContextByIdMap* contextGroup(int contextGroupId); - void disconnect(V8InspectorSessionImpl*); - V8InspectorSessionImpl* sessionForContextGroup(int contextGroupId); - InspectedContext* getContext(int groupId, int contextId) const; - -private: - void enable(); - void disable(); - V8DebuggerAgentImpl* findEnabledDebuggerAgent(int contextGroupId); - V8DebuggerAgentImpl* findEnabledDebuggerAgent(v8::Local); - - void compileDebuggerScript(); - v8::MaybeLocal callDebuggerMethod(const char* functionName, int argc, v8::Local argv[]); - v8::Local debuggerContext() const; - void clearBreakpoints(); - - static void breakProgramCallback(const v8::FunctionCallbackInfo&); - void handleProgramBreak(v8::Local pausedContext, v8::Local executionState, v8::Local exception, v8::Local hitBreakpoints, bool isPromiseRejection = false); - static void v8DebugEventCallback(const v8::Debug::EventDetails&); - v8::Local callInternalGetterFunction(v8::Local, const char* functionName); - void handleV8DebugEvent(const v8::Debug::EventDetails&); - - v8::Local v8InternalizedString(const char*) const; - - void handleV8AsyncTaskEvent(v8::Local, v8::Local executionState, v8::Local eventData); - - using ContextsByGroupMap = protocol::HashMap>; - - v8::Local collectionEntries(v8::Local, v8::Local); - v8::Local generatorObjectLocation(v8::Local); - v8::Local functionLocation(v8::Local, v8::Local); - - v8::Isolate* m_isolate; - V8DebuggerClient* m_client; - ContextsByGroupMap m_contexts; - using SessionMap = protocol::HashMap; - SessionMap m_sessions; - using ConsoleStorageMap = protocol::HashMap>; - ConsoleStorageMap m_consoleStorageMap; - int m_capturingStackTracesCount; - unsigned m_lastExceptionId; - int m_enabledAgentsCount; - bool m_breakpointsActivated; - v8::Global m_debuggerScript; - v8::Global m_debuggerContext; - v8::Local m_executionState; - v8::Local m_pausedContext; - bool m_runningNestedMessageLoop; - v8::Global m_regexContext; - - using AsyncTaskToStackTrace = protocol::HashMap>; - AsyncTaskToStackTrace m_asyncTaskStacks; - protocol::HashSet m_recurringTasks; - int m_maxAsyncCallStackDepth; - std::vector m_currentTasks; - std::vector> m_currentStacks; - protocol::HashMap m_maxAsyncCallStackDepthMap; -}; - -} // namespace blink - - -#endif // V8DebuggerImpl_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.cpp index 91a060b954e..edb2fcdc7d3 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.cpp @@ -78,7 +78,7 @@ V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, v8::Local o m_startColumn = object->Get(toV8StringInternalized(isolate, "startColumn"))->ToInteger(isolate)->Value(); m_endLine = object->Get(toV8StringInternalized(isolate, "endLine"))->ToInteger(isolate)->Value(); m_endColumn = object->Get(toV8StringInternalized(isolate, "endColumn"))->ToInteger(isolate)->Value(); - m_isContentScript = object->Get(toV8StringInternalized(isolate, "isContentScript"))->ToBoolean(isolate)->Value(); + m_executionContextAuxData = toProtocolStringWithTypeCheck(object->Get(toV8StringInternalized(isolate, "executionContextAuxData"))); m_isInternalScript = object->Get(toV8StringInternalized(isolate, "isInternalScript"))->ToBoolean(isolate)->Value(); m_executionContextId = object->Get(toV8StringInternalized(isolate, "executionContextId"))->ToInteger(isolate)->Value(); m_isLiveEdit = isLiveEdit; @@ -92,7 +92,7 @@ V8DebuggerScript::~V8DebuggerScript() { } -String16 V8DebuggerScript::sourceURL() const +const String16& V8DebuggerScript::sourceURL() const { return m_sourceURL.isEmpty() ? m_url : m_sourceURL; } diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.h index 60d93d81986..d3e9d8d02d5 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8DebuggerScript.h @@ -42,19 +42,19 @@ class V8DebuggerScript { V8DebuggerScript(v8::Isolate*, v8::Local, bool isLiveEdit); ~V8DebuggerScript(); - String16 scriptId() const { return m_id; } - String16 url() const { return m_url; } + const String16& scriptId() const { return m_id; } + const String16& url() const { return m_url; } bool hasSourceURL() const { return !m_sourceURL.isEmpty(); } - String16 sourceURL() const; - String16 sourceMappingURL() const { return m_sourceMappingURL; } + const String16& sourceURL() const; + const String16& sourceMappingURL() const { return m_sourceMappingURL; } v8::Local source(v8::Isolate*) const; - String16 hash() const { return m_hash; } + const String16& hash() const { return m_hash; } int startLine() const { return m_startLine; } int startColumn() const { return m_startColumn; } int endLine() const { return m_endLine; } int endColumn() const { return m_endColumn; } int executionContextId() const { return m_executionContextId; } - bool isContentScript() const { return m_isContentScript; } + const String16& executionContextAuxData() const { return m_executionContextAuxData; } bool isInternalScript() const { return m_isInternalScript; } bool isLiveEdit() const { return m_isLiveEdit; } @@ -74,7 +74,7 @@ class V8DebuggerScript { int m_endLine; int m_endColumn; int m_executionContextId; - bool m_isContentScript; + String16 m_executionContextAuxData; bool m_isInternalScript; bool m_isLiveEdit; }; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.cpp index 73edc7260f0..bed316ef35d 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.cpp @@ -32,16 +32,17 @@ #include "platform/inspector_protocol/Platform.h" #include "platform/v8_inspector/V8Compat.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8Debugger.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" #include namespace blink { -V8FunctionCall::V8FunctionCall(V8DebuggerImpl* debugger, v8::Local context, v8::Local value, const String16& name) - : m_debugger(debugger) +V8FunctionCall::V8FunctionCall(V8InspectorImpl* inspector, v8::Local context, v8::Local value, const String16& name) + : m_inspector(inspector) , m_context(context) , m_name(toV8String(context->GetIsolate(), name)) , m_value(value) @@ -68,11 +69,6 @@ void V8FunctionCall::appendArgument(bool argument) m_arguments.push_back(argument ? v8::True(m_context->GetIsolate()) : v8::False(m_context->GetIsolate())); } -void V8FunctionCall::appendUndefinedArgument() -{ - m_arguments.push_back(v8::Undefined(m_context->GetIsolate())); -} - v8::Local V8FunctionCall::call(bool& hadException, bool reportExceptions) { v8::TryCatch tryCatch(m_context->GetIsolate()); @@ -85,10 +81,6 @@ v8::Local V8FunctionCall::call(bool& hadException, bool reportExcepti v8::Local V8FunctionCall::callWithoutExceptionHandling() { - // TODO(dgozman): get rid of this check. - if (!m_debugger->client()->isExecutionAllowed()) - return v8::Local(); - v8::Local thisObject = v8::Local::Cast(m_value); v8::Local value; if (!thisObject->Get(m_context, m_name).ToLocal(&value)) @@ -103,23 +95,22 @@ v8::Local V8FunctionCall::callWithoutExceptionHandling() DCHECK(!info[i].IsEmpty()); } + int contextGroupId = V8Debugger::getGroupId(m_context); + if (contextGroupId) { + m_inspector->client()->muteMetrics(contextGroupId); + m_inspector->muteExceptions(contextGroupId); + } v8::MicrotasksScope microtasksScope(m_context->GetIsolate(), v8::MicrotasksScope::kDoNotRunMicrotasks); + v8::MaybeLocal maybeResult = function->Call(m_context, thisObject, m_arguments.size(), info.get()); + if (contextGroupId) { + m_inspector->client()->unmuteMetrics(contextGroupId); + m_inspector->unmuteExceptions(contextGroupId); + } + v8::Local result; - if (!function->Call(m_context, thisObject, m_arguments.size(), info.get()).ToLocal(&result)) + if (!maybeResult.ToLocal(&result)) return v8::Local(); return result; } -v8::Local V8FunctionCall::function() -{ - v8::TryCatch tryCatch(m_context->GetIsolate()); - v8::Local thisObject = v8::Local::Cast(m_value); - v8::Local value; - if (!thisObject->Get(m_context, m_name).ToLocal(&value)) - return v8::Local(); - - DCHECK(value->IsFunction()); - return v8::Local::Cast(value); -} - } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.h index 0b9d4e2a509..acb5b5c3417 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8FunctionCall.h @@ -37,25 +37,22 @@ namespace blink { -class V8DebuggerImpl; +class V8InspectorImpl; class V8FunctionCall { public: - V8FunctionCall(V8DebuggerImpl*, v8::Local, v8::Local, const String16& name); + V8FunctionCall(V8InspectorImpl*, v8::Local, v8::Local, const String16& name); void appendArgument(v8::Local); void appendArgument(const String16&); void appendArgument(int); void appendArgument(bool); - void appendUndefinedArgument(); v8::Local call(bool& hadException, bool reportExceptions = true); - v8::Local function(); v8::Local callWithoutExceptionHandling(); - v8::Local context() { return m_context; } protected: - V8DebuggerImpl* m_debugger; + V8InspectorImpl* m_inspector; v8::Local m_context; std::vector> m_arguments; v8::Local m_name; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp index 240dc3d2749..d256fe1cc29 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp @@ -5,10 +5,11 @@ #include "platform/v8_inspector/V8HeapProfilerAgentImpl.h" #include "platform/v8_inspector/InjectedScript.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8Debugger.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" #include #include @@ -50,14 +51,10 @@ class GlobalObjectNameResolver final : public v8::HeapProfiler::ObjectNameResolv const char* GetName(v8::Local object) override { - int contextId = V8DebuggerImpl::contextId(object->CreationContext()); - if (!contextId) + InspectedContext* context = m_session->inspector()->getContext(m_session->contextGroupId(), V8Debugger::contextId(object->CreationContext())); + if (!context) return ""; - ErrorString errorString; - InjectedScript* injectedScript = m_session->findInjectedScript(&errorString, contextId); - if (!injectedScript) - return ""; - String16 name = injectedScript->context()->origin(); + String16 name = context->origin(); size_t length = name.length(); if (m_offset + length + 1 >= m_strings.size()) return ""; @@ -149,7 +146,7 @@ class HeapStatsStream final : public v8::OutputStream { V8HeapProfilerAgentImpl::V8HeapProfilerAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state) : m_session(session) - , m_isolate(session->debugger()->isolate()) + , m_isolate(session->inspector()->isolate()) , m_frontend(frontendChannel) , m_state(state) , m_hasTimer(false) @@ -253,7 +250,7 @@ void V8HeapProfilerAgentImpl::getObjectByHeapObjectId(ErrorString* error, const return; } - if (!m_session->debugger()->client()->isInspectableHeapObject(heapObject)) { + if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject)) { *error = "Object is not available"; return; } @@ -279,7 +276,7 @@ void V8HeapProfilerAgentImpl::addInspectedHeapObject(ErrorString* errorString, c return; } - if (!m_session->debugger()->client()->isInspectableHeapObject(heapObject)) { + if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject)) { *errorString = "Object is not available"; return; } @@ -290,8 +287,10 @@ void V8HeapProfilerAgentImpl::addInspectedHeapObject(ErrorString* errorString, c void V8HeapProfilerAgentImpl::getHeapObjectId(ErrorString* errorString, const String16& objectId, String16* heapSnapshotObjectId) { v8::HandleScope handles(m_isolate); - v8::Local value = m_session->findObject(errorString, objectId); - if (value.IsEmpty() || value->IsUndefined()) + v8::Local value; + v8::Local context; + String16 objectGroup; + if (!m_session->unwrapObject(errorString, objectId, &value, &context, &objectGroup) || value->IsUndefined()) return; v8::SnapshotObjectId id = m_isolate->GetHeapProfiler()->GetObjectId(value); @@ -302,7 +301,7 @@ void V8HeapProfilerAgentImpl::requestHeapStatsUpdate() { HeapStatsStream stream(&m_frontend); v8::SnapshotObjectId lastSeenObjectId = m_isolate->GetHeapProfiler()->GetHeapStats(&stream); - m_frontend.lastSeenObjectId(lastSeenObjectId, m_session->debugger()->client()->currentTimeMS()); + m_frontend.lastSeenObjectId(lastSeenObjectId, m_session->inspector()->client()->currentTimeMS()); } // static @@ -316,14 +315,14 @@ void V8HeapProfilerAgentImpl::startTrackingHeapObjectsInternal(bool trackAllocat m_isolate->GetHeapProfiler()->StartTrackingHeapObjects(trackAllocations); if (!m_hasTimer) { m_hasTimer = true; - m_session->debugger()->client()->startRepeatingTimer(0.05, &V8HeapProfilerAgentImpl::onTimer, reinterpret_cast(this)); + m_session->inspector()->client()->startRepeatingTimer(0.05, &V8HeapProfilerAgentImpl::onTimer, reinterpret_cast(this)); } } void V8HeapProfilerAgentImpl::stopTrackingHeapObjectsInternal() { if (m_hasTimer) { - m_session->debugger()->client()->cancelTimer(reinterpret_cast(this)); + m_session->inspector()->client()->cancelTimer(reinterpret_cast(this)); m_hasTimer = false; } m_isolate->GetHeapProfiler()->StopTrackingHeapObjects(); diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.cpp index afa5138f6ec..6f9a2a05cec 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.cpp @@ -7,10 +7,11 @@ #include "platform/inspector_protocol/String16.h" #include "platform/v8_inspector/InjectedScriptNative.h" #include "platform/v8_inspector/V8Compat.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8Debugger.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InternalValueType.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" namespace blink { @@ -20,38 +21,36 @@ void setFunctionProperty(v8::Local context, v8::Local o { v8::Local funcName = toV8StringInternalized(context->GetIsolate(), name); v8::Local func; - if (!v8::Function::New(context, callback, external, 0, v8::ConstructorBehavior::kThrow).ToLocal(&func)) + if (!V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, external, 0).ToLocal(&func)) return; func->SetName(funcName); if (!obj->Set(context, funcName, func).FromMaybe(false)) return; } -V8DebuggerImpl* unwrapDebugger(const v8::FunctionCallbackInfo& info) +V8InspectorImpl* unwrapInspector(const v8::FunctionCallbackInfo& info) { DCHECK(!info.Data().IsEmpty()); DCHECK(info.Data()->IsExternal()); - V8DebuggerImpl* debugger = static_cast(info.Data().As()->Value()); - DCHECK(debugger); - return debugger; + V8InspectorImpl* inspector = static_cast(info.Data().As()->Value()); + DCHECK(inspector); + return inspector; } } // namespace -v8::Local V8InjectedScriptHost::create(v8::Local context, V8DebuggerImpl* debugger) +v8::Local V8InjectedScriptHost::create(v8::Local context, V8InspectorImpl* inspector) { - v8::Isolate* isolate = debugger->isolate(); + v8::Isolate* isolate = inspector->isolate(); v8::Local injectedScriptHost = v8::Object::New(isolate); - v8::Local debuggerExternal = v8::External::New(isolate, debugger); + v8::Local debuggerExternal = v8::External::New(isolate, inspector); setFunctionProperty(context, injectedScriptHost, "internalConstructorName", V8InjectedScriptHost::internalConstructorNameCallback, debuggerExternal); setFunctionProperty(context, injectedScriptHost, "formatAccessorsAsProperties", V8InjectedScriptHost::formatAccessorsAsProperties, debuggerExternal); - setFunctionProperty(context, injectedScriptHost, "isTypedArray", V8InjectedScriptHost::isTypedArrayCallback, debuggerExternal); setFunctionProperty(context, injectedScriptHost, "subtype", V8InjectedScriptHost::subtypeCallback, debuggerExternal); setFunctionProperty(context, injectedScriptHost, "getInternalProperties", V8InjectedScriptHost::getInternalPropertiesCallback, debuggerExternal); - setFunctionProperty(context, injectedScriptHost, "suppressWarningsAndCallFunction", V8InjectedScriptHost::suppressWarningsAndCallFunctionCallback, debuggerExternal); + setFunctionProperty(context, injectedScriptHost, "objectHasOwnProperty", V8InjectedScriptHost::objectHasOwnPropertyCallback, debuggerExternal); setFunctionProperty(context, injectedScriptHost, "bind", V8InjectedScriptHost::bindCallback, debuggerExternal); setFunctionProperty(context, injectedScriptHost, "proxyTargetValue", V8InjectedScriptHost::proxyTargetValueCallback, debuggerExternal); - setFunctionProperty(context, injectedScriptHost, "prototype", V8InjectedScriptHost::prototypeCallback, debuggerExternal); return injectedScriptHost; } @@ -73,15 +72,7 @@ void V8InjectedScriptHost::formatAccessorsAsProperties(const v8::FunctionCallbac // Check that function is user-defined. if (info[1].As()->ScriptId() != v8::UnboundScript::kNoScriptId) return; - info.GetReturnValue().Set(unwrapDebugger(info)->client()->formatAccessorsAsProperties(info[0])); -} - -void V8InjectedScriptHost::isTypedArrayCallback(const v8::FunctionCallbackInfo& info) -{ - if (info.Length() < 1) - return; - - info.GetReturnValue().Set(info[0]->IsTypedArray()); + info.GetReturnValue().Set(unwrapInspector(info)->client()->formatAccessorsAsProperties(info[0])); } void V8InjectedScriptHost::subtypeCallback(const v8::FunctionCallbackInfo& info) @@ -98,10 +89,14 @@ void V8InjectedScriptHost::subtypeCallback(const v8::FunctionCallbackInfoIsArray() || value->IsTypedArray() || value->IsArgumentsObject()) { + if (value->IsArray() || value->IsArgumentsObject()) { info.GetReturnValue().Set(toV8StringInternalized(isolate, "array")); return; } + if (value->IsTypedArray()) { + info.GetReturnValue().Set(toV8StringInternalized(isolate, "typedarray")); + return; + } if (value->IsDate()) { info.GetReturnValue().Set(toV8StringInternalized(isolate, "date")); return; @@ -134,7 +129,11 @@ void V8InjectedScriptHost::subtypeCallback(const v8::FunctionCallbackInfoclient()->valueSubtype(value); + if (value->IsPromise()) { + info.GetReturnValue().Set(toV8StringInternalized(isolate, "promise")); + return; + } + String16 subtype = unwrapInspector(info)->client()->valueSubtype(value); if (!subtype.isEmpty()) { info.GetReturnValue().Set(toV8String(isolate, subtype)); return; @@ -146,51 +145,16 @@ void V8InjectedScriptHost::getInternalPropertiesCallback(const v8::FunctionCallb if (info.Length() < 1) return; v8::Local properties; - if (unwrapDebugger(info)->internalProperties(info.GetIsolate()->GetCurrentContext(), info[0]).ToLocal(&properties)) + if (unwrapInspector(info)->debugger()->internalProperties(info.GetIsolate()->GetCurrentContext(), info[0]).ToLocal(&properties)) info.GetReturnValue().Set(properties); } -void V8InjectedScriptHost::suppressWarningsAndCallFunctionCallback(const v8::FunctionCallbackInfo& info) +void V8InjectedScriptHost::objectHasOwnPropertyCallback(const v8::FunctionCallbackInfo& info) { - if (info.Length() < 2 || info.Length() > 3 || !info[0]->IsFunction()) { - NOTREACHED(); + if (info.Length() < 2 || !info[0]->IsObject() || !info[1]->IsString()) return; - } - if (info.Length() > 2 && (!info[2]->IsArray() && !info[2]->IsUndefined())) { - NOTREACHED(); - return; - } - - v8::Isolate* isolate = info.GetIsolate(); - v8::Local context = isolate->GetCurrentContext(); - - v8::Local function = info[0].As(); - v8::Local receiver = info[1]; - std::unique_ptr[]> argv = nullptr; - size_t argc = 0; - - if (info.Length() > 2 && info[2]->IsArray()) { - v8::Local arguments = info[2].As(); - argc = arguments->Length(); - argv.reset(new v8::Local[argc]); - for (size_t i = 0; i < argc; ++i) { - if (!arguments->Get(context, i).ToLocal(&argv[i])) - return; - } - } - - V8DebuggerImpl* debugger = unwrapDebugger(info); - int contextGroupId = V8DebuggerImpl::getGroupId(context); - if (contextGroupId) - debugger->client()->muteWarningsAndDeprecations(contextGroupId); - - v8::MicrotasksScope microtasks(isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); - v8::Local result; - if (function->Call(context, receiver, argc, argv.get()).ToLocal(&result)) - info.GetReturnValue().Set(result); - - if (contextGroupId) - debugger->client()->unmuteWarningsAndDeprecations(contextGroupId); + bool result = info[0].As()->HasOwnProperty(info.GetIsolate()->GetCurrentContext(), v8::Local::Cast(info[1])).FromMaybe(false); + info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), result)); } void V8InjectedScriptHost::bindCallback(const v8::FunctionCallbackInfo& info) @@ -219,10 +183,4 @@ void V8InjectedScriptHost::proxyTargetValueCallback(const v8::FunctionCallbackIn info.GetReturnValue().Set(target); } -void V8InjectedScriptHost::prototypeCallback(const v8::FunctionCallbackInfo& info) -{ - DCHECK(info.Length() > 0 && info[0]->IsObject()); - info.GetReturnValue().Set(info[0].As()->GetPrototype()); -} - } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.h index bf49fa71f40..496b5a77f80 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InjectedScriptHost.h @@ -9,7 +9,7 @@ namespace blink { -class V8DebuggerImpl; +class V8InspectorImpl; // SECURITY NOTE: Although the InjectedScriptHost is intended for use solely by the inspector, // a reference to the InjectedScriptHost may be leaked to the page being inspected. Thus, the @@ -19,18 +19,16 @@ class V8DebuggerImpl; class V8InjectedScriptHost { public: // We expect that debugger outlives any JS context and thus V8InjectedScriptHost (owned by JS) - // is destroyed before debugger. - static v8::Local create(v8::Local, V8DebuggerImpl*); + // is destroyed before inspector. + static v8::Local create(v8::Local, V8InspectorImpl*); private: static void internalConstructorNameCallback(const v8::FunctionCallbackInfo&); static void formatAccessorsAsProperties(const v8::FunctionCallbackInfo&); - static void isTypedArrayCallback(const v8::FunctionCallbackInfo&); static void subtypeCallback(const v8::FunctionCallbackInfo&); static void getInternalPropertiesCallback(const v8::FunctionCallbackInfo&); - static void suppressWarningsAndCallFunctionCallback(const v8::FunctionCallbackInfo&); + static void objectHasOwnPropertyCallback(const v8::FunctionCallbackInfo&); static void bindCallback(const v8::FunctionCallbackInfo&); static void proxyTargetValueCallback(const v8::FunctionCallbackInfo&); - static void prototypeCallback(const v8::FunctionCallbackInfo&); }; } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorImpl.cpp new file mode 100644 index 00000000000..caac2020602 --- /dev/null +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorImpl.cpp @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2010-2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "platform/v8_inspector/V8InspectorImpl.h" + +#include "platform/v8_inspector/InspectedContext.h" +#include "platform/v8_inspector/V8Compat.h" +#include "platform/v8_inspector/V8ConsoleAgentImpl.h" +#include "platform/v8_inspector/V8ConsoleMessage.h" +#include "platform/v8_inspector/V8Debugger.h" +#include "platform/v8_inspector/V8DebuggerAgentImpl.h" +#include "platform/v8_inspector/V8InspectorSessionImpl.h" +#include "platform/v8_inspector/V8RuntimeAgentImpl.h" +#include "platform/v8_inspector/V8StackTraceImpl.h" +#include "platform/v8_inspector/V8StringUtil.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" +#include + +namespace blink { + +std::unique_ptr V8Inspector::create(v8::Isolate* isolate, V8InspectorClient* client) +{ + return wrapUnique(new V8InspectorImpl(isolate, client)); +} + +V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate, V8InspectorClient* client) + : m_isolate(isolate) + , m_client(client) + , m_debugger(new V8Debugger(isolate, this)) + , m_capturingStackTracesCount(0) + , m_lastExceptionId(0) +{ +} + +V8InspectorImpl::~V8InspectorImpl() +{ +} + +V8DebuggerAgentImpl* V8InspectorImpl::enabledDebuggerAgentForGroup(int contextGroupId) +{ + V8InspectorSessionImpl* session = sessionForContextGroup(contextGroupId); + V8DebuggerAgentImpl* agent = session ? session->debuggerAgent() : nullptr; + return agent && agent->enabled() ? agent : nullptr; +} + +V8RuntimeAgentImpl* V8InspectorImpl::enabledRuntimeAgentForGroup(int contextGroupId) +{ + V8InspectorSessionImpl* session = sessionForContextGroup(contextGroupId); + V8RuntimeAgentImpl* agent = session ? session->runtimeAgent() : nullptr; + return agent && agent->enabled() ? agent : nullptr; +} + +v8::MaybeLocal V8InspectorImpl::runCompiledScript(v8::Local context, v8::Local script) +{ + v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicrotasks); + int groupId = V8Debugger::getGroupId(context); + if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) + agent->willExecuteScript(script->GetUnboundScript()->GetId()); + v8::MaybeLocal result = script->Run(context); + // Get agent from the map again, since it could have detached during script execution. + if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) + agent->didExecuteScript(); + return result; +} + +v8::MaybeLocal V8InspectorImpl::callFunction(v8::Local function, v8::Local context, v8::Local receiver, int argc, v8::Local info[]) +{ + v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicrotasks); + int groupId = V8Debugger::getGroupId(context); + if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) + agent->willExecuteScript(function->ScriptId()); + v8::MaybeLocal result = function->Call(context, receiver, argc, info); + // Get agent from the map again, since it could have detached during script execution. + if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) + agent->didExecuteScript(); + return result; +} + +v8::MaybeLocal V8InspectorImpl::compileAndRunInternalScript(v8::Local context, v8::Local source) +{ + v8::Local script = compileScript(context, source, String(), true); + if (script.IsEmpty()) + return v8::MaybeLocal(); + v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); + return script->Run(context); +} + +v8::Local V8InspectorImpl::compileScript(v8::Local context, v8::Local code, const String16& fileName, bool markAsInternal) +{ + v8::ScriptOrigin origin( + toV8String(m_isolate, fileName), + v8::Integer::New(m_isolate, 0), + v8::Integer::New(m_isolate, 0), + v8::False(m_isolate), // sharable + v8::Local(), + v8::Boolean::New(m_isolate, markAsInternal), // internal + toV8String(m_isolate, String16()), // sourceMap + v8::True(m_isolate)); // opaqueresource + v8::ScriptCompiler::Source source(code, origin); + v8::Local script; + if (!v8::ScriptCompiler::Compile(context, &source, v8::ScriptCompiler::kNoCompileOptions).ToLocal(&script)) + return v8::Local(); + return script; +} + +void V8InspectorImpl::enableStackCapturingIfNeeded() +{ + if (!m_capturingStackTracesCount) + V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate, true); + ++m_capturingStackTracesCount; +} + +void V8InspectorImpl::disableStackCapturingIfNeeded() +{ + if (!(--m_capturingStackTracesCount)) + V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate, false); +} + +void V8InspectorImpl::muteExceptions(int contextGroupId) +{ + m_muteExceptionsMap[contextGroupId]++; +} + +void V8InspectorImpl::unmuteExceptions(int contextGroupId) +{ + m_muteExceptionsMap[contextGroupId]--; +} + +V8ConsoleMessageStorage* V8InspectorImpl::ensureConsoleMessageStorage(int contextGroupId) +{ + ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGroupId); + if (storageIt == m_consoleStorageMap.end()) + storageIt = m_consoleStorageMap.insert(std::make_pair(contextGroupId, wrapUnique(new V8ConsoleMessageStorage(this, contextGroupId)))).first; + return storageIt->second.get(); +} + +std::unique_ptr V8InspectorImpl::createStackTrace(v8::Local stackTrace) +{ + return m_debugger->createStackTrace(stackTrace); +} + +std::unique_ptr V8InspectorImpl::connect(int contextGroupId, protocol::FrontendChannel* channel, const String16* state) +{ + DCHECK(m_sessions.find(contextGroupId) == m_sessions.cend()); + std::unique_ptr session = V8InspectorSessionImpl::create(this, contextGroupId, channel, state); + m_sessions[contextGroupId] = session.get(); + return std::move(session); +} + +void V8InspectorImpl::disconnect(V8InspectorSessionImpl* session) +{ + DCHECK(m_sessions.find(session->contextGroupId()) != m_sessions.end()); + m_sessions.erase(session->contextGroupId()); +} + +InspectedContext* V8InspectorImpl::getContext(int groupId, int contextId) const +{ + if (!groupId || !contextId) + return nullptr; + + ContextsByGroupMap::const_iterator contextGroupIt = m_contexts.find(groupId); + if (contextGroupIt == m_contexts.end()) + return nullptr; + + ContextByIdMap::iterator contextIt = contextGroupIt->second->find(contextId); + if (contextIt == contextGroupIt->second->end()) + return nullptr; + + return contextIt->second.get(); +} + +void V8InspectorImpl::contextCreated(const V8ContextInfo& info) +{ + int contextId = m_debugger->markContext(info); + + ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId); + if (contextIt == m_contexts.end()) + contextIt = m_contexts.insert(std::make_pair(info.contextGroupId, wrapUnique(new ContextByIdMap()))).first; + + const auto& contextById = contextIt->second; + + DCHECK(contextById->find(contextId) == contextById->cend()); + InspectedContext* context = new InspectedContext(this, info, contextId); + (*contextById)[contextId] = wrapUnique(context); + SessionMap::iterator sessionIt = m_sessions.find(info.contextGroupId); + if (sessionIt != m_sessions.end()) + sessionIt->second->runtimeAgent()->reportExecutionContextCreated(context); +} + +void V8InspectorImpl::contextDestroyed(v8::Local context) +{ + int contextId = V8Debugger::contextId(context); + int contextGroupId = V8Debugger::getGroupId(context); + + ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGroupId); + if (storageIt != m_consoleStorageMap.end()) + storageIt->second->contextDestroyed(contextId); + + InspectedContext* inspectedContext = getContext(contextGroupId, contextId); + if (!inspectedContext) + return; + + SessionMap::iterator iter = m_sessions.find(contextGroupId); + if (iter != m_sessions.end()) + iter->second->runtimeAgent()->reportExecutionContextDestroyed(inspectedContext); + discardInspectedContext(contextGroupId, contextId); +} + +void V8InspectorImpl::resetContextGroup(int contextGroupId) +{ + m_consoleStorageMap.erase(contextGroupId); + m_muteExceptionsMap.erase(contextGroupId); + SessionMap::iterator session = m_sessions.find(contextGroupId); + if (session != m_sessions.end()) + session->second->reset(); + m_contexts.erase(contextGroupId); +} + +void V8InspectorImpl::willExecuteScript(v8::Local context, int scriptId) +{ + if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(V8Debugger::getGroupId(context))) + agent->willExecuteScript(scriptId); +} + +void V8InspectorImpl::didExecuteScript(v8::Local context) +{ + if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(V8Debugger::getGroupId(context))) + agent->didExecuteScript(); +} + +void V8InspectorImpl::idleStarted() +{ + m_isolate->GetCpuProfiler()->SetIdle(true); +} + +void V8InspectorImpl::idleFinished() +{ + m_isolate->GetCpuProfiler()->SetIdle(false); +} + +unsigned V8InspectorImpl::exceptionThrown(v8::Local context, const String16& message, v8::Local exception, const String16& detailedMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr stackTrace, int scriptId) +{ + int contextGroupId = V8Debugger::getGroupId(context); + if (!contextGroupId || m_muteExceptionsMap[contextGroupId]) + return 0; + std::unique_ptr stackTraceImpl = wrapUnique(static_cast(stackTrace.release())); + unsigned exceptionId = ++m_lastExceptionId; + std::unique_ptr consoleMessage = V8ConsoleMessage::createForException(m_client->currentTimeMS(), detailedMessage, url, lineNumber, columnNumber, std::move(stackTraceImpl), scriptId, m_isolate, message, V8Debugger::contextId(context), exception, exceptionId); + ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMessage)); + return exceptionId; +} + +void V8InspectorImpl::exceptionRevoked(v8::Local context, unsigned exceptionId, const String16& message) +{ + int contextGroupId = V8Debugger::getGroupId(context); + if (!contextGroupId) + return; + + std::unique_ptr consoleMessage = V8ConsoleMessage::createForRevokedException(m_client->currentTimeMS(), message, exceptionId); + ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMessage)); +} + +std::unique_ptr V8InspectorImpl::captureStackTrace(bool fullStack) +{ + return m_debugger->captureStackTrace(fullStack); +} + +void V8InspectorImpl::asyncTaskScheduled(const String16& taskName, void* task, bool recurring) +{ + m_debugger->asyncTaskScheduled(taskName, task, recurring); +} + +void V8InspectorImpl::asyncTaskCanceled(void* task) +{ + m_debugger->asyncTaskCanceled(task); +} + +void V8InspectorImpl::asyncTaskStarted(void* task) +{ + m_debugger->asyncTaskStarted(task); +} + +void V8InspectorImpl::asyncTaskFinished(void* task) +{ + m_debugger->asyncTaskFinished(task); +} + +void V8InspectorImpl::allAsyncTasksCanceled() +{ + m_debugger->allAsyncTasksCanceled(); +} + +v8::Local V8InspectorImpl::regexContext() +{ + if (m_regexContext.IsEmpty()) + m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate)); + return m_regexContext.Get(m_isolate); +} + +void V8InspectorImpl::discardInspectedContext(int contextGroupId, int contextId) +{ + if (!getContext(contextGroupId, contextId)) + return; + m_contexts[contextGroupId]->erase(contextId); + if (m_contexts[contextGroupId]->empty()) + m_contexts.erase(contextGroupId); +} + +const V8InspectorImpl::ContextByIdMap* V8InspectorImpl::contextGroup(int contextGroupId) +{ + ContextsByGroupMap::iterator iter = m_contexts.find(contextGroupId); + return iter == m_contexts.end() ? nullptr : iter->second.get(); +} + +V8InspectorSessionImpl* V8InspectorImpl::sessionForContextGroup(int contextGroupId) +{ + if (!contextGroupId) + return nullptr; + SessionMap::iterator iter = m_sessions.find(contextGroupId); + return iter == m_sessions.end() ? nullptr : iter->second; +} + +} // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorImpl.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorImpl.h new file mode 100644 index 00000000000..e4dad93d9c6 --- /dev/null +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorImpl.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef V8InspectorImpl_h +#define V8InspectorImpl_h + +#include "platform/inspector_protocol/Allocator.h" +#include "platform/inspector_protocol/Collections.h" +#include "platform/inspector_protocol/Platform.h" +#include "platform/v8_inspector/public/V8Inspector.h" + +#include +#include +#include + +namespace blink { + +class InspectedContext; +class V8ConsoleMessageStorage; +class V8Debugger; +class V8DebuggerAgentImpl; +class V8InspectorSessionImpl; +class V8RuntimeAgentImpl; +class V8StackTraceImpl; + +class V8InspectorImpl : public V8Inspector { + PROTOCOL_DISALLOW_COPY(V8InspectorImpl); +public: + V8InspectorImpl(v8::Isolate*, V8InspectorClient*); + ~V8InspectorImpl() override; + + v8::Isolate* isolate() const { return m_isolate; } + V8InspectorClient* client() { return m_client; } + V8Debugger* debugger() { return m_debugger.get(); } + + v8::MaybeLocal runCompiledScript(v8::Local, v8::Local); + v8::MaybeLocal callFunction(v8::Local, v8::Local, v8::Local receiver, int argc, v8::Local info[]); + v8::MaybeLocal compileAndRunInternalScript(v8::Local, v8::Local); + v8::Local compileScript(v8::Local, v8::Local, const String16& fileName, bool markAsInternal); + v8::Local regexContext(); + + // V8Inspector implementation. + std::unique_ptr connect(int contextGroupId, protocol::FrontendChannel*, const String16* state) override; + void contextCreated(const V8ContextInfo&) override; + void contextDestroyed(v8::Local) override; + void resetContextGroup(int contextGroupId) override; + void willExecuteScript(v8::Local, int scriptId) override; + void didExecuteScript(v8::Local) override; + void idleStarted() override; + void idleFinished() override; + unsigned exceptionThrown(v8::Local, const String16& message, v8::Local exception, const String16& detailedMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId) override; + void exceptionRevoked(v8::Local, unsigned exceptionId, const String16& message) override; + std::unique_ptr createStackTrace(v8::Local) override; + std::unique_ptr captureStackTrace(bool fullStack) override; + void asyncTaskScheduled(const String16& taskName, void* task, bool recurring) override; + void asyncTaskCanceled(void* task) override; + void asyncTaskStarted(void* task) override; + void asyncTaskFinished(void* task) override; + void allAsyncTasksCanceled() override; + + void enableStackCapturingIfNeeded(); + void disableStackCapturingIfNeeded(); + void muteExceptions(int contextGroupId); + void unmuteExceptions(int contextGroupId); + V8ConsoleMessageStorage* ensureConsoleMessageStorage(int contextGroupId); + using ContextByIdMap = protocol::HashMap>; + void discardInspectedContext(int contextGroupId, int contextId); + const ContextByIdMap* contextGroup(int contextGroupId); + void disconnect(V8InspectorSessionImpl*); + V8InspectorSessionImpl* sessionForContextGroup(int contextGroupId); + InspectedContext* getContext(int groupId, int contextId) const; + V8DebuggerAgentImpl* enabledDebuggerAgentForGroup(int contextGroupId); + V8RuntimeAgentImpl* enabledRuntimeAgentForGroup(int contextGroupId); + +private: + v8::Isolate* m_isolate; + V8InspectorClient* m_client; + std::unique_ptr m_debugger; + v8::Global m_regexContext; + int m_capturingStackTracesCount; + unsigned m_lastExceptionId; + + using MuteExceptionsMap = protocol::HashMap; + MuteExceptionsMap m_muteExceptionsMap; + + using ContextsByGroupMap = protocol::HashMap>; + ContextsByGroupMap m_contexts; + + using SessionMap = protocol::HashMap; + SessionMap m_sessions; + + using ConsoleStorageMap = protocol::HashMap>; + ConsoleStorageMap m_consoleStorageMap; +}; + +} // namespace blink + + +#endif // V8InspectorImpl_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.cpp index 88aac8c894d..814b7f91ea5 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.cpp @@ -9,33 +9,36 @@ #include "platform/v8_inspector/InspectedContext.h" #include "platform/v8_inspector/RemoteObjectId.h" #include "platform/v8_inspector/V8ConsoleAgentImpl.h" +#include "platform/v8_inspector/V8Debugger.h" #include "platform/v8_inspector/V8DebuggerAgentImpl.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" #include "platform/v8_inspector/V8HeapProfilerAgentImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8ProfilerAgentImpl.h" #include "platform/v8_inspector/V8RuntimeAgentImpl.h" +#include "platform/v8_inspector/V8StringUtil.h" #include "platform/v8_inspector/public/V8ContextInfo.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" namespace blink { -const char V8InspectorSession::backtraceObjectGroup[] = "backtrace"; - // static -bool V8InspectorSession::isV8ProtocolMethod(const String16& method) +bool V8InspectorSession::canDispatchMethod(const String16& method) { - return method.startWith("Debugger.") || method.startWith("HeapProfiler.") || method.startWith("Profiler.") || method.startWith("Runtime.") || method.startWith("Console."); + return method.startWith(protocol::Runtime::Metainfo::commandPrefix) + || method.startWith(protocol::Debugger::Metainfo::commandPrefix) + || method.startWith(protocol::Profiler::Metainfo::commandPrefix) + || method.startWith(protocol::HeapProfiler::Metainfo::commandPrefix) + || method.startWith(protocol::Console::Metainfo::commandPrefix); } -std::unique_ptr V8InspectorSessionImpl::create(V8DebuggerImpl* debugger, int contextGroupId, protocol::FrontendChannel* channel, V8InspectorSessionClient* client, const String16* state) +std::unique_ptr V8InspectorSessionImpl::create(V8InspectorImpl* inspector, int contextGroupId, protocol::FrontendChannel* channel, const String16* state) { - return wrapUnique(new V8InspectorSessionImpl(debugger, contextGroupId, channel, client, state)); + return wrapUnique(new V8InspectorSessionImpl(inspector, contextGroupId, channel, state)); } -V8InspectorSessionImpl::V8InspectorSessionImpl(V8DebuggerImpl* debugger, int contextGroupId, protocol::FrontendChannel* channel, V8InspectorSessionClient* client, const String16* savedState) +V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector, int contextGroupId, protocol::FrontendChannel* channel, const String16* savedState) : m_contextGroupId(contextGroupId) - , m_debugger(debugger) - , m_client(client) + , m_inspector(inspector) , m_customObjectFormatterEnabled(false) , m_dispatcher(channel) , m_state(nullptr) @@ -89,7 +92,7 @@ V8InspectorSessionImpl::~V8InspectorSessionImpl() m_runtimeAgent->disable(&errorString); discardInjectedScripts(); - m_debugger->disconnect(this); + m_inspector->disconnect(this); } protocol::DictionaryValue* V8InspectorSessionImpl::agentState(const String16& name) @@ -113,7 +116,7 @@ void V8InspectorSessionImpl::reset() void V8InspectorSessionImpl::discardInjectedScripts() { m_inspectedObjects.clear(); - const V8DebuggerImpl::ContextByIdMap* contexts = m_debugger->contextGroup(m_contextGroupId); + const V8InspectorImpl::ContextByIdMap* contexts = m_inspector->contextGroup(m_contextGroupId); if (!contexts) return; @@ -122,7 +125,7 @@ void V8InspectorSessionImpl::discardInjectedScripts() for (auto& idContext : *contexts) keys.push_back(idContext.first); for (auto& key : keys) { - contexts = m_debugger->contextGroup(m_contextGroupId); + contexts = m_inspector->contextGroup(m_contextGroupId); if (!contexts) continue; auto contextIt = contexts->find(key); @@ -138,8 +141,13 @@ InjectedScript* V8InspectorSessionImpl::findInjectedScript(ErrorString* errorStr return nullptr; } - const V8DebuggerImpl::ContextByIdMap* contexts = m_debugger->contextGroup(m_contextGroupId); - auto contextsIt = contexts ? contexts->find(contextId) : contexts->end(); + const V8InspectorImpl::ContextByIdMap* contexts = m_inspector->contextGroup(m_contextGroupId); + if (!contexts) { + *errorString = "Cannot find context with specified id"; + return nullptr; + } + + auto contextsIt = contexts->find(contextId); if (contextsIt == contexts->end()) { *errorString = "Cannot find context with specified id"; return nullptr; @@ -165,7 +173,7 @@ InjectedScript* V8InspectorSessionImpl::findInjectedScript(ErrorString* errorStr void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) { - const V8DebuggerImpl::ContextByIdMap* contexts = m_debugger->contextGroup(m_contextGroupId); + const V8InspectorImpl::ContextByIdMap* contexts = m_inspector->contextGroup(m_contextGroupId); if (!contexts) return; @@ -173,7 +181,7 @@ void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) for (auto& idContext : *contexts) keys.push_back(idContext.first); for (auto& key : keys) { - contexts = m_debugger->contextGroup(m_contextGroupId); + contexts = m_inspector->contextGroup(m_contextGroupId); if (!contexts) continue; auto contextsIt = contexts->find(key); @@ -185,29 +193,30 @@ void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) } } -v8::Local V8InspectorSessionImpl::findObject(ErrorString* errorString, const String16& objectId, v8::Local* context, String16* groupName) +bool V8InspectorSessionImpl::unwrapObject(ErrorString* errorString, const String16& objectId, v8::Local* object, v8::Local* context, String16* objectGroup) { std::unique_ptr remoteId = RemoteObjectId::parse(errorString, objectId); if (!remoteId) - return v8::Local(); + return false; InjectedScript* injectedScript = findInjectedScript(errorString, remoteId.get()); if (!injectedScript) - return v8::Local(); - v8::Local objectValue; - injectedScript->findObject(errorString, *remoteId, &objectValue); - if (objectValue.IsEmpty()) - return v8::Local(); - if (context) - *context = injectedScript->context()->context(); - if (groupName) - *groupName = injectedScript->objectGroupName(*remoteId); - return objectValue; + return false; + if (!injectedScript->findObject(errorString, *remoteId, object)) + return false; + *context = injectedScript->context()->context(); + *objectGroup = injectedScript->objectGroupName(*remoteId); + return true; +} + +std::unique_ptr V8InspectorSessionImpl::wrapObject(v8::Local context, v8::Local value, const String16& groupName) +{ + return wrapObject(context, value, groupName, false); } std::unique_ptr V8InspectorSessionImpl::wrapObject(v8::Local context, v8::Local value, const String16& groupName, bool generatePreview) { ErrorString errorString; - InjectedScript* injectedScript = findInjectedScript(&errorString, V8DebuggerImpl::contextId(context)); + InjectedScript* injectedScript = findInjectedScript(&errorString, V8Debugger::contextId(context)); if (!injectedScript) return nullptr; return injectedScript->wrapObject(&errorString, value, groupName, false, generatePreview); @@ -216,7 +225,7 @@ std::unique_ptr V8InspectorSessionImpl::wrapObj std::unique_ptr V8InspectorSessionImpl::wrapTable(v8::Local context, v8::Local table, v8::Local columns) { ErrorString errorString; - InjectedScript* injectedScript = findInjectedScript(&errorString, V8DebuggerImpl::contextId(context)); + InjectedScript* injectedScript = findInjectedScript(&errorString, V8Debugger::contextId(context)); if (!injectedScript) return nullptr; return injectedScript->wrapTable(table, columns); @@ -225,7 +234,7 @@ std::unique_ptr V8InspectorSessionImpl::wrapTab void V8InspectorSessionImpl::setCustomObjectFormatterEnabled(bool enabled) { m_customObjectFormatterEnabled = enabled; - const V8DebuggerImpl::ContextByIdMap* contexts = m_debugger->contextGroup(m_contextGroupId); + const V8InspectorImpl::ContextByIdMap* contexts = m_inspector->contextGroup(m_contextGroupId); if (!contexts) return; for (auto& idContext : *contexts) { @@ -237,7 +246,7 @@ void V8InspectorSessionImpl::setCustomObjectFormatterEnabled(bool enabled) void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) { - const V8DebuggerImpl::ContextByIdMap* contexts = m_debugger->contextGroup(m_contextGroupId); + const V8InspectorImpl::ContextByIdMap* contexts = m_inspector->contextGroup(m_contextGroupId); if (!contexts) return; for (auto& idContext : *contexts) @@ -268,9 +277,9 @@ V8InspectorSession::Inspectable* V8InspectorSessionImpl::inspectedObject(unsigne return m_inspectedObjects[num].get(); } -void V8InspectorSessionImpl::schedulePauseOnNextStatement(const String16& breakReason, std::unique_ptr data) +void V8InspectorSessionImpl::schedulePauseOnNextStatement(const String16& breakReason, const String16& breakDetails) { - m_debuggerAgent->schedulePauseOnNextStatement(breakReason, std::move(data)); + m_debuggerAgent->schedulePauseOnNextStatement(breakReason, protocol::DictionaryValue::cast(parseJSON(breakDetails))); } void V8InspectorSessionImpl::cancelPauseOnNextStatement() @@ -278,9 +287,9 @@ void V8InspectorSessionImpl::cancelPauseOnNextStatement() m_debuggerAgent->cancelPauseOnNextStatement(); } -void V8InspectorSessionImpl::breakProgram(const String16& breakReason, std::unique_ptr data) +void V8InspectorSessionImpl::breakProgram(const String16& breakReason, const String16& breakDetails) { - m_debuggerAgent->breakProgram(breakReason, std::move(data)); + m_debuggerAgent->breakProgram(breakReason, protocol::DictionaryValue::cast(parseJSON(breakDetails))); } void V8InspectorSessionImpl::setSkipAllPauses(bool skip) @@ -301,4 +310,13 @@ void V8InspectorSessionImpl::stepOver() m_debuggerAgent->stepOver(&errorString); } +std::unique_ptr> V8InspectorSessionImpl::searchInTextByLines(const String16& text, const String16& query, bool caseSensitive, bool isRegex) +{ + std::vector> matches = searchInTextByLinesImpl(this, text, query, caseSensitive, isRegex); + std::unique_ptr> result = protocol::Array::create(); + for (size_t i = 0; i < matches.size(); ++i) + result->addItem(std::move(matches[i])); + return result; +} + } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.h index 21753dac21b..d5ee2ef75f8 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8InspectorSessionImpl.h @@ -11,7 +11,6 @@ #include "platform/inspector_protocol/String16.h" #include "platform/v8_inspector/protocol/Runtime.h" #include "platform/v8_inspector/public/V8InspectorSession.h" -#include "platform/v8_inspector/public/V8InspectorSessionClient.h" #include @@ -23,7 +22,7 @@ class InjectedScript; class RemoteObjectIdBase; class V8ConsoleAgentImpl; class V8DebuggerAgentImpl; -class V8DebuggerImpl; +class V8InspectorImpl; class V8HeapProfilerAgentImpl; class V8ProfilerAgentImpl; class V8RuntimeAgentImpl; @@ -31,11 +30,10 @@ class V8RuntimeAgentImpl; class V8InspectorSessionImpl : public V8InspectorSession { PROTOCOL_DISALLOW_COPY(V8InspectorSessionImpl); public: - static std::unique_ptr create(V8DebuggerImpl*, int contextGroupId, protocol::FrontendChannel*, V8InspectorSessionClient*, const String16* state); + static std::unique_ptr create(V8InspectorImpl*, int contextGroupId, protocol::FrontendChannel*, const String16* state); ~V8InspectorSessionImpl(); - V8DebuggerImpl* debugger() const { return m_debugger; } - V8InspectorSessionClient* client() const { return m_client; } + V8InspectorImpl* inspector() const { return m_inspector; } V8ConsoleAgentImpl* consoleAgent() { return m_consoleAgent.get(); } V8DebuggerAgentImpl* debuggerAgent() { return m_debuggerAgent.get(); } V8ProfilerAgentImpl* profilerAgent() { return m_profilerAgent.get(); } @@ -48,32 +46,33 @@ class V8InspectorSessionImpl : public V8InspectorSession { void discardInjectedScripts(); void reportAllContexts(V8RuntimeAgentImpl*); void setCustomObjectFormatterEnabled(bool); + std::unique_ptr wrapObject(v8::Local, v8::Local, const String16& groupName, bool generatePreview); + std::unique_ptr wrapTable(v8::Local, v8::Local table, v8::Local columns); // V8InspectorSession implementation. void dispatchProtocolMessage(const String16& message) override; String16 stateJSON() override; void addInspectedObject(std::unique_ptr) override; - void schedulePauseOnNextStatement(const String16& breakReason, std::unique_ptr data) override; + void schedulePauseOnNextStatement(const String16& breakReason, const String16& breakDetails) override; void cancelPauseOnNextStatement() override; - void breakProgram(const String16& breakReason, std::unique_ptr data) override; + void breakProgram(const String16& breakReason, const String16& breakDetails) override; void setSkipAllPauses(bool) override; void resume() override; void stepOver() override; + std::unique_ptr> searchInTextByLines(const String16& text, const String16& query, bool caseSensitive, bool isRegex) override; void releaseObjectGroup(const String16& objectGroup) override; - v8::Local findObject(ErrorString*, const String16& objectId, v8::Local* = nullptr, String16* groupName = nullptr) override; - std::unique_ptr wrapObject(v8::Local, v8::Local, const String16& groupName, bool generatePreview) override; - std::unique_ptr wrapTable(v8::Local, v8::Local table, v8::Local columns); + bool unwrapObject(ErrorString*, const String16& objectId, v8::Local*, v8::Local*, String16* objectGroup) override; + std::unique_ptr wrapObject(v8::Local, v8::Local, const String16& groupName) override; V8InspectorSession::Inspectable* inspectedObject(unsigned num); static const unsigned kInspectedObjectBufferSize = 5; private: - V8InspectorSessionImpl(V8DebuggerImpl*, int contextGroupId, protocol::FrontendChannel*, V8InspectorSessionClient*, const String16* state); + V8InspectorSessionImpl(V8InspectorImpl*, int contextGroupId, protocol::FrontendChannel*, const String16* state); protocol::DictionaryValue* agentState(const String16& name); int m_contextGroupId; - V8DebuggerImpl* m_debugger; - V8InspectorSessionClient* m_client; + V8InspectorImpl* m_inspector; bool m_customObjectFormatterEnabled; protocol::UberDispatcher m_dispatcher; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.cpp index 0761f87e0d7..57712a9c107 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.cpp @@ -5,7 +5,7 @@ #include "platform/v8_inspector/V8ProfilerAgentImpl.h" #include "platform/v8_inspector/Atomics.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" @@ -13,6 +13,9 @@ #include +#define ENSURE_V8_VERSION(major, minor) \ + (V8_MAJOR_VERSION * 1000 + V8_MINOR_VERSION >= (major) * 1000 + (minor)) + namespace blink { namespace ProfilerAgentState { @@ -102,9 +105,9 @@ std::unique_ptr createCPUProfile(v8::Isolate* is return profile; } -std::unique_ptr currentDebugLocation(V8DebuggerImpl* debugger) +std::unique_ptr currentDebugLocation(V8InspectorImpl* inspector) { - std::unique_ptr callStack = debugger->captureStackTrace(1); + std::unique_ptr callStack = inspector->captureStackTrace(1); std::unique_ptr location = protocol::Debugger::Location::create() .setScriptId(callStack->topScriptId()) .setLineNumber(callStack->topLineNumber()).build(); @@ -127,7 +130,8 @@ class V8ProfilerAgentImpl::ProfileDescriptor { V8ProfilerAgentImpl::V8ProfilerAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state) : m_session(session) - , m_isolate(m_session->debugger()->isolate()) + , m_isolate(m_session->inspector()->isolate()) + , m_profiler(nullptr) , m_state(state) , m_frontend(frontendChannel) , m_enabled(false) @@ -137,6 +141,10 @@ V8ProfilerAgentImpl::V8ProfilerAgentImpl(V8InspectorSessionImpl* session, protoc V8ProfilerAgentImpl::~V8ProfilerAgentImpl() { +#if ENSURE_V8_VERSION(5, 4) + if (m_profiler) + m_profiler->Dispose(); +#endif } void V8ProfilerAgentImpl::consoleProfile(const String16& title) @@ -146,7 +154,7 @@ void V8ProfilerAgentImpl::consoleProfile(const String16& title) String16 id = nextProfileId(); m_startedProfiles.push_back(ProfileDescriptor(id, title)); startProfiling(id); - m_frontend.consoleProfileStarted(id, currentDebugLocation(m_session->debugger()), title); + m_frontend.consoleProfileStarted(id, currentDebugLocation(m_session->inspector()), title); } void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) @@ -177,7 +185,7 @@ void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) std::unique_ptr profile = stopProfiling(id, true); if (!profile) return; - std::unique_ptr location = currentDebugLocation(m_session->debugger()); + std::unique_ptr location = currentDebugLocation(m_session->inspector()); m_frontend.consoleProfileFinished(id, std::move(location), std::move(profile), resolvedTitle); } @@ -186,6 +194,10 @@ void V8ProfilerAgentImpl::enable(ErrorString*) if (m_enabled) return; m_enabled = true; +#if ENSURE_V8_VERSION(5, 4) + DCHECK(!m_profiler); + m_profiler = v8::CpuProfiler::New(m_isolate); +#endif m_state->setBoolean(ProfilerAgentState::profilerEnabled, true); } @@ -197,6 +209,10 @@ void V8ProfilerAgentImpl::disable(ErrorString* errorString) stopProfiling(m_startedProfiles[i - 1].m_id, false); m_startedProfiles.clear(); stop(nullptr, nullptr); +#if ENSURE_V8_VERSION(5, 4) + m_profiler->Dispose(); + m_profiler = nullptr; +#endif m_enabled = false; m_state->setBoolean(ProfilerAgentState::profilerEnabled, false); } @@ -208,7 +224,7 @@ void V8ProfilerAgentImpl::setSamplingInterval(ErrorString* error, int interval) return; } m_state->setInteger(ProfilerAgentState::samplingInterval, interval); - m_isolate->GetCpuProfiler()->SetSamplingInterval(interval); + profiler()->SetSamplingInterval(interval); } void V8ProfilerAgentImpl::restore() @@ -217,10 +233,14 @@ void V8ProfilerAgentImpl::restore() if (!m_state->booleanProperty(ProfilerAgentState::profilerEnabled, false)) return; m_enabled = true; +#if ENSURE_V8_VERSION(5, 4) + DCHECK(!m_profiler); + m_profiler = v8::CpuProfiler::New(m_isolate); +#endif int interval = 0; m_state->getInteger(ProfilerAgentState::samplingInterval, &interval); if (interval) - m_isolate->GetCpuProfiler()->SetSamplingInterval(interval); + profiler()->SetSamplingInterval(interval); if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling, false)) { ErrorString error; start(&error); @@ -239,7 +259,6 @@ void V8ProfilerAgentImpl::start(ErrorString* error) m_frontendInitiatedProfileId = nextProfileId(); startProfiling(m_frontendInitiatedProfileId); m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true); - m_session->client()->profilingStarted(); } void V8ProfilerAgentImpl::stop(ErrorString* errorString, std::unique_ptr* profile) @@ -258,7 +277,6 @@ void V8ProfilerAgentImpl::stop(ErrorString* errorString, std::unique_ptrsetBoolean(ProfilerAgentState::userInitiatedProfiling, false); - m_session->client()->profilingStopped(); } String16 V8ProfilerAgentImpl::nextProfileId() @@ -269,13 +287,13 @@ String16 V8ProfilerAgentImpl::nextProfileId() void V8ProfilerAgentImpl::startProfiling(const String16& title) { v8::HandleScope handleScope(m_isolate); - m_isolate->GetCpuProfiler()->StartProfiling(toV8String(m_isolate, title), true); + profiler()->StartProfiling(toV8String(m_isolate, title), true); } std::unique_ptr V8ProfilerAgentImpl::stopProfiling(const String16& title, bool serialize) { v8::HandleScope handleScope(m_isolate); - v8::CpuProfile* profile = m_isolate->GetCpuProfiler()->StopProfiling(toV8String(m_isolate, title)); + v8::CpuProfile* profile = profiler()->StopProfiling(toV8String(m_isolate, title)); if (!profile) return nullptr; std::unique_ptr result; @@ -290,4 +308,13 @@ bool V8ProfilerAgentImpl::isRecording() const return m_recordingCPUProfile || !m_startedProfiles.empty(); } +v8::CpuProfiler* V8ProfilerAgentImpl::profiler() +{ +#if ENSURE_V8_VERSION(5, 4) + return m_profiler; +#else + return m_isolate->GetCpuProfiler(); +#endif +} + } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.h index 03b8f703ae1..4bbe00be679 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8ProfilerAgentImpl.h @@ -12,6 +12,7 @@ #include namespace v8 { +class CpuProfiler; class Isolate; } @@ -39,6 +40,7 @@ class V8ProfilerAgentImpl : public protocol::Profiler::Backend { private: String16 nextProfileId(); + v8::CpuProfiler* profiler(); void startProfiling(const String16& title); std::unique_ptr stopProfiling(const String16& title, bool serialize); @@ -47,6 +49,7 @@ class V8ProfilerAgentImpl : public protocol::Profiler::Backend { V8InspectorSessionImpl* m_session; v8::Isolate* m_isolate; + v8::CpuProfiler* m_profiler; protocol::DictionaryValue* m_state; protocol::Profiler::Frontend m_frontend; bool m_enabled; @@ -58,5 +61,4 @@ class V8ProfilerAgentImpl : public protocol::Profiler::Backend { } // namespace blink - #endif // !defined(V8ProfilerAgentImpl_h) diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.cpp index 304b715f797..96cd350d814 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.cpp @@ -5,20 +5,20 @@ #include "platform/v8_inspector/V8Regex.h" #include "platform/v8_inspector/V8Compat.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" #include namespace blink { -V8Regex::V8Regex(V8DebuggerImpl* debugger, const String16& pattern, bool caseSensitive, bool multiline) - : m_debugger(debugger) +V8Regex::V8Regex(V8InspectorImpl* inspector, const String16& pattern, bool caseSensitive, bool multiline) + : m_inspector(inspector) { - v8::Isolate* isolate = m_debugger->isolate(); + v8::Isolate* isolate = m_inspector->isolate(); v8::HandleScope handleScope(isolate); - v8::Local context = m_debugger->regexContext(); + v8::Local context = m_inspector->regexContext(); v8::Context::Scope contextScope(context); v8::TryCatch tryCatch(isolate); @@ -49,9 +49,9 @@ int V8Regex::match(const String16& string, int startFrom, int* matchLength) cons if (string.length() > INT_MAX) return -1; - v8::Isolate* isolate = m_debugger->isolate(); + v8::Isolate* isolate = m_inspector->isolate(); v8::HandleScope handleScope(isolate); - v8::Local context = m_debugger->regexContext(); + v8::Local context = m_inspector->regexContext(); v8::MicrotasksScope microtasks(isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::TryCatch tryCatch(isolate); diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.h index 983717d971a..e4900e2d540 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8Regex.h @@ -11,7 +11,7 @@ namespace blink { -class V8DebuggerImpl; +class V8InspectorImpl; enum MultilineMode { MultilineDisabled, @@ -21,13 +21,13 @@ enum MultilineMode { class V8Regex { PROTOCOL_DISALLOW_COPY(V8Regex); public: - V8Regex(V8DebuggerImpl*, const String16&, bool caseSensitive, bool multiline = false); + V8Regex(V8InspectorImpl*, const String16&, bool caseSensitive, bool multiline = false); int match(const String16&, int startFrom = 0, int* matchLength = 0) const; bool isValid() const { return !m_regex.IsEmpty(); } const String16& errorMessage() const { return m_errorMessage; } private: - V8DebuggerImpl* m_debugger; + V8InspectorImpl* m_inspector; v8::Global m_regex; String16 m_errorMessage; }; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.cpp index c9a235ae29e..79d8cc9ce00 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.cpp @@ -30,15 +30,20 @@ #include "platform/v8_inspector/V8RuntimeAgentImpl.h" +#include "platform/inspector_protocol/Parser.h" #include "platform/inspector_protocol/Values.h" #include "platform/v8_inspector/InjectedScript.h" #include "platform/v8_inspector/InspectedContext.h" #include "platform/v8_inspector/RemoteObjectId.h" +#include "platform/v8_inspector/V8Compat.h" #include "platform/v8_inspector/V8ConsoleMessage.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8Debugger.h" +#include "platform/v8_inspector/V8DebuggerAgentImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" +#include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" namespace blink { @@ -57,11 +62,165 @@ static bool hasInternalError(ErrorString* errorString, bool hasError) return hasError; } +namespace { + +template +class ProtocolPromiseHandler { +public: + static void add(V8InspectorImpl* inspector, v8::Local context, v8::MaybeLocal value, const String16& notPromiseError, int contextGroupId, int executionContextId, const String16& objectGroup, bool returnByValue, bool generatePreview, std::unique_ptr callback) + { + if (value.IsEmpty()) { + callback->sendFailure("Internal error"); + return; + } + if (!value.ToLocalChecked()->IsPromise()) { + callback->sendFailure(notPromiseError); + return; + } + v8::Local promise = v8::Local::Cast(value.ToLocalChecked()); + Callback* rawCallback = callback.get(); + ProtocolPromiseHandler* handler = new ProtocolPromiseHandler(inspector, contextGroupId, executionContextId, objectGroup, returnByValue, generatePreview, std::move(callback)); + v8::Local wrapper = handler->m_wrapper.Get(inspector->isolate()); + + v8::Local thenCallbackFunction = V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, thenCallback, wrapper, 0).ToLocalChecked(); + if (promise->Then(context, thenCallbackFunction).IsEmpty()) { + rawCallback->sendFailure("Internal error"); + return; + } + v8::Local catchCallbackFunction = V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, catchCallback, wrapper, 0).ToLocalChecked(); + if (promise->Catch(context, catchCallbackFunction).IsEmpty()) { + rawCallback->sendFailure("Internal error"); + return; + } + } +private: + static void thenCallback(const v8::FunctionCallbackInfo& info) + { + ProtocolPromiseHandler* handler = static_cast*>(info.Data().As()->Value()); + DCHECK(handler); + v8::Local value = info.Length() > 0 ? info[0] : v8::Local::Cast(v8::Undefined(info.GetIsolate())); + handler->m_callback->sendSuccess(handler->wrapObject(value), Maybe(), Maybe()); + } + + static void catchCallback(const v8::FunctionCallbackInfo& info) + { + ProtocolPromiseHandler* handler = static_cast*>(info.Data().As()->Value()); + DCHECK(handler); + v8::Local value = info.Length() > 0 ? info[0] : v8::Local::Cast(v8::Undefined(info.GetIsolate())); + + std::unique_ptr exceptionDetails; + std::unique_ptr stack = handler->m_inspector->debugger()->captureStackTrace(true); + if (stack) { + exceptionDetails = protocol::Runtime::ExceptionDetails::create() + .setText("Promise was rejected") + .setLineNumber(!stack->isEmpty() ? stack->topLineNumber() : 0) + .setColumnNumber(!stack->isEmpty() ? stack->topColumnNumber() : 0) + .setScriptId(!stack->isEmpty() ? stack->topScriptId() : String16()) + .setStackTrace(stack->buildInspectorObjectImpl()) + .build(); + } + handler->m_callback->sendSuccess(handler->wrapObject(value), true, std::move(exceptionDetails)); + } + + ProtocolPromiseHandler(V8InspectorImpl* inspector, int contextGroupId, int executionContextId, const String16& objectGroup, bool returnByValue, bool generatePreview, std::unique_ptr callback) + : m_inspector(inspector) + , m_contextGroupId(contextGroupId) + , m_executionContextId(executionContextId) + , m_objectGroup(objectGroup) + , m_returnByValue(returnByValue) + , m_generatePreview(generatePreview) + , m_callback(std::move(callback)) + , m_wrapper(inspector->isolate(), v8::External::New(inspector->isolate(), this)) + { + m_wrapper.SetWeak(this, cleanup, v8::WeakCallbackType::kParameter); + } + + static void cleanup(const v8::WeakCallbackInfo>& data) + { + if (!data.GetParameter()->m_wrapper.IsEmpty()) { + data.GetParameter()->m_wrapper.Reset(); + data.SetSecondPassCallback(cleanup); + } else { + data.GetParameter()->m_callback->sendFailure("Promise was collected"); + delete data.GetParameter(); + } + } + + std::unique_ptr wrapObject(v8::Local value) + { + ErrorString errorString; + InjectedScript::ContextScope scope(&errorString, m_inspector, m_contextGroupId, m_executionContextId); + if (!scope.initialize()) { + m_callback->sendFailure(errorString); + return nullptr; + } + std::unique_ptr wrappedValue = scope.injectedScript()->wrapObject(&errorString, value, m_objectGroup, m_returnByValue, m_generatePreview); + if (!wrappedValue) { + m_callback->sendFailure(errorString); + return nullptr; + } + return wrappedValue; + } + + V8InspectorImpl* m_inspector; + int m_contextGroupId; + int m_executionContextId; + String16 m_objectGroup; + bool m_returnByValue; + bool m_generatePreview; + std::unique_ptr m_callback; + v8::Global m_wrapper; +}; + +template +bool wrapEvaluateResultAsync(InjectedScript* injectedScript, v8::MaybeLocal maybeResultValue, const v8::TryCatch& tryCatch, const String16& objectGroup, bool returnByValue, bool generatePreview, Callback* callback) +{ + std::unique_ptr result; + Maybe wasThrown; + Maybe exceptionDetails; + + ErrorString errorString; + injectedScript->wrapEvaluateResult(&errorString, + maybeResultValue, + tryCatch, + objectGroup, + returnByValue, + generatePreview, + &result, + &wasThrown, + &exceptionDetails); + if (errorString.isEmpty()) { + callback->sendSuccess(std::move(result), wasThrown, exceptionDetails); + return true; + } + callback->sendFailure(errorString); + return false; +} + +int ensureContext(ErrorString* errorString, V8InspectorImpl* inspector, int contextGroupId, const Maybe& executionContextId) +{ + int contextId; + if (executionContextId.isJust()) { + contextId = executionContextId.fromJust(); + } else { + v8::HandleScope handles(inspector->isolate()); + v8::Local defaultContext = inspector->client()->ensureDefaultContextInGroup(contextGroupId); + if (defaultContext.IsEmpty()) { + *errorString = "Cannot find default execution context"; + return 0; + } + contextId = V8Debugger::contextId(defaultContext); + } + return contextId; +} + +} // namespace + V8RuntimeAgentImpl::V8RuntimeAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* FrontendChannel, protocol::DictionaryValue* state) : m_session(session) , m_state(state) , m_frontend(FrontendChannel) - , m_debugger(session->debugger()) + , m_inspector(session->inspector()) , m_enabled(false) { } @@ -71,7 +230,6 @@ V8RuntimeAgentImpl::~V8RuntimeAgentImpl() } void V8RuntimeAgentImpl::evaluate( - ErrorString* errorString, const String16& expression, const Maybe& objectGroup, const Maybe& includeCommandLineAPI, @@ -80,34 +238,31 @@ void V8RuntimeAgentImpl::evaluate( const Maybe& returnByValue, const Maybe& generatePreview, const Maybe& userGesture, - std::unique_ptr* result, - Maybe* wasThrown, - Maybe* exceptionDetails) + const Maybe& awaitPromise, + std::unique_ptr callback) { - int contextId; - if (executionContextId.isJust()) { - contextId = executionContextId.fromJust(); - } else { - v8::HandleScope handles(m_debugger->isolate()); - v8::Local defaultContext = m_debugger->client()->ensureDefaultContextInGroup(m_session->contextGroupId()); - if (defaultContext.IsEmpty()) { - *errorString = "Cannot find default execution context"; - return; - } - contextId = V8DebuggerImpl::contextId(defaultContext); + ErrorString errorString; + int contextId = ensureContext(&errorString, m_inspector, m_session->contextGroupId(), executionContextId); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; } - InjectedScript::ContextScope scope(errorString, m_debugger, m_session->contextGroupId(), contextId); - if (!scope.initialize()) + InjectedScript::ContextScope scope(&errorString, m_inspector, m_session->contextGroupId(), contextId); + if (!scope.initialize()) { + callback->sendFailure(errorString); return; + } if (doNotPauseOnExceptionsAndMuteConsole.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole(); if (userGesture.fromMaybe(false)) scope.pretendUserGesture(); - if (includeCommandLineAPI.fromMaybe(false) && !scope.installCommandLineAPI()) + if (includeCommandLineAPI.fromMaybe(false) && !scope.installCommandLineAPI()) { + callback->sendFailure(errorString); return; + } bool evalIsDisabled = !scope.context()->IsCodeGenerationFromStringsAllowed(); // Temporarily enable allow evals for inspector. @@ -115,28 +270,62 @@ void V8RuntimeAgentImpl::evaluate( scope.context()->AllowCodeGenerationFromStrings(true); v8::MaybeLocal maybeResultValue; - v8::Local script = m_debugger->compileInternalScript(scope.context(), toV8String(m_debugger->isolate(), expression), String16()); + v8::Local script = m_inspector->compileScript(scope.context(), toV8String(m_inspector->isolate(), expression), String16(), false); if (!script.IsEmpty()) - maybeResultValue = m_debugger->runCompiledScript(scope.context(), script); + maybeResultValue = m_inspector->runCompiledScript(scope.context(), script); if (evalIsDisabled) scope.context()->AllowCodeGenerationFromStrings(false); // Re-initialize after running client's code, as it could have destroyed context or session. - if (!scope.initialize()) + if (!scope.initialize()) { + callback->sendFailure(errorString); return; - scope.injectedScript()->wrapEvaluateResult(errorString, + } + + if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { + wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), callback.get()); + return; + } + ProtocolPromiseHandler::add( + m_inspector, + scope.context(), maybeResultValue, - scope.tryCatch(), + "Result of the evaluation is not a promise", + m_session->contextGroupId(), + scope.injectedScript()->context()->contextId(), objectGroup.fromMaybe(""), returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), - result, - wasThrown, - exceptionDetails); + std::move(callback)); +} + +void V8RuntimeAgentImpl::awaitPromise( + const String16& promiseObjectId, + const Maybe& returnByValue, + const Maybe& generatePreview, + std::unique_ptr callback) +{ + ErrorString errorString; + InjectedScript::ObjectScope scope(&errorString, m_inspector, m_session->contextGroupId(), promiseObjectId); + if (!scope.initialize()) { + callback->sendFailure(errorString); + return; + } + ProtocolPromiseHandler::add( + m_inspector, + scope.context(), + scope.object(), + "Could not find promise with given id", + m_session->contextGroupId(), + scope.injectedScript()->context()->contextId(), + scope.objectGroupName(), + returnByValue.fromMaybe(false), + generatePreview.fromMaybe(false), + std::move(callback)); } -void V8RuntimeAgentImpl::callFunctionOn(ErrorString* errorString, +void V8RuntimeAgentImpl::callFunctionOn( const String16& objectId, const String16& expression, const Maybe>& optionalArguments, @@ -144,12 +333,15 @@ void V8RuntimeAgentImpl::callFunctionOn(ErrorString* errorString, const Maybe& returnByValue, const Maybe& generatePreview, const Maybe& userGesture, - std::unique_ptr* result, - Maybe* wasThrown) + const Maybe& awaitPromise, + std::unique_ptr callback) { - InjectedScript::ObjectScope scope(errorString, m_debugger, m_session->contextGroupId(), objectId); - if (!scope.initialize()) + ErrorString errorString; + InjectedScript::ObjectScope scope(&errorString, m_inspector, m_session->contextGroupId(), objectId); + if (!scope.initialize()) { + callback->sendFailure(errorString); return; + } std::unique_ptr[]> argv = nullptr; int argc = 0; @@ -159,8 +351,10 @@ void V8RuntimeAgentImpl::callFunctionOn(ErrorString* errorString, argv.reset(new v8::Local[argc]); for (int i = 0; i < argc; ++i) { v8::Local argumentValue; - if (!scope.injectedScript()->resolveCallArgument(errorString, arguments->get(i)).ToLocal(&argumentValue)) + if (!scope.injectedScript()->resolveCallArgument(&errorString, arguments->get(i)).ToLocal(&argumentValue)) { + callback->sendFailure(errorString); return; + } argv[i] = argumentValue; } } @@ -170,28 +364,47 @@ void V8RuntimeAgentImpl::callFunctionOn(ErrorString* errorString, if (userGesture.fromMaybe(false)) scope.pretendUserGesture(); - v8::MaybeLocal maybeFunctionValue = m_debugger->compileAndRunInternalScript(scope.context(), toV8String(m_debugger->isolate(), "(" + expression + ")")); + v8::MaybeLocal maybeFunctionValue = m_inspector->compileAndRunInternalScript(scope.context(), toV8String(m_inspector->isolate(), "(" + expression + ")")); // Re-initialize after running client's code, as it could have destroyed context or session. - if (!scope.initialize()) + if (!scope.initialize()) { + callback->sendFailure(errorString); return; + } if (scope.tryCatch().HasCaught()) { - scope.injectedScript()->wrapEvaluateResult(errorString, maybeFunctionValue, scope.tryCatch(), scope.objectGroupName(), false, false, result, wasThrown, nullptr); + wrapEvaluateResultAsync(scope.injectedScript(), maybeFunctionValue, scope.tryCatch(), scope.objectGroupName(), false, false, callback.get()); return; } v8::Local functionValue; if (!maybeFunctionValue.ToLocal(&functionValue) || !functionValue->IsFunction()) { - *errorString = "Given expression does not evaluate to a function"; + callback->sendFailure("Given expression does not evaluate to a function"); return; } - v8::MaybeLocal maybeResultValue = m_debugger->callFunction(functionValue.As(), scope.context(), scope.object(), argc, argv.get()); + v8::MaybeLocal maybeResultValue = m_inspector->callFunction(functionValue.As(), scope.context(), scope.object(), argc, argv.get()); // Re-initialize after running client's code, as it could have destroyed context or session. - if (!scope.initialize()) + if (!scope.initialize()) { + callback->sendFailure(errorString); + return; + } + + if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { + wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, scope.tryCatch(), scope.objectGroupName(), returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), callback.get()); return; + } - scope.injectedScript()->wrapEvaluateResult(errorString, maybeResultValue, scope.tryCatch(), scope.objectGroupName(), returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), result, wasThrown, nullptr); + ProtocolPromiseHandler::add( + m_inspector, + scope.context(), + maybeResultValue, + "Result of the function call is not a promise", + m_session->contextGroupId(), + scope.injectedScript()->context()->contextId(), + scope.objectGroupName(), + returnByValue.fromMaybe(false), + generatePreview.fromMaybe(false), + std::move(callback)); } void V8RuntimeAgentImpl::getProperties( @@ -206,7 +419,7 @@ void V8RuntimeAgentImpl::getProperties( { using protocol::Runtime::InternalPropertyDescriptor; - InjectedScript::ObjectScope scope(errorString, m_debugger, m_session->contextGroupId(), objectId); + InjectedScript::ObjectScope scope(errorString, m_inspector, m_session->contextGroupId(), objectId); if (!scope.initialize()) return; @@ -221,7 +434,7 @@ void V8RuntimeAgentImpl::getProperties( if (!errorString->isEmpty() || exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false)) return; v8::Local propertiesArray; - if (hasInternalError(errorString, !m_debugger->internalProperties(scope.context(), scope.object()).ToLocal(&propertiesArray))) + if (hasInternalError(errorString, !m_inspector->debugger()->internalProperties(scope.context(), scope.object()).ToLocal(&propertiesArray))) return; std::unique_ptr> propertiesProtocolArray = protocol::Array::create(); for (uint32_t i = 0; i < propertiesArray->Length(); i += 2) { @@ -245,7 +458,7 @@ void V8RuntimeAgentImpl::getProperties( void V8RuntimeAgentImpl::releaseObject(ErrorString* errorString, const String16& objectId) { - InjectedScript::ObjectScope scope(errorString, m_debugger, m_session->contextGroupId(), objectId); + InjectedScript::ObjectScope scope(errorString, m_inspector, m_session->contextGroupId(), objectId); if (!scope.initialize()) return; scope.injectedScript()->releaseObject(objectId); @@ -258,7 +471,7 @@ void V8RuntimeAgentImpl::releaseObjectGroup(ErrorString*, const String16& object void V8RuntimeAgentImpl::run(ErrorString* errorString) { - m_session->client()->resumeStartup(); + m_inspector->client()->resumeStartup(m_session->contextGroupId()); } void V8RuntimeAgentImpl::setCustomObjectFormatterEnabled(ErrorString*, bool enabled) @@ -269,7 +482,7 @@ void V8RuntimeAgentImpl::setCustomObjectFormatterEnabled(ErrorString*, bool enab void V8RuntimeAgentImpl::discardConsoleEntries(ErrorString*) { - V8ConsoleMessageStorage* storage = m_session->debugger()->ensureConsoleMessageStorage(m_session->contextGroupId()); + V8ConsoleMessageStorage* storage = m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId()); storage->clear(); } @@ -277,7 +490,7 @@ void V8RuntimeAgentImpl::compileScript(ErrorString* errorString, const String16& expression, const String16& sourceURL, bool persistScript, - int executionContextId, + const Maybe& executionContextId, Maybe* scriptId, Maybe* exceptionDetails) { @@ -285,11 +498,18 @@ void V8RuntimeAgentImpl::compileScript(ErrorString* errorString, *errorString = "Runtime agent is not enabled"; return; } - InjectedScript::ContextScope scope(errorString, m_debugger, m_session->contextGroupId(), executionContextId); + int contextId = ensureContext(errorString, m_inspector, m_session->contextGroupId(), executionContextId); + if (!errorString->isEmpty()) + return; + InjectedScript::ContextScope scope(errorString, m_inspector, m_session->contextGroupId(), contextId); if (!scope.initialize()) return; - v8::Local script = m_debugger->compileInternalScript(scope.context(), toV8String(m_debugger->isolate(), expression), sourceURL); + if (!persistScript) + m_inspector->debugger()->muteScriptParsedEvents(); + v8::Local script = m_inspector->compileScript(scope.context(), toV8String(m_inspector->isolate(), expression), sourceURL, false); + if (!persistScript) + m_inspector->debugger()->unmuteScriptParsedEvents(); if (script.IsEmpty()) { v8::Local message = scope.tryCatch().Message(); if (!message.IsEmpty()) @@ -303,55 +523,81 @@ void V8RuntimeAgentImpl::compileScript(ErrorString* errorString, return; String16 scriptValueId = String16::fromInteger(script->GetUnboundScript()->GetId()); - std::unique_ptr> global(new v8::Global(m_debugger->isolate(), script)); + std::unique_ptr> global(new v8::Global(m_inspector->isolate(), script)); m_compiledScripts[scriptValueId] = std::move(global); *scriptId = scriptValueId; } -void V8RuntimeAgentImpl::runScript(ErrorString* errorString, +void V8RuntimeAgentImpl::runScript( const String16& scriptId, - int executionContextId, + const Maybe& executionContextId, const Maybe& objectGroup, const Maybe& doNotPauseOnExceptionsAndMuteConsole, const Maybe& includeCommandLineAPI, - std::unique_ptr* result, - Maybe* exceptionDetails) + const Maybe& returnByValue, + const Maybe& generatePreview, + const Maybe& awaitPromise, + std::unique_ptr callback) { if (!m_enabled) { - *errorString = "Runtime agent is not enabled"; + callback->sendFailure("Runtime agent is not enabled"); return; } auto it = m_compiledScripts.find(scriptId); if (it == m_compiledScripts.end()) { - *errorString = "Script execution failed"; + callback->sendFailure("No script with given id"); return; } - InjectedScript::ContextScope scope(errorString, m_debugger, m_session->contextGroupId(), executionContextId); - if (!scope.initialize()) + ErrorString errorString; + int contextId = ensureContext(&errorString, m_inspector, m_session->contextGroupId(), executionContextId); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); return; + } + + InjectedScript::ContextScope scope(&errorString, m_inspector, m_session->contextGroupId(), contextId); + if (!scope.initialize()) { + callback->sendFailure(errorString); + return; + } if (doNotPauseOnExceptionsAndMuteConsole.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole(); std::unique_ptr> scriptWrapper = std::move(it->second); m_compiledScripts.erase(it); - v8::Local script = scriptWrapper->Get(m_debugger->isolate()); + v8::Local script = scriptWrapper->Get(m_inspector->isolate()); if (script.IsEmpty()) { - *errorString = "Script execution failed"; + callback->sendFailure("Script execution failed"); return; } if (includeCommandLineAPI.fromMaybe(false) && !scope.installCommandLineAPI()) return; - v8::MaybeLocal maybeResultValue = m_debugger->runCompiledScript(scope.context(), script); + v8::MaybeLocal maybeResultValue = m_inspector->runCompiledScript(scope.context(), script); // Re-initialize after running client's code, as it could have destroyed context or session. if (!scope.initialize()) return; - scope.injectedScript()->wrapEvaluateResult(errorString, maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), false, false, result, nullptr, exceptionDetails); + + if (!awaitPromise.fromMaybe(false) || scope.tryCatch().HasCaught()) { + wrapEvaluateResultAsync(scope.injectedScript(), maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), callback.get()); + return; + } + ProtocolPromiseHandler::add( + m_inspector, + scope.context(), + maybeResultValue.ToLocalChecked(), + "Result of the script execution is not a promise", + m_session->contextGroupId(), + scope.injectedScript()->context()->contextId(), + objectGroup.fromMaybe(""), + returnByValue.fromMaybe(false), + generatePreview.fromMaybe(false), + std::move(callback)); } void V8RuntimeAgentImpl::restore() @@ -369,12 +615,12 @@ void V8RuntimeAgentImpl::enable(ErrorString* errorString) { if (m_enabled) return; - m_session->client()->runtimeEnabled(); + m_inspector->client()->beginEnsureAllContextsInGroup(m_session->contextGroupId()); m_enabled = true; m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, true); - m_session->debugger()->enableStackCapturingIfNeeded(); + m_inspector->enableStackCapturingIfNeeded(); m_session->reportAllContexts(this); - V8ConsoleMessageStorage* storage = m_session->debugger()->ensureConsoleMessageStorage(m_session->contextGroupId()); + V8ConsoleMessageStorage* storage = m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId()); for (const auto& message : storage->messages()) reportMessage(message.get(), false); } @@ -385,17 +631,17 @@ void V8RuntimeAgentImpl::disable(ErrorString* errorString) return; m_enabled = false; m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, false); - m_session->debugger()->disableStackCapturingIfNeeded(); + m_inspector->disableStackCapturingIfNeeded(); m_session->discardInjectedScripts(); reset(); - m_session->client()->runtimeDisabled(); + m_inspector->client()->endEnsureAllContextsInGroup(m_session->contextGroupId()); } void V8RuntimeAgentImpl::reset() { m_compiledScripts.clear(); if (m_enabled) { - if (const V8DebuggerImpl::ContextByIdMap* contexts = m_debugger->contextGroup(m_session->contextGroupId())) { + if (const V8InspectorImpl::ContextByIdMap* contexts = m_inspector->contextGroup(m_session->contextGroupId())) { for (auto& idContext : *contexts) idContext.second->setReported(false); } @@ -410,10 +656,10 @@ void V8RuntimeAgentImpl::reportExecutionContextCreated(InspectedContext* context context->setReported(true); std::unique_ptr description = protocol::Runtime::ExecutionContextDescription::create() .setId(context->contextId()) - .setIsDefault(context->isDefault()) .setName(context->humanReadableName()) - .setOrigin(context->origin()) - .setFrameId(context->frameId()).build(); + .setOrigin(context->origin()).build(); + if (!context->auxData().isEmpty()) + description->setAuxData(protocol::DictionaryValue::cast(parseJSON(context->auxData()))); m_frontend.executionContextCreated(std::move(description)); } diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.h index 7b33379a0c2..8594ce8e2d5 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8RuntimeAgentImpl.h @@ -43,7 +43,7 @@ class InjectedScript; class InspectedContext; class RemoteObjectIdBase; class V8ConsoleMessage; -class V8DebuggerImpl; +class V8InspectorImpl; class V8InspectorSessionImpl; namespace protocol { @@ -62,7 +62,7 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { // Part of the protocol. void enable(ErrorString*) override; void disable(ErrorString*) override; - void evaluate(ErrorString*, + void evaluate( const String16& expression, const Maybe& objectGroup, const Maybe& includeCommandLineAPI, @@ -71,10 +71,14 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { const Maybe& returnByValue, const Maybe& generatePreview, const Maybe& userGesture, - std::unique_ptr* result, - Maybe* wasThrown, - Maybe*) override; - void callFunctionOn(ErrorString*, + const Maybe& awaitPromise, + std::unique_ptr) override; + void awaitPromise( + const String16& promiseObjectId, + const Maybe& returnByValue, + const Maybe& generatePreview, + std::unique_ptr) override; + void callFunctionOn( const String16& objectId, const String16& expression, const Maybe>& optionalArguments, @@ -82,8 +86,8 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { const Maybe& returnByValue, const Maybe& generatePreview, const Maybe& userGesture, - std::unique_ptr* result, - Maybe* wasThrown) override; + const Maybe& awaitPromise, + std::unique_ptr) override; void releaseObject(ErrorString*, const String16& objectId) override; void getProperties(ErrorString*, const String16& objectId, @@ -101,17 +105,19 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { const String16& expression, const String16& sourceURL, bool persistScript, - int executionContextId, + const Maybe& executionContextId, Maybe*, Maybe*) override; - void runScript(ErrorString*, + void runScript( const String16&, - int executionContextId, + const Maybe& executionContextId, const Maybe& objectGroup, const Maybe& doNotPauseOnExceptionsAndMuteConsole, const Maybe& includeCommandLineAPI, - std::unique_ptr* result, - Maybe*) override; + const Maybe& returnByValue, + const Maybe& generatePreview, + const Maybe& awaitPromise, + std::unique_ptr) override; void reset(); void reportExecutionContextCreated(InspectedContext*); @@ -126,7 +132,7 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { V8InspectorSessionImpl* m_session; protocol::DictionaryValue* m_state; protocol::Runtime::Frontend m_frontend; - V8DebuggerImpl* m_debugger; + V8InspectorImpl* m_inspector; bool m_enabled; protocol::HashMap>> m_compiledScripts; }; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.cpp index 343234c0227..0a8e6e1e489 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.cpp @@ -6,7 +6,7 @@ #include "platform/inspector_protocol/Platform.h" #include "platform/inspector_protocol/String16.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8Debugger.h" #include "platform/v8_inspector/V8StringUtil.h" #include @@ -93,7 +93,7 @@ std::unique_ptr V8StackTraceImpl::Frame::buildInsp .build(); } -V8StackTraceImpl::Frame V8StackTraceImpl::Frame::isolatedCopy() const +V8StackTraceImpl::Frame V8StackTraceImpl::Frame::clone() const { return Frame(m_functionName.isolatedCopy(), m_scriptId.isolatedCopy(), m_scriptName.isolatedCopy(), m_lineNumber, m_columnNumber); } @@ -105,7 +105,7 @@ void V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(v8::Isolate* is } // static -std::unique_ptr V8StackTraceImpl::create(V8DebuggerImpl* debugger, int contextGroupId, v8::Local stackTrace, size_t maxStackSize, const String16& description) +std::unique_ptr V8StackTraceImpl::create(V8Debugger* debugger, int contextGroupId, v8::Local stackTrace, size_t maxStackSize, const String16& description) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope scope(isolate); @@ -147,7 +147,7 @@ std::unique_ptr V8StackTraceImpl::create(V8DebuggerImpl* debug return result; } -std::unique_ptr V8StackTraceImpl::capture(V8DebuggerImpl* debugger, int contextGroupId, size_t maxStackSize, const String16& description) +std::unique_ptr V8StackTraceImpl::capture(V8Debugger* debugger, int contextGroupId, size_t maxStackSize, const String16& description) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope handleScope(isolate); @@ -161,28 +161,18 @@ std::unique_ptr V8StackTraceImpl::capture(V8DebuggerImpl* debu return V8StackTraceImpl::create(debugger, contextGroupId, stackTrace, maxStackSize, description); } -std::unique_ptr V8StackTraceImpl::clone() -{ - return cloneImpl(); -} - std::unique_ptr V8StackTraceImpl::cloneImpl() { std::vector framesCopy(m_frames); return wrapUnique(new V8StackTraceImpl(m_contextGroupId, m_description, framesCopy, m_parent ? m_parent->cloneImpl() : nullptr)); } -std::unique_ptr V8StackTraceImpl::isolatedCopy() -{ - return isolatedCopyImpl(); -} - -std::unique_ptr V8StackTraceImpl::isolatedCopyImpl() +std::unique_ptr V8StackTraceImpl::clone() { std::vector frames; for (size_t i = 0; i < m_frames.size(); i++) - frames.push_back(m_frames.at(i).isolatedCopy()); - return wrapUnique(new V8StackTraceImpl(m_contextGroupId, m_description.isolatedCopy(), frames, m_parent ? m_parent->isolatedCopyImpl() : nullptr)); + frames.push_back(m_frames.at(i).clone()); + return wrapUnique(new V8StackTraceImpl(m_contextGroupId, m_description.isolatedCopy(), frames, nullptr)); } V8StackTraceImpl::V8StackTraceImpl(int contextGroupId, const String16& description, std::vector& frames, std::unique_ptr parent) @@ -227,7 +217,7 @@ String16 V8StackTraceImpl::topScriptId() const return m_frames[0].m_scriptId; } -std::unique_ptr V8StackTraceImpl::buildInspectorObject() const +std::unique_ptr V8StackTraceImpl::buildInspectorObjectImpl() const { std::unique_ptr> frames = protocol::Array::create(); for (size_t i = 0; i < m_frames.size(); i++) @@ -238,18 +228,23 @@ std::unique_ptr V8StackTraceImpl::buildInspectorO if (!m_description.isEmpty()) stackTrace->setDescription(m_description); if (m_parent) - stackTrace->setParent(m_parent->buildInspectorObject()); + stackTrace->setParent(m_parent->buildInspectorObjectImpl()); return stackTrace; } -std::unique_ptr V8StackTraceImpl::buildInspectorObjectForTail(V8DebuggerImpl* debugger) const +std::unique_ptr V8StackTraceImpl::buildInspectorObjectForTail(V8Debugger* debugger) const { v8::HandleScope handleScope(v8::Isolate::GetCurrent()); // Next call collapses possible empty stack and ensures maxAsyncCallChainDepth. std::unique_ptr fullChain = V8StackTraceImpl::create(debugger, m_contextGroupId, v8::Local(), V8StackTraceImpl::maxCallStackSizeToCapture); if (!fullChain || !fullChain->m_parent) return nullptr; - return fullChain->m_parent->buildInspectorObject(); + return fullChain->m_parent->buildInspectorObjectImpl(); +} + +std::unique_ptr V8StackTraceImpl::buildInspectorObject() const +{ + return buildInspectorObjectImpl(); } String16 V8StackTraceImpl::toString() const diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.h index 63b59e8d900..9d9a4892f1d 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StackTraceImpl.h @@ -5,7 +5,9 @@ #ifndef V8StackTraceImpl_h #define V8StackTraceImpl_h +#include "platform/inspector_protocol/Allocator.h" #include "platform/inspector_protocol/Platform.h" +#include "platform/v8_inspector/protocol/Runtime.h" #include "platform/v8_inspector/public/V8StackTrace.h" #include @@ -13,7 +15,7 @@ namespace blink { class TracedValue; -class V8DebuggerImpl; +class V8Debugger; // Note: async stack trace may have empty top stack with non-empty tail to indicate // that current native-only state had some async story. @@ -34,7 +36,7 @@ class V8StackTraceImpl final : public V8StackTrace { const String16& sourceURL() const { return m_scriptName; } int lineNumber() const { return m_lineNumber; } int columnNumber() const { return m_columnNumber; } - Frame isolatedCopy() const; + Frame clone() const; private: friend class V8StackTraceImpl; @@ -49,14 +51,14 @@ class V8StackTraceImpl final : public V8StackTrace { }; static void setCaptureStackTraceForUncaughtExceptions(v8::Isolate*, bool capture); - static std::unique_ptr create(V8DebuggerImpl*, int contextGroupId, v8::Local, size_t maxStackSize, const String16& description = String16()); - static std::unique_ptr capture(V8DebuggerImpl*, int contextGroupId, size_t maxStackSize, const String16& description = String16()); + static std::unique_ptr create(V8Debugger*, int contextGroupId, v8::Local, size_t maxStackSize, const String16& description = String16()); + static std::unique_ptr capture(V8Debugger*, int contextGroupId, size_t maxStackSize, const String16& description = String16()); + // This method drops the async chain. Use cloneImpl() instead. std::unique_ptr clone() override; std::unique_ptr cloneImpl(); - std::unique_ptr isolatedCopy() override; - std::unique_ptr isolatedCopyImpl(); - std::unique_ptr buildInspectorObjectForTail(V8DebuggerImpl*) const; + std::unique_ptr buildInspectorObjectForTail(V8Debugger*) const; + std::unique_ptr buildInspectorObjectImpl() const; ~V8StackTraceImpl() override; // V8StackTrace implementation. @@ -66,7 +68,7 @@ class V8StackTraceImpl final : public V8StackTrace { int topColumnNumber() const override; String16 topScriptId() const override; String16 topFunctionName() const override; - std::unique_ptr buildInspectorObject() const override; + std::unique_ptr buildInspectorObject() const override; String16 toString() const override; private: diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.cpp index 4ba7898bc58..037d91036cf 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.cpp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.cpp @@ -5,10 +5,9 @@ #include "platform/v8_inspector/V8StringUtil.h" #include "platform/inspector_protocol/String16.h" -#include "platform/v8_inspector/V8DebuggerImpl.h" +#include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8Regex.h" -#include "platform/v8_inspector/public/V8ContentSearchUtil.h" namespace blink { @@ -144,10 +143,10 @@ std::unique_ptr buildObjectForSearchMatch(int l .build(); } -std::unique_ptr createSearchRegex(V8DebuggerImpl* debugger, const String16& query, bool caseSensitive, bool isRegex) +std::unique_ptr createSearchRegex(V8InspectorImpl* inspector, const String16& query, bool caseSensitive, bool isRegex) { String16 regexSource = isRegex ? query : createSearchRegexSource(query); - return wrapUnique(new V8Regex(debugger, regexSource, caseSensitive)); + return wrapUnique(new V8Regex(inspector, regexSource, caseSensitive)); } } // namespace @@ -166,6 +165,11 @@ v8::Local toV8StringInternalized(v8::Isolate* isolate, const String1 return v8::String::NewFromTwoByte(isolate, reinterpret_cast(string.characters16()), v8::NewStringType::kInternalized, string.length()).ToLocalChecked(); } +v8::Local toV8StringInternalized(v8::Isolate* isolate, const char* str) +{ + return v8::String::NewFromUtf8(isolate, str, v8::NewStringType::kInternalized).ToLocalChecked(); +} + String16 toProtocolString(v8::Local value) { if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) @@ -182,7 +186,16 @@ String16 toProtocolStringWithTypeCheck(v8::Local value) return toProtocolString(value.As()); } -namespace V8ContentSearchUtil { +std::vector> searchInTextByLinesImpl(V8InspectorSession* session, const String16& text, const String16& query, const bool caseSensitive, const bool isRegex) +{ + std::unique_ptr regex = createSearchRegex(static_cast(session)->inspector(), query, caseSensitive, isRegex); + std::vector> matches = scriptRegexpMatchesByLines(*regex.get(), text); + + std::vector> result; + for (const auto& match : matches) + result.push_back(buildObjectForSearchMatch(match.first, match.second)); + return result; +} String16 findSourceURL(const String16& content, bool multiline, bool* deprecated) { @@ -194,20 +207,6 @@ String16 findSourceMapURL(const String16& content, bool multiline, bool* depreca return findMagicComment(content, "sourceMappingURL", multiline, deprecated); } -std::unique_ptr> searchInTextByLines(V8InspectorSession* session, const String16& text, const String16& query, const bool caseSensitive, const bool isRegex) -{ - std::unique_ptr> result = protocol::Array::create(); - std::unique_ptr regex = createSearchRegex(static_cast(session)->debugger(), query, caseSensitive, isRegex); - std::vector> matches = scriptRegexpMatchesByLines(*regex.get(), text); - - for (const auto& match : matches) - result->addItem(buildObjectForSearchMatch(match.first, match.second)); - - return result; -} - -} // namespace V8ContentSearchUtil - std::unique_ptr toProtocolValue(v8::Local context, v8::Local value, int maxDepth) { if (value.IsEmpty()) { diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.h index 2d42613d416..029ed5661a9 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/V8StringUtil.h @@ -7,18 +7,26 @@ #include "platform/inspector_protocol/String16.h" #include "platform/inspector_protocol/Values.h" +#include "platform/v8_inspector/protocol/Debugger.h" #include namespace blink { +class V8InspectorSession; + std::unique_ptr toProtocolValue(v8::Local, v8::Local, int maxDepth = protocol::Value::maxDepth); v8::Local toV8String(v8::Isolate*, const String16&); v8::Local toV8StringInternalized(v8::Isolate*, const String16&); +v8::Local toV8StringInternalized(v8::Isolate*, const char*); String16 toProtocolString(v8::Local); String16 toProtocolStringWithTypeCheck(v8::Local); +String16 findSourceURL(const String16& content, bool multiline, bool* deprecated = nullptr); +String16 findSourceMapURL(const String16& content, bool multiline, bool* deprecated = nullptr); +std::vector> searchInTextByLinesImpl(V8InspectorSession*, const String16& text, const String16& query, bool caseSensitive, bool isRegex); + } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/debugger_script_externs.js b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/debugger_script_externs.js index cf2a0457c4c..dddc709a57a 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/debugger_script_externs.js +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/debugger_script_externs.js @@ -29,7 +29,7 @@ var RawLocation; startColumn: number, endColumn: number, executionContextId: number, - isContentScript: boolean, + executionContextAuxData: string, isInternalScript: boolean }} */ var FormattedScript; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/injected_script_externs.js b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/injected_script_externs.js index 5fba025caab..03455614f32 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/injected_script_externs.js +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/injected_script_externs.js @@ -39,12 +39,11 @@ InjectedScriptHostClass.prototype.isTypedArray = function(obj) {} InjectedScriptHostClass.prototype.getInternalProperties = function(obj) {} /** - * @param {!Function} fn - * @param {*} receiver - * @param {!Array.<*>=} argv - * @return {*} + * @param {!Object} object + * @param {string} propertyName + * @return {boolean} */ -InjectedScriptHostClass.prototype.suppressWarningsAndCallFunction = function(fn, receiver, argv) {} +InjectedScriptHostClass.prototype.objectHasOwnProperty = function(object, propertyName) {} /** * @param {*} value @@ -59,12 +58,6 @@ InjectedScriptHostClass.prototype.bind = function(value, groupName) {} */ InjectedScriptHostClass.prototype.proxyTargetValue = function(object) {} -/** - * @param {!Object} object - * @return {Object|undefined} - */ -InjectedScriptHostClass.prototype.prototype = function(object) {} - /** @type {!InjectedScriptHostClass} */ var InjectedScriptHost; /** @type {!Window} */ diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/js_protocol.json b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/js_protocol.json index 78548bc8402..161cdb89e17 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/js_protocol.json +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/js_protocol.json @@ -14,25 +14,33 @@ "type": "string", "description": "Unique object identifier." }, + { + "id": "UnserializableValue", + "type": "string", + "enum": ["Infinity", "NaN", "-Infinity", "-0"], + "description": "Primitive value which cannot be JSON-stringified." + }, { "id": "RemoteObject", "type": "object", "description": "Mirror object referencing original JavaScript object.", + "exported": true, "properties": [ { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for object type values only." }, { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for object type values only." }, - { "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested), or description string if the value can not be JSON-stringified (like NaN, Infinity, -Infinity, -0)." }, + { "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested)." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "experimental": true, "description": "Primitive value which can not be JSON-stringified does not have value, but gets this property." }, { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, - { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for object type values only.", "hidden": true }, - { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "hidden": true} + { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for object type values only.", "experimental": true }, + { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "experimental": true} ] }, { "id": "CustomPreview", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "header", "type": "string"}, { "name": "hasBody", "type": "boolean"}, @@ -44,7 +52,7 @@ { "id": "ObjectPreview", "type": "object", - "hidden": true, + "experimental": true, "description": "Object containing abbreviated remote object value.", "properties": [ { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, @@ -58,7 +66,7 @@ { "id": "PropertyPreview", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "name", "type": "string", "description": "Property name." }, { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type. Accessor means that the property itself is an accessor property." }, @@ -70,7 +78,7 @@ { "id": "EntryPreview", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Preview of the key. Specified for map-like collection entries." }, { "name": "value", "$ref": "ObjectPreview", "description": "Preview of the value." } @@ -89,8 +97,8 @@ { "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." }, { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object.", "hidden": true }, - { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the symbol type.", "hidden": true } + { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object.", "experimental": true }, + { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the symbol type.", "experimental": true } ] }, { @@ -101,16 +109,16 @@ { "name": "name", "type": "string", "description": "Conventional property name." }, { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." } ], - "hidden": true + "experimental": true }, { "id": "CallArgument", "type": "object", - "description": "Represents function call argument. Either remote object id objectId or primitive value or neither of (for undefined) them should be specified.", + "description": "Represents function call argument. Either remote object id objectId, primitive value, unserializable primitive value or neither of (for undefined) them should be specified.", "properties": [ - { "name": "value", "type": "any", "optional": true, "description": "Primitive value, or description string if the value can not be JSON-stringified (like NaN, Infinity, -Infinity, -0)." }, - { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." }, - { "name": "type", "optional": true, "hidden": true, "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." } + { "name": "value", "type": "any", "optional": true, "description": "Primitive value." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "experimental": true, "description": "Primitive value which can not be JSON-stringified." }, + { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." } ] }, { @@ -124,16 +132,15 @@ "description": "Description of an isolated world.", "properties": [ { "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." }, - { "name": "isDefault", "type": "boolean", "description": "Whether context is the default page context (as opposite to e.g. context of content script).", "hidden": true }, - { "name": "origin", "type": "string", "description": "Execution context origin.", "hidden": true}, - { "name": "name", "type": "string", "description": "Human readable name describing given context.", "hidden": true}, - { "name": "frameId", "type": "string", "description": "Id of the owning frame. May be an empty string if the context is not associated with a frame." } + { "name": "origin", "type": "string", "description": "Execution context origin.", "experimental": true }, + { "name": "name", "type": "string", "description": "Human readable name describing given context.", "experimental": true }, + { "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "experimental": true } ] }, { "id": "ExceptionDetails", "type": "object", - "hidden": true, + "experimental": true, "description": "Detailed information about exception (or error) that was thrown during script compilation or execution.", "properties": [ { "name": "text", "type": "string", "description": "Exception text." }, @@ -148,7 +155,7 @@ "id": "Timestamp", "type": "number", "description": "Number of milliseconds since epoch.", - "hidden": true + "experimental": true }, { "id": "CallFrame", @@ -166,47 +173,69 @@ "id": "StackTrace", "type": "object", "description": "Call frames for assertions or error messages.", + "exported": true, "properties": [ { "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." }, { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." }, - { "name": "parent", "$ref": "StackTrace", "optional": true, "hidden": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } + { "name": "parent", "$ref": "StackTrace", "optional": true, "experimental": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } ] } ], "commands": [ { "name": "evaluate", + "async": true, "parameters": [ { "name": "expression", "type": "string", "description": "Expression to evaluate." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation.", "hidden": true }, - { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "hidden": true }, - { "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which isolated context to perform evaluation. Each content script lives in an isolated context and this parameter may be used to specify one of those contexts. If the parameter is omitted or 0 the evaluation will be performed in the context of the inspected page." }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation.", "experimental": true }, + { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "experimental": true }, + { "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "hidden": true, "description": "Whether execution should be treated as initiated by user in the UI." } + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "experimental": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } ], "returns": [ { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "hidden": true, "description": "Exception details."} + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Evaluates expression on global object." }, + { + "name": "awaitPromise", + "experimental": true, + "async": true, + "parameters": [ + { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Promise result. Will contain rejected value if promise was rejected." }, + { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the promise was rejected." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details if stack strace is available."} + ], + "description": "Add handler to promise with given promise object id." + }, { "name": "callFunctionOn", + "async": true, "parameters": [ { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to call function on." }, { "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." }, { "name": "arguments", "type": "array", "items": { "$ref": "CallArgument", "description": "Call argument." }, "optional": true, "description": "Call arguments. All call arguments must belong to the same JavaScript world as the target object." }, - { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether function call should stop on exceptions and mute console. Overrides setPauseOnException state.", "hidden": true }, + { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether function call should stop on exceptions and mute console. Overrides setPauseOnException state.", "experimental": true }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "hidden": true, "description": "Whether execution should be treated as initiated by user in the UI." } + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "experimental": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } ], "returns": [ { "name": "result", "$ref": "RemoteObject", "description": "Call result." }, - { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." } + { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object." }, @@ -215,13 +244,13 @@ "parameters": [ { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." }, - { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "hidden": true }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the results." } + { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "experimental": true }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the results." } ], "returns": [ { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor" }, "description": "Object properties." }, - { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself).", "hidden": true }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "hidden": true, "description": "Exception details."} + { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself).", "experimental": true }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Returns properties of a given object. Object group of the result is inherited from the target object." }, @@ -241,7 +270,7 @@ }, { "name": "run", - "hidden": true, + "experimental": true, "description": "Tells inspected instance(worker or page) that it can run in case it was started paused." }, { @@ -250,12 +279,12 @@ }, { "name": "disable", - "hidden": true, + "experimental": true, "description": "Disables reporting of execution contexts creation." }, { "name": "discardConsoleEntries", - "hidden": true, + "experimental": true, "description": "Discards collected exceptions and console API calls." }, { @@ -266,16 +295,16 @@ "type": "boolean" } ], - "hidden": true + "experimental": true }, { "name": "compileScript", - "hidden": true, + "experimental": true, "parameters": [ { "name": "expression", "type": "string", "description": "Expression to compile." }, { "name": "sourceURL", "type": "string", "description": "Source url to be set for the script." }, { "name": "persistScript", "type": "boolean", "description": "Specifies whether the compiled script should be persisted." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Specifies in which isolated context to perform script run. Each content script lives in an isolated context and this parameter is used to specify one of those contexts." } + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." } ], "returns": [ { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Id of the script." }, @@ -285,16 +314,21 @@ }, { "name": "runScript", - "hidden": true, + "experimental": true, + "async": true, "parameters": [ { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." }, - { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Specifies in which isolated context to perform script run. Each content script lives in an isolated context and this parameter is used to specify one of those contexts." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether script run should stop on exceptions and mute console. Overrides setPauseOnException state." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." } + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, + { "name": "awaitPromise", "type": "boolean", "optional": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } ], "returns": [ { "name": "result", "$ref": "RemoteObject", "description": "Run result." }, + { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the execution." }, { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} ], "description": "Runs script with given id in a given context." @@ -329,7 +363,7 @@ { "name": "exception", "$ref": "RemoteObject", "optional": true, "description": "Exception object." }, { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Identifier of the context where exception happened." } ], - "hidden": true + "experimental": true }, { "name": "exceptionRevoked", @@ -338,7 +372,7 @@ { "name": "message", "type": "string", "description": "Message describing why exception was revoked." }, { "name": "exceptionId", "type": "integer", "description": "The id of revoked exception, as reported in exceptionUnhandled." } ], - "hidden": true + "experimental": true }, { "name": "consoleAPICalled", @@ -350,7 +384,7 @@ { "name": "timestamp", "$ref": "Timestamp", "description": "Call timestamp." }, { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "Stack trace captured when the call was made." } ], - "hidden": true + "experimental": true }, { "name": "inspectRequested", @@ -358,7 +392,7 @@ { "name": "object", "$ref": "RemoteObject" }, { "name": "hints", "type": "object" } ], - "hidden": true + "experimental": true } ] }, @@ -389,7 +423,7 @@ }, { "id": "ScriptPosition", - "hidden": true, + "experimental": true, "type": "object", "properties": [ { "name": "lineNumber", "type": "integer" }, @@ -403,11 +437,11 @@ "properties": [ { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused." }, { "name": "functionName", "type": "string", "description": "Name of the JavaScript function called on this call frame." }, - { "name": "functionLocation", "$ref": "Location", "optional": true, "hidden": true, "description": "Location in the source code." }, + { "name": "functionLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code." }, { "name": "location", "$ref": "Location", "description": "Location in the source code." }, { "name": "scopeChain", "type": "array", "items": { "$ref": "Scope" }, "description": "Scope chain for this call frame." }, { "name": "this", "$ref": "Runtime.RemoteObject", "description": "this object for this call frame." }, - { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "hidden": true, "description": "The value being returned, if the function is at return point." } + { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "experimental": true, "description": "The value being returned, if the function is at return point." } ], "description": "JavaScript call frame. Array of call frames form the call stack." }, @@ -417,9 +451,9 @@ "properties": [ { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script"], "description": "Scope type." }, { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For global and with scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }, - { "name": "name", "type": "string", "optional": true, "hidden": true }, - { "name": "startLocation", "$ref": "Location", "optional": true, "hidden": true, "description": "Location in the source code where scope starts" }, - { "name": "endLocation", "$ref": "Location", "optional": true, "hidden": true, "description": "Location in the source code where scope ends" } + { "name": "name", "type": "string", "optional": true, "experimental": true }, + { "name": "startLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code where scope starts" }, + { "name": "endLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code where scope ends" } ], "description": "Scope description." }, @@ -427,11 +461,12 @@ "id": "SearchMatch", "type": "object", "description": "Search match for resource.", + "exported": true, "properties": [ { "name": "lineNumber", "type": "number", "description": "Line number in resource content." }, { "name": "lineContent", "type": "string", "description": "Line with match content." } ], - "hidden": true + "experimental": true } ], "commands": [ @@ -452,7 +487,7 @@ }, { "name": "setSkipAllPauses", - "hidden": true, + "experimental": true, "parameters": [ { "name": "skipped", "type": "boolean", "description": "New value for skip pauses state." } ], @@ -496,7 +531,7 @@ "name": "continueToLocation", "parameters": [ { "name": "location", "$ref": "Location", "description": "Location to continue to." }, - { "name": "interstatementLocation", "type": "boolean", "optional": true, "hidden": true, "description": "Allows breakpoints at the intemediate positions inside statements." } + { "name": "interstatementLocation", "type": "boolean", "optional": true, "experimental": true, "description": "Allows breakpoints at the intemediate positions inside statements." } ], "description": "Continues execution until specific location is reached." }, @@ -545,12 +580,12 @@ "parameters": [ { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to edit." }, { "name": "scriptSource", "type": "string", "description": "New content of the script." }, - { "name": "preview", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Preview mode may be used to get result description without actually modifying the code.", "hidden": true } + { "name": "preview", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Preview mode may be used to get result description without actually modifying the code.", "experimental": true } ], "returns": [ { "name": "callFrames", "type": "array", "optional": true, "items": { "$ref": "CallFrame" }, "description": "New stack trace in case editing has happened while VM was stopped." }, - { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes.", "hidden": true }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "hidden": true }, + { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes.", "experimental": true }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "experimental": true }, { "name": "compileError", "optional": true, "$ref": "Runtime.ExceptionDetails", "description": "Error data if any." } ], "description": "Edits JavaScript source live." @@ -564,7 +599,7 @@ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "New stack trace." }, { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } ], - "hidden": true, + "experimental": true, "description": "Restarts particular call frame from the beginning." }, { @@ -590,15 +625,15 @@ { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." }, { "name": "expression", "type": "string", "description": "Expression to evaluate." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "String object group name to put result into (allows rapid releasing resulting object handles using releaseObjectGroup)." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false.", "hidden": true }, - { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "hidden": true }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false.", "experimental": true }, + { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "experimental": true }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the result." } + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." } ], "returns": [ { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "hidden": true, "description": "Exception details."} + { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Evaluates expression on a given call frame." }, @@ -610,7 +645,7 @@ { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." }, { "name": "callFrameId", "$ref": "CallFrameId", "description": "Id of callframe that holds variable." } ], - "hidden": true, + "experimental": true, "description": "Changes value of variable in a callframe. Object-based scopes are not supported and must be mutated manually." }, { @@ -619,7 +654,7 @@ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } ], - "hidden": true, + "experimental": true, "description": "Returns call stack including variables changed since VM was paused. VM must be paused." }, { @@ -627,7 +662,7 @@ "parameters": [ { "name": "maxDepth", "type": "integer", "description": "Maximum depth of async call stacks. Setting to 0 will effectively disable collecting async call stacks (default)." } ], - "hidden": true, + "experimental": true, "description": "Enables or disables async call stacks tracking." }, { @@ -635,7 +670,7 @@ "parameters": [ { "name": "patterns", "type": "array", "items": { "type": "string" }, "description": "Array of regexps that will be used to check script url for blackbox state." } ], - "hidden": true, + "experimental": true, "description": "Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in scripts with url matching one of the patterns. VM will try to leave blackboxed script by performing 'step in' several times, finally resorting to 'step out' if unsuccessful." }, { @@ -644,7 +679,7 @@ { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script." }, { "name": "positions", "type": "array", "items": { "$ref": "ScriptPosition" } } ], - "hidden": true, + "experimental": true, "description": "Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. Positions array contains positions where blackbox state is changed. First interval isn't blackboxed. Array should be sorted." } ], @@ -658,14 +693,14 @@ { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, { "name": "endLine", "type": "integer", "description": "Last line of the script." }, { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "hidden": true }, - { "name": "hash", "type": "string", "hidden": true, "description": "Content hash of the script."}, - { "name": "isContentScript", "type": "boolean", "optional": true, "description": "Determines whether this script is a user extension script." }, - { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "hidden": true }, - { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "hidden": true }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "experimental": true }, + { "name": "hash", "type": "string", "experimental": true, "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "experimental": true }, + { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "experimental": true }, + { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "experimental": true }, { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "hidden": true }, - { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "hidden": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true }, + { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "experimental": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} ], "description": "Fired when virtual machine parses script. This event is also fired for all known and uncollected scripts upon enabling debugger." }, @@ -678,13 +713,13 @@ { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, { "name": "endLine", "type": "integer", "description": "Last line of the script." }, { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "hidden": true }, - { "name": "hash", "type": "string", "hidden": true, "description": "Content hash of the script."}, - { "name": "isContentScript", "type": "boolean", "optional": true, "description": "Determines whether this script is a user extension script." }, - { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "hidden": true }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "experimental": true }, + { "name": "hash", "type": "string", "experimental": true, "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "experimental": true }, + { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "experimental": true }, { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "hidden": true }, - { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "hidden": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true }, + { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "experimental": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} ], "description": "Fired when virtual machine fails to parse the script." }, @@ -700,10 +735,10 @@ "name": "paused", "parameters": [ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, - { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason." }, + { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason.", "exported": true }, { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, - { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs", "hidden": true }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "hidden": true } + { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs", "experimental": true }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "experimental": true } ], "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria." }, @@ -759,7 +794,7 @@ "name": "messageRepeatCountUpdated", "parameters": [ { "name": "count", "type": "integer", "description": "New repeat count value." }, - { "name": "timestamp", "$ref": "Runtime.Timestamp", "description": "Timestamp of most recent message in batch.", "hidden": true } + { "name": "timestamp", "$ref": "Runtime.Timestamp", "description": "Timestamp of most recent message in batch.", "experimental": true } ], "description": "Not issued.", "deprecated": true @@ -774,7 +809,7 @@ { "domain": "Profiler", "dependencies": ["Runtime", "Debugger"], - "hidden": true, + "experimental": true, "types": [ { "id": "CPUProfileNode", @@ -859,7 +894,7 @@ { "domain": "HeapProfiler", "dependencies": ["Runtime"], - "hidden": true, + "experimental": true, "types": [ { "id": "HeapSnapshotObjectId", diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/InspectorVersion.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/InspectorVersion.h new file mode 100644 index 00000000000..aff7b1519fb --- /dev/null +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/InspectorVersion.h @@ -0,0 +1,6 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is automatically generated. Do not modify. +#define V8_INSPECTOR_REVISION "62cd277117e6f8ec53e31b1be58290a6f7ab42ef" diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ConsoleTypes.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ConsoleTypes.h deleted file mode 100644 index 73c1878e9e3..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ConsoleTypes.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8ConsoleTypes_h -#define V8ConsoleTypes_h - -namespace blink { - -enum MessageLevel { - DebugMessageLevel = 4, - LogMessageLevel = 1, - InfoMessageLevel = 5, - WarningMessageLevel = 2, - ErrorMessageLevel = 3 -}; - -} - -#endif // !defined(V8ConsoleTypes_h) diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ContentSearchUtil.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ContentSearchUtil.h deleted file mode 100644 index a932b7a4664..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ContentSearchUtil.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8ContentSearchUtil_h -#define V8ContentSearchUtil_h - -#include "platform/inspector_protocol/Platform.h" -#include "platform/inspector_protocol/String16.h" -#include "platform/v8_inspector/protocol/Debugger.h" - -namespace blink { - -class V8InspectorSession; - -namespace V8ContentSearchUtil { - -PLATFORM_EXPORT String16 findSourceURL(const String16& content, bool multiline, bool* deprecated = nullptr); -PLATFORM_EXPORT String16 findSourceMapURL(const String16& content, bool multiline, bool* deprecated = nullptr); -PLATFORM_EXPORT std::unique_ptr> searchInTextByLines(V8InspectorSession*, const String16& text, const String16& query, const bool caseSensitive, const bool isRegex); - -} - -} - -#endif // !defined(V8ContentSearchUtil_h) diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ContextInfo.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ContextInfo.h index 0dc1de29da7..81a98e6c520 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ContextInfo.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8ContextInfo.h @@ -13,14 +13,11 @@ namespace blink { class V8ContextInfo { public: - V8ContextInfo(v8::Local context, int contextGroupId, bool isDefault, const String16& origin, const String16& humanReadableName, const String16& frameId, bool hasMemoryOnConsole) + V8ContextInfo(v8::Local context, int contextGroupId, const String16& humanReadableName) : context(context) , contextGroupId(contextGroupId) - , isDefault(isDefault) - , origin(origin) , humanReadableName(humanReadableName) - , frameId(frameId) - , hasMemoryOnConsole(hasMemoryOnConsole) + , hasMemoryOnConsole(false) { } @@ -29,11 +26,9 @@ class V8ContextInfo { // V8DebuggerAgent to notify about events in the context. // |contextGroupId| must be non-0. int contextGroupId; - bool isDefault; - const String16 origin; - const String16 humanReadableName; - // TODO(dgozman): aux data? - const String16 frameId; + String16 humanReadableName; + String16 origin; + String16 auxData; bool hasMemoryOnConsole; }; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Debugger.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Debugger.h deleted file mode 100644 index da3dcacf555..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Debugger.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8Debugger_h -#define V8Debugger_h - -#include "platform/inspector_protocol/Platform.h" -#include "platform/inspector_protocol/String16.h" -#include "platform/v8_inspector/public/V8ConsoleTypes.h" - -#include - -namespace blink { - -class V8ContextInfo; -class V8DebuggerClient; -class V8InspectorSession; -class V8InspectorSessionClient; -class V8StackTrace; - -namespace protocol { -class FrontendChannel; -} - -class PLATFORM_EXPORT V8Debugger { -public: - static std::unique_ptr create(v8::Isolate*, V8DebuggerClient*); - virtual ~V8Debugger() { } - - // Contexts instrumentation. - virtual void contextCreated(const V8ContextInfo&) = 0; - virtual void contextDestroyed(v8::Local) = 0; - virtual void resetContextGroup(int contextGroupId) = 0; - - // Various instrumentation. - virtual void willExecuteScript(v8::Local, int scriptId) = 0; - virtual void didExecuteScript(v8::Local) = 0; - virtual void idleStarted() = 0; - virtual void idleFinished() = 0; - - // Async call stacks instrumentation. - virtual void asyncTaskScheduled(const String16& taskName, void* task, bool recurring) = 0; - virtual void asyncTaskCanceled(void* task) = 0; - virtual void asyncTaskStarted(void* task) = 0; - virtual void asyncTaskFinished(void* task) = 0; - virtual void allAsyncTasksCanceled() = 0; - - // Runtime instrumentation. - // TODO(dgozman): can we pass exception object? - virtual void exceptionThrown(int contextGroupId, const String16& errorMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId) = 0; - virtual unsigned promiseRejected(v8::Local, const String16& errorMessage, v8::Local exception, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId) = 0; - virtual void promiseRejectionRevoked(v8::Local, unsigned promiseRejectionId) = 0; - - // TODO(dgozman): can we remove this method? - virtual void logToConsole(v8::Local, v8::Local arg1, v8::Local arg2) = 0; - - // API methods. - virtual std::unique_ptr connect(int contextGroupId, protocol::FrontendChannel*, V8InspectorSessionClient*, const String16* state) = 0; - virtual std::unique_ptr createStackTrace(v8::Local) = 0; - virtual std::unique_ptr captureStackTrace(bool fullStack) = 0; -}; - -} // namespace blink - - -#endif // V8Debugger_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8DebuggerClient.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8DebuggerClient.h deleted file mode 100644 index 3747f66707d..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8DebuggerClient.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8DebuggerClient_h -#define V8DebuggerClient_h - -#include "platform/inspector_protocol/Platform.h" -#include "platform/v8_inspector/public/V8ConsoleTypes.h" -#include "platform/v8_inspector/public/V8ContextInfo.h" - -#include - -namespace blink { - -class V8StackTrace; - -class PLATFORM_EXPORT V8DebuggerClient { -public: - virtual ~V8DebuggerClient() { } - virtual void runMessageLoopOnPause(int contextGroupId) = 0; - virtual void quitMessageLoopOnPause() = 0; - virtual void muteWarningsAndDeprecations(int contextGroupId) = 0; - virtual void unmuteWarningsAndDeprecations(int contextGroupId) = 0; - virtual void beginUserGesture() = 0; - virtual void endUserGesture() = 0; - virtual bool callingContextCanAccessContext(v8::Local calling, v8::Local target) = 0; - virtual String16 valueSubtype(v8::Local) = 0; - virtual bool formatAccessorsAsProperties(v8::Local) = 0; - virtual bool isExecutionAllowed() = 0; - virtual double currentTimeMS() = 0; - virtual v8::Local ensureDefaultContextInGroup(int contextGroupId) = 0; - virtual bool isInspectableHeapObject(v8::Local) = 0; - virtual void enableAsyncInstrumentation() = 0; - virtual void disableAsyncInstrumentation() = 0; - - virtual void installAdditionalCommandLineAPI(v8::Local, v8::Local) = 0; - - virtual void consoleTime(const String16& title) = 0; - virtual void consoleTimeEnd(const String16& title) = 0; - virtual void consoleTimeStamp(const String16& title) = 0; - virtual void consoleAPIMessage(int contextGroupId, MessageLevel, const String16& message, const String16& url, unsigned lineNumber, unsigned columnNumber, V8StackTrace*) = 0; - - virtual v8::MaybeLocal memoryInfo(v8::Isolate*, v8::Local) = 0; - - typedef void (*TimerCallback)(void*); - virtual void startRepeatingTimer(double, TimerCallback, void* data) = 0; - virtual void cancelTimer(void* data) = 0; -}; - -} // namespace blink - - -#endif // V8DebuggerClient_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Inspector.cpp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Inspector.cpp deleted file mode 100644 index f118dcacf3c..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Inspector.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -#include "platform/v8_inspector/public/V8Inspector.h" - -#include "platform/inspector_protocol/DispatcherBase.h" -#include "platform/v8_inspector/V8StringUtil.h" -#include "platform/v8_inspector/public/V8Debugger.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" - -namespace blink { - -V8Inspector::V8Inspector(v8::Isolate* isolate, v8::Local context) - : m_context(context) -{ - m_debugger = V8Debugger::create(isolate, this); - m_debugger->contextCreated(V8ContextInfo(context, 1, true, "", - "NodeJS Main Context", "", false)); -} - -V8Inspector::~V8Inspector() -{ - disconnectFrontend(); -} - -bool V8Inspector::callingContextCanAccessContext(v8::Local calling, v8::Local target) -{ - return true; -} - -String16 V8Inspector::valueSubtype(v8::Local value) -{ - return String16(); -} - -bool V8Inspector::formatAccessorsAsProperties(v8::Local value) -{ - return false; -} - -void V8Inspector::connectFrontend(protocol::FrontendChannel* channel) -{ - m_session = m_debugger->connect(1, channel, this, &m_state); -} - -void V8Inspector::disconnectFrontend() -{ - m_session.reset(); -} - -void V8Inspector::dispatchMessageFromFrontend(const String16& message) -{ - if (m_session) - m_session->dispatchProtocolMessage(message); -} - -v8::Local V8Inspector::ensureDefaultContextInGroup(int) -{ - return m_context; -} - -bool V8Inspector::isExecutionAllowed() -{ - return true; -} - -bool V8Inspector::canExecuteScripts() -{ - return true; -} - -} // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Inspector.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Inspector.h index 4dbb797d509..a62f0c8b3a0 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Inspector.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8Inspector.h @@ -1,4 +1,4 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,76 +6,55 @@ #define V8Inspector_h #include "platform/inspector_protocol/Platform.h" -#include "platform/v8_inspector/public/V8DebuggerClient.h" -#include "platform/v8_inspector/public/V8InspectorSession.h" -#include "platform/v8_inspector/public/V8InspectorSessionClient.h" +#include "platform/inspector_protocol/String16.h" +#include "platform/v8_inspector/public/V8ContextInfo.h" #include namespace blink { +class V8InspectorClient; +class V8InspectorSession; +class V8StackTrace; + namespace protocol { -class Dispatcher; -class Frontend; class FrontendChannel; } -class V8Debugger; -class V8HeapProfilerAgent; -class V8ProfilerAgent; - -class V8Inspector : public V8DebuggerClient, V8InspectorSessionClient { +class PLATFORM_EXPORT V8Inspector { public: - V8Inspector(v8::Isolate*, v8::Local); - ~V8Inspector(); - - // Transport interface. - void connectFrontend(protocol::FrontendChannel*); - void disconnectFrontend(); - void dispatchMessageFromFrontend(const String16& message); - -private: - bool callingContextCanAccessContext(v8::Local calling, v8::Local target) override; - String16 valueSubtype(v8::Local) override; - bool formatAccessorsAsProperties(v8::Local) override; - void muteWarningsAndDeprecations(int) override { } - void unmuteWarningsAndDeprecations(int) override { } - double currentTimeMS() override { return 0; }; - - bool isExecutionAllowed() override; - v8::Local ensureDefaultContextInGroup(int contextGroupId) override; - void beginUserGesture() override { } - void endUserGesture() override { } - bool isInspectableHeapObject(v8::Local) override { return true; } - void consoleTime(const String16& title) override { } - void consoleTimeEnd(const String16& title) override { } - void consoleTimeStamp(const String16& title) override { } - void consoleAPIMessage(int contextGroupId, MessageLevel, const String16& message, const String16& url, unsigned lineNumber, unsigned columnNumber, V8StackTrace*) override { } - v8::MaybeLocal memoryInfo(v8::Isolate*, v8::Local) override - { - return v8::MaybeLocal(); - } - void installAdditionalCommandLineAPI(v8::Local, v8::Local) override { } - void enableAsyncInstrumentation() override { } - void disableAsyncInstrumentation() override { } - void startRepeatingTimer(double, TimerCallback, void* data) override { } - void cancelTimer(void* data) override { } - - // V8InspectorSessionClient - void runtimeEnabled() override { }; - void runtimeDisabled() override { }; - void resumeStartup() override { }; - bool canExecuteScripts() override; - void profilingStarted() override { }; - void profilingStopped() override { }; - void consoleCleared() override { }; - - std::unique_ptr m_debugger; - std::unique_ptr m_session; - String16 m_state; - v8::Local m_context; + static std::unique_ptr create(v8::Isolate*, V8InspectorClient*); + virtual ~V8Inspector() { } + + // Contexts instrumentation. + virtual void contextCreated(const V8ContextInfo&) = 0; + virtual void contextDestroyed(v8::Local) = 0; + virtual void resetContextGroup(int contextGroupId) = 0; + + // Various instrumentation. + virtual void willExecuteScript(v8::Local, int scriptId) = 0; + virtual void didExecuteScript(v8::Local) = 0; + virtual void idleStarted() = 0; + virtual void idleFinished() = 0; + + // Async stack traces instrumentation. + virtual void asyncTaskScheduled(const String16& taskName, void* task, bool recurring) = 0; + virtual void asyncTaskCanceled(void* task) = 0; + virtual void asyncTaskStarted(void* task) = 0; + virtual void asyncTaskFinished(void* task) = 0; + virtual void allAsyncTasksCanceled() = 0; + + // Exceptions instrumentation. + virtual unsigned exceptionThrown(v8::Local, const String16& message, v8::Local exception, const String16& detailedMessage, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr, int scriptId) = 0; + virtual void exceptionRevoked(v8::Local, unsigned exceptionId, const String16& message) = 0; + + // API methods. + virtual std::unique_ptr connect(int contextGroupId, protocol::FrontendChannel*, const String16* state) = 0; + virtual std::unique_ptr createStackTrace(v8::Local) = 0; + virtual std::unique_ptr captureStackTrace(bool fullStack) = 0; }; -} +} // namespace blink + #endif // V8Inspector_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorClient.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorClient.h new file mode 100644 index 00000000000..27495ae9884 --- /dev/null +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorClient.h @@ -0,0 +1,60 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8InspectorClient_h +#define V8InspectorClient_h + +#include "platform/inspector_protocol/Platform.h" +#include "platform/inspector_protocol/String16.h" + +#include + +namespace blink { + +class V8StackTrace; + +enum class V8ConsoleAPIType { kClear, kDebug, kLog, kInfo, kWarning, kError }; + +class PLATFORM_EXPORT V8InspectorClient { +public: + virtual ~V8InspectorClient() { } + + virtual void runMessageLoopOnPause(int contextGroupId) { } + virtual void quitMessageLoopOnPause() { } + virtual void resumeStartup(int contextGroupId) { } + + virtual void muteMetrics(int contextGroupId) { } + virtual void unmuteMetrics(int contextGroupId) { } + + virtual void beginUserGesture() { } + virtual void endUserGesture() { } + + virtual String16 valueSubtype(v8::Local) { return String16(); } + virtual bool formatAccessorsAsProperties(v8::Local) { return false; } + virtual bool isInspectableHeapObject(v8::Local) { return true; } + + virtual v8::Local ensureDefaultContextInGroup(int contextGroupId) { return v8::Local(); } + virtual void beginEnsureAllContextsInGroup(int contextGroupId) { } + virtual void endEnsureAllContextsInGroup(int contextGroupId) { } + + virtual void installAdditionalCommandLineAPI(v8::Local, v8::Local) { } + virtual void consoleAPIMessage(int contextGroupId, V8ConsoleAPIType, const String16& message, const String16& url, unsigned lineNumber, unsigned columnNumber, V8StackTrace*) { } + virtual v8::MaybeLocal memoryInfo(v8::Isolate*, v8::Local) { return v8::MaybeLocal(); } + + virtual void consoleTime(const String16& title) { } + virtual void consoleTimeEnd(const String16& title) { } + virtual void consoleTimeStamp(const String16& title) { } + virtual double currentTimeMS() { return 0; } + typedef void (*TimerCallback)(void*); + virtual void startRepeatingTimer(double, TimerCallback, void* data) { } + virtual void cancelTimer(void* data) { } + + // TODO(dgozman): this was added to support service worker shadow page. We should not connect at all. + virtual bool canExecuteScripts(int contextGroupId) { return true; } +}; + +} // namespace blink + + +#endif // V8InspectorClient_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorSession.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorSession.h index 2103467e440..365ab86432b 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorSession.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorSession.h @@ -5,8 +5,10 @@ #ifndef V8InspectorSession_h #define V8InspectorSession_h +#include "platform/inspector_protocol/Array.h" #include "platform/inspector_protocol/Platform.h" -#include "platform/v8_inspector/protocol/Runtime.h" +#include "platform/v8_inspector/public/protocol/Debugger.h" +#include "platform/v8_inspector/public/protocol/Runtime.h" #include @@ -25,23 +27,22 @@ class PLATFORM_EXPORT V8InspectorSession { virtual void addInspectedObject(std::unique_ptr) = 0; // Dispatching protocol messages. - // TODO(dgozman): generate this one. - static bool isV8ProtocolMethod(const String16& method); + static bool canDispatchMethod(const String16& method); virtual void dispatchProtocolMessage(const String16& message) = 0; virtual String16 stateJSON() = 0; // Debugger actions. - virtual void schedulePauseOnNextStatement(const String16& breakReason, std::unique_ptr data) = 0; + virtual void schedulePauseOnNextStatement(const String16& breakReason, const String16& breakDetails) = 0; virtual void cancelPauseOnNextStatement() = 0; - virtual void breakProgram(const String16& breakReason, std::unique_ptr data) = 0; + virtual void breakProgram(const String16& breakReason, const String16& breakDetails) = 0; virtual void setSkipAllPauses(bool) = 0; virtual void resume() = 0; virtual void stepOver() = 0; + virtual std::unique_ptr> searchInTextByLines(const String16& text, const String16& query, bool caseSensitive, bool isRegex) = 0; // Remote objects. - static const char backtraceObjectGroup[]; - virtual std::unique_ptr wrapObject(v8::Local, v8::Local, const String16& groupName, bool generatePreview) = 0; - virtual v8::Local findObject(ErrorString*, const String16& objectId, v8::Local* = nullptr, String16* objectGroup = nullptr) = 0; + virtual std::unique_ptr wrapObject(v8::Local, v8::Local, const String16& groupName) = 0; + virtual bool unwrapObject(ErrorString*, const String16& objectId, v8::Local*, v8::Local*, String16* objectGroup) = 0; virtual void releaseObjectGroup(const String16&) = 0; }; diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorSessionClient.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorSessionClient.h deleted file mode 100644 index e9e7c33ea83..00000000000 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8InspectorSessionClient.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8InspectorSessionClient_h -#define V8InspectorSessionClient_h - -#include "platform/inspector_protocol/Platform.h" - -#include - -namespace blink { - -class PLATFORM_EXPORT V8InspectorSessionClient { -public: - virtual ~V8InspectorSessionClient() { } - virtual void runtimeEnabled() = 0; - virtual void runtimeDisabled() = 0; - virtual void resumeStartup() = 0; - // TODO(dgozman): this was added to support service worker shadow page. We should not connect at all. - virtual bool canExecuteScripts() = 0; - virtual void profilingStarted() = 0; - virtual void profilingStopped() = 0; - virtual void consoleCleared() = 0; -}; - -} // namespace blink - -#endif // V8InspectorSessionClient_h diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8StackTrace.h b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8StackTrace.h index beee1155f6e..1913554a20e 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8StackTrace.h +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/public/V8StackTrace.h @@ -7,13 +7,12 @@ #include "platform/inspector_protocol/Platform.h" #include "platform/inspector_protocol/String16.h" -#include "platform/v8_inspector/protocol/Runtime.h" +#include "platform/v8_inspector/public/protocol/Runtime.h" #include namespace blink { -// TODO(dgozman): migrate to V8SourceLocation. class V8StackTrace { public: virtual bool isEmpty() const = 0; @@ -24,10 +23,11 @@ class V8StackTrace { virtual String16 topFunctionName() const = 0; virtual ~V8StackTrace() { } - virtual std::unique_ptr buildInspectorObject() const = 0; + virtual std::unique_ptr buildInspectorObject() const = 0; virtual String16 toString() const = 0; + + // Safe to pass between threads, drops async chain. virtual std::unique_ptr clone() = 0; - virtual std::unique_ptr isolatedCopy() = 0; // Safe to pass between threads. }; } // namespace blink diff --git a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/v8_inspector.gyp b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/v8_inspector.gyp index 6de6017c693..ebfc91a66d4 100644 --- a/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/v8_inspector.gyp +++ b/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector/v8_inspector.gyp @@ -79,6 +79,8 @@ # Source code templates. '../inspector_protocol/TypeBuilder_h.template', '../inspector_protocol/TypeBuilder_cpp.template', + '../inspector_protocol/Exported_h.template', + '../inspector_protocol/Imported_h.template', # Protocol definitions 'js_protocol.json', ], @@ -93,6 +95,8 @@ '<(blink_platform_output_dir)/v8_inspector/protocol/Profiler.h', '<(blink_platform_output_dir)/v8_inspector/protocol/Runtime.cpp', '<(blink_platform_output_dir)/v8_inspector/protocol/Runtime.h', + '<(blink_platform_output_dir)/v8_inspector/public/protocol/Runtime.h', + '<(blink_platform_output_dir)/v8_inspector/public/protocol/Debugger.h', ], 'action': [ 'python', @@ -102,6 +106,8 @@ '--export_macro', 'PLATFORM_EXPORT', '--output_dir', '<(blink_platform_output_dir)/v8_inspector/protocol', '--output_package', 'platform/v8_inspector/protocol', + '--exported_dir', '<(blink_platform_output_dir)/v8_inspector/public/protocol', + '--exported_package', 'platform/v8_inspector/public/protocol', ], 'message': 'Generating protocol backend sources from json definitions.', }, @@ -177,11 +183,9 @@ '../inspector_protocol/String16STL.h', '../inspector_protocol/Values.cpp', '../inspector_protocol/Values.h', - '../inspector_protocol/ValueConversions.cpp', '../inspector_protocol/ValueConversions.h', 'Atomics.h', - 'IgnoreExceptionsScope.h', 'InjectedScript.cpp', 'InjectedScript.h', 'InjectedScriptNative.cpp', @@ -200,10 +204,12 @@ 'V8ConsoleAgentImpl.h', 'V8ConsoleMessage.cpp', 'V8ConsoleMessage.h', + 'V8Debugger.cpp', + 'V8Debugger.h', 'V8DebuggerAgentImpl.cpp', 'V8DebuggerAgentImpl.h', - 'V8DebuggerImpl.cpp', - 'V8DebuggerImpl.h', + 'V8InspectorImpl.cpp', + 'V8InspectorImpl.h', 'V8DebuggerScript.cpp', 'V8DebuggerScript.h', 'V8FunctionCall.cpp', @@ -227,13 +233,10 @@ 'V8StringUtil.cpp', 'V8StringUtil.h', 'public/V8EventListenerInfo.h', - 'public/V8ContentSearchUtil.h', 'public/V8ContextInfo.h', - 'public/V8Debugger.h', - 'public/V8DebuggerClient.h', - 'public/V8HeapProfilerAgent.h', - 'public/V8Inspector.cpp', 'public/V8Inspector.h', + 'public/V8InspectorClient.h', + 'public/V8HeapProfilerAgent.h', 'public/V8InspectorSession.h', 'public/V8StackTrace.h', diff --git a/doc/api/addons.md b/doc/api/addons.md index 1333b3b1360..a239e15de65 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -423,7 +423,7 @@ const addon = require('./build/Release/addon'); var obj1 = addon('hello'); var obj2 = addon('world'); -console.log(obj1.msg + ' ' + obj2.msg); // 'hello world' +console.log(obj1.msg, obj2.msg); // 'hello world' ``` diff --git a/doc/api/assert.md b/doc/api/assert.md index bc5c0b833ae..f1f8238b0f9 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -1,6 +1,6 @@ # Assert - Stability: 3 - Locked +> Stability: 3 - Locked The `assert` module provides a simple set of assertion tests that can be used to test invariants. The module is intended for internal use by Node.js, but can be @@ -258,7 +258,7 @@ const obj3 = { a : { b : 1 } -} +}; const obj4 = Object.create(obj1); assert.notDeepEqual(obj1, obj1); diff --git a/doc/api/buffer.md b/doc/api/buffer.md index ebce7fc4ba3..9533324c15f 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -1,6 +1,6 @@ # Buffer - Stability: 2 - Stable +> Stability: 2 - Stable Prior to the introduction of [`TypedArray`] in ECMAScript 2015 (ES6), the JavaScript language had no mechanism for reading or manipulating streams @@ -300,7 +300,7 @@ It can be constructed in a variety of ways. deprecated: v6.0.0 --> - Stability: 0 - Deprecated: Use [`Buffer.from(array)`] instead. +> Stability: 0 - Deprecated: Use [`Buffer.from(array)`] instead. * `array` {Array} An array of bytes to copy from @@ -318,7 +318,7 @@ const buf = new Buffer([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); deprecated: v6.0.0 --> - Stability: 0 - Deprecated: Use [`Buffer.from(buffer)`] instead. +> Stability: 0 - Deprecated: Use [`Buffer.from(buffer)`] instead. * `buffer` {Buffer} An existing `Buffer` to copy data from @@ -344,9 +344,9 @@ console.log(buf2.toString()); deprecated: v6.0.0 --> - Stability: 0 - Deprecated: Use - [`Buffer.from(arrayBuffer[, byteOffset [, length]])`][`Buffer.from(arrayBuffer)`] - instead. +> Stability: 0 - Deprecated: Use +> [`Buffer.from(arrayBuffer[, byteOffset [, length]])`][`Buffer.from(arrayBuffer)`] +> instead. * `arrayBuffer` {ArrayBuffer} The `.buffer` property of a [`TypedArray`] or [`ArrayBuffer`] @@ -387,8 +387,8 @@ console.log(buf); deprecated: v6.0.0 --> - Stability: 0 - Deprecated: Use [`Buffer.alloc()`] instead (also see - [`Buffer.allocUnsafe()`]). +> Stability: 0 - Deprecated: Use [`Buffer.alloc()`] instead (also see +> [`Buffer.allocUnsafe()`]). * `size` {Integer} The desired length of the new `Buffer` @@ -420,8 +420,8 @@ console.log(buf); deprecated: v6.0.0 --> - Stability: 0 - Deprecated: - Use [`Buffer.from(string[, encoding])`][`Buffer.from(string)`] instead. +> Stability: 0 - Deprecated: +> Use [`Buffer.from(string[, encoding])`][`Buffer.from(string)`] instead. * `string` {String} String to encode * `encoding` {String} The encoding of `string`. **Default:** `'utf8'` @@ -2309,7 +2309,7 @@ On 64-bit architectures, this value is `(2^31)-1` (~2GB). deprecated: v6.0.0 --> - Stability: 0 - Deprecated: Use [`Buffer.allocUnsafeSlow()`] instead. +> Stability: 0 - Deprecated: Use [`Buffer.allocUnsafeSlow()`] instead. Returns an un-pooled `Buffer`. @@ -2349,7 +2349,7 @@ has observed undue memory retention in their applications. deprecated: v6.0.0 --> - Stability: 0 - Deprecated: Use [`Buffer.allocUnsafeSlow()`] instead. +> Stability: 0 - Deprecated: Use [`Buffer.allocUnsafeSlow()`] instead. * `size` {Integer} The desired length of the new `SlowBuffer` diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 7c01e34cecb..fe265afc122 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -1,6 +1,6 @@ # Child Process - Stability: 2 - Stable +> Stability: 2 - Stable The `child_process` module provides the ability to spawn child processes in a manner that is similar, but not identical, to popen(3). This capability @@ -295,6 +295,8 @@ added: v0.1.90 * `options` {Object} * `cwd` {String} Current working directory of the child process * `env` {Object} Environment key-value pairs + * `argv0` {String} Explicitly set the value of `argv[0]` sent to the child + process. This will be set to `command` if not specified. * `stdio` {Array|String} Child's stdio configuration. (See [`options.stdio`][`stdio`]) * `detached` {Boolean} Prepare child to run independently of its parent @@ -397,6 +399,14 @@ child.on('error', (err) => { }); ``` +*Note: Certain platforms (OS X, Linux) will use the value of `argv[0]` for the +process title while others (Windows, SunOS) will use `command`.* + +*Note: Node.js currently overwrites `argv[0]` with `process.execPath` on +startup, so `process.argv[0]` in a Node.js child process will not match the +`argv0` parameter passed to `spawn` from the parent, retrieve it with the +`process.argv0` property instead.* + #### options.detached + +When set to `1`, writes to `stdout` and `stderr` will be non-blocking and +asynchronous when outputting to a TTY on platforms which support async stdio. +Setting this will void any guarantee that stdio will not be interleaved or +dropped at program exit. **Use of this mode is not recommended.** + + [Buffer]: buffer.html#buffer_buffer [debugger]: debugger.html [REPL]: repl.html diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 6f0b424e05e..ede975b3b57 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -1,6 +1,6 @@ # Cluster - Stability: 2 - Stable +> Stability: 2 - Stable A single instance of Node.js runs in a single thread. To take advantage of multi-core systems the user will sometimes want to launch a cluster of Node.js @@ -108,12 +108,18 @@ responsibility to manage the worker pool for your application's needs. ## Class: Worker + A Worker object contains all public information and method about a worker. In the master it can be obtained using `cluster.workers`. In a worker it can be obtained using `cluster.worker`. ### Event: 'disconnect' + Similar to the `cluster.on('disconnect')` event, but specific to this worker. @@ -124,12 +130,18 @@ cluster.fork().on('disconnect', () => { ``` ### Event: 'error' + This event is the same as the one provided by [`child_process.fork()`][]. In a worker you can also use `process.on('error')`. ### Event: 'exit' + * `code` {Number} the exit code, if it exited normally. * `signal` {String} the name of the signal (eg. `'SIGHUP'`) that caused @@ -151,6 +163,9 @@ worker.on('exit', (code, signal) => { ``` ### Event: 'listening' + * `address` {Object} @@ -165,6 +180,9 @@ cluster.fork().on('listening', (address) => { It is not emitted in the worker. ### Event: 'message' + * `message` {Object} * `handle` {undefined|Object} @@ -220,6 +238,9 @@ if (cluster.isMaster) { ``` ### Event: 'online' + Similar to the `cluster.on('online')` event, but specific to this worker. @@ -232,6 +253,9 @@ cluster.fork().on('online', () => { It is not emitted in the worker. ### worker.disconnect() + In a worker, this function will close all servers, wait for the `'close'` event on those servers, and then disconnect the IPC channel. @@ -293,6 +317,9 @@ if (cluster.isMaster) { ``` ### worker.exitedAfterDisconnect + * {Boolean} @@ -314,6 +341,9 @@ worker.kill(); ``` ### worker.id + * {Number} @@ -324,17 +354,26 @@ While a worker is alive, this is the key that indexes it in cluster.workers ### worker.isConnected() + This function returns `true` if the worker is connected to its master via its IPC channel, `false` otherwise. A worker is connected to its master after it's been created. It is disconnected after the `'disconnect'` event is emitted. ### worker.isDead() + This function returns `true` if the worker's process has terminated (either because of exiting or being signaled). Otherwise, it returns `false`. ### worker.kill([signal='SIGTERM']) + * `signal` {String} Name of the kill signal to send to the worker process. @@ -351,6 +390,9 @@ Note that in a worker, `process.kill()` exists, but it is not this function, it is [`kill`][]. ### worker.process + * {ChildProcess} @@ -365,6 +407,9 @@ on `process` and `.exitedAfterDisconnect` is not `true`. This protects against accidental disconnection. ### worker.send(message[, sendHandle][, callback]) + * `message` {Object} * `sendHandle` {Handle} @@ -394,8 +439,12 @@ if (cluster.isMaster) { ``` ### worker.suicide + - Stability: 0 - Deprecated: Use [`worker.exitedAfterDisconnect`][] instead. +> Stability: 0 - Deprecated: Use [`worker.exitedAfterDisconnect`][] instead. An alias to [`worker.exitedAfterDisconnect`][]. @@ -420,6 +469,9 @@ This API only exists for backwards compatibility and will be removed in the future. ## Event: 'disconnect' + * `worker` {cluster.Worker} @@ -438,6 +490,9 @@ cluster.on('disconnect', (worker) => { ``` ## Event: 'exit' + * `worker` {cluster.Worker} * `code` {Number} the exit code, if it exited normally. @@ -459,6 +514,9 @@ cluster.on('exit', (worker, code, signal) => { See [child_process event: 'exit'][]. ## Event: 'fork' + * `worker` {cluster.Worker} @@ -484,6 +542,9 @@ cluster.on('exit', (worker, code, signal) => { ``` ## Event: 'listening' + * `worker` {cluster.Worker} * `address` {Object} @@ -516,7 +577,7 @@ The `addressType` is one of: * `message` {Object} * `handle` {undefined|Object} -Emitted when any worker receives a message. +Emitted when the cluster master receives a message from any worker. See [child_process event: 'message'][]. @@ -538,6 +599,9 @@ cluster.on('message', function(worker, message, handle) { ``` ## Event: 'online' + * `worker` {cluster.Worker} @@ -553,6 +617,9 @@ cluster.on('online', (worker) => { ``` ## Event: 'setup' + * `settings` {Object} @@ -565,6 +632,9 @@ The `settings` object is the `cluster.settings` object at the time If accuracy is important, use `cluster.settings`. ## cluster.disconnect([callback]) + * `callback` {Function} called when all workers are disconnected and handles are closed @@ -579,6 +649,9 @@ The method takes an optional callback argument which will be called when finishe This can only be called from the master process. ## cluster.fork([env]) + * `env` {Object} Key/value pairs to add to worker process environment. * return {cluster.Worker} @@ -588,6 +661,9 @@ Spawn a new worker process. This can only be called from the master process. ## cluster.isMaster + * {Boolean} @@ -596,12 +672,18 @@ by the `process.env.NODE_UNIQUE_ID`. If `process.env.NODE_UNIQUE_ID` is undefined, then `isMaster` is `true`. ## cluster.isWorker + * {Boolean} True if the process is not a master (it is the negation of `cluster.isMaster`). ## cluster.schedulingPolicy + The scheduling policy, either `cluster.SCHED_RR` for round-robin or `cluster.SCHED_NONE` to leave it to the operating system. This is a @@ -617,6 +699,9 @@ distribute IOCP handles without incurring a large performance hit. values are `"rr"` and `"none"`. ## cluster.settings + * {Object} * `execArgv` {Array} list of string arguments passed to the Node.js @@ -626,6 +711,9 @@ values are `"rr"` and `"none"`. (Default=`process.argv.slice(2)`) * `silent` {Boolean} whether or not to send output to parent's stdio. (Default=`false`) + * `stdio` {Array} Configures the stdio of forked processes. Because the + cluster module relies on IPC to function, this configuration must contain an + `'ipc'` entry. When this option is provided, it overrides `silent`. * `uid` {Number} Sets the user identity of the process. (See setuid(2).) * `gid` {Number} Sets the group identity of the process. (See setgid(2).) @@ -635,6 +723,9 @@ the settings, including the default values. This object is not supposed to be changed or set manually, by you. ## cluster.setupMaster([settings]) + * `settings` {Object} * `exec` {String} file path to worker file. (Default=`process.argv[1]`) @@ -642,6 +733,8 @@ This object is not supposed to be changed or set manually, by you. (Default=`process.argv.slice(2)`) * `silent` {Boolean} whether or not to send output to parent's stdio. (Default=`false`) + * `stdio` {Array} Configures the stdio of forked processes. When this option + is provided, it overrides `silent`. `setupMaster` is used to change the default 'fork' behavior. Once called, the settings will be present in `cluster.settings`. @@ -675,6 +768,9 @@ cluster.fork(); // http worker This can only be called from the master process. ## cluster.worker + * {Object} @@ -693,6 +789,9 @@ if (cluster.isMaster) { ``` ## cluster.workers + * {Object} diff --git a/doc/api/console.md b/doc/api/console.md index 9fb8c37a6df..74850c0c2e0 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -1,6 +1,6 @@ # Console - Stability: 2 - Stable +> Stability: 2 - Stable The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. @@ -220,7 +220,7 @@ values similar to `printf(3)` (the arguments are all passed to var count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout -console.log('count: ', count); +console.log('count:', count); // Prints: count: 5, to stdout ``` diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 1c4e825d4e2..1d4b451be0d 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1,6 +1,6 @@ # Crypto - Stability: 2 - Stable +> Stability: 2 - Stable The `crypto` module provides cryptographic functionality that includes a set of wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign and verify functions. @@ -510,7 +510,7 @@ public point (key) is also generated and set in the ECDH object. ### ecdh.setPublicKey(public_key[, encoding]) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated Sets the EC Diffie-Hellman public key. Key encoding can be `'latin1'`, `'hex'` or `'base64'`. If `encoding` is provided `public_key` is expected to @@ -913,12 +913,12 @@ recent OpenSSL releases, `openssl list-cipher-algorithms` will display the available cipher algorithms. The `key` is the raw key used by the `algorithm` and `iv` is an -[initialization vector][]. Both arguments must be `'latin1'` encoded strings or +[initialization vector][]. Both arguments must be `'utf8'` encoded strings or [buffers][`Buffer`]. ### crypto.createCredentials(details) - Stability: 0 - Deprecated: Use [`tls.createSecureContext()`][] instead. +> Stability: 0 - Deprecated: Use [`tls.createSecureContext()`][] instead. The `crypto.createCredentials()` method is a deprecated alias for creating and returning a `tls.SecureContext` object. The `crypto.createCredentials()` @@ -968,7 +968,7 @@ recent OpenSSL releases, `openssl list-cipher-algorithms` will display the available cipher algorithms. The `key` is the raw key used by the `algorithm` and `iv` is an -[initialization vector][]. Both arguments must be `'latin1'` encoded strings or +[initialization vector][]. Both arguments must be `'utf8'` encoded strings or [buffers][`Buffer`]. ### crypto.createDiffieHellman(prime[, prime_encoding][, generator][, generator_encoding]) diff --git a/doc/api/debugger.md b/doc/api/debugger.md index d146292f2d7..acffe65cbaa 100644 --- a/doc/api/debugger.md +++ b/doc/api/debugger.md @@ -1,6 +1,6 @@ # Debugger - Stability: 2 - Stable +> Stability: 2 - Stable diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 1a5cce0b91e..91d6f749334 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -1,6 +1,6 @@ # UDP / Datagram Sockets - Stability: 2 - Stable +> Stability: 2 - Stable diff --git a/doc/api/dns.md b/doc/api/dns.md index 7192be9a861..775d288a54b 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -1,6 +1,6 @@ # DNS - Stability: 2 - Stable +> Stability: 2 - Stable The `dns` module contains functions belonging to two different categories: diff --git a/doc/api/documentation.md b/doc/api/documentation.md index 1acb21a8969..38ede72cf6c 100644 --- a/doc/api/documentation.md +++ b/doc/api/documentation.md @@ -64,7 +64,7 @@ Please do not suggest API changes in this area; they will be refused. ## JSON Output - Stability: 1 - Experimental +> Stability: 1 - Experimental Every HTML file in the markdown has a corresponding JSON file with the same data. diff --git a/doc/api/domain.md b/doc/api/domain.md index c556e2533c0..2fe7e2c39af 100644 --- a/doc/api/domain.md +++ b/doc/api/domain.md @@ -1,6 +1,6 @@ # Domain - Stability: 0 - Deprecated +> Stability: 0 - Deprecated **This module is pending deprecation**. Once a replacement API has been finalized, this module will be fully deprecated. Most end users should @@ -436,8 +436,8 @@ without exiting the domain. ### domain.dispose() - Stability: 0 - Deprecated. Please recover from failed IO actions - explicitly via error event handlers set on the domain. +> Stability: 0 - Deprecated. Please recover from failed IO actions +> explicitly via error event handlers set on the domain. Once `dispose` has been called, the domain will no longer be used by callbacks bound into the domain via `run`, `bind`, or `intercept`, and a `'dispose'` event diff --git a/doc/api/events.md b/doc/api/events.md index 0e2d4954395..eab0bef17ed 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -1,6 +1,6 @@ # Events - Stability: 2 - Stable +> Stability: 2 - Stable @@ -167,6 +167,9 @@ myEmitter.emit('error', new Error('whoops!')); ``` ## Class: EventEmitter + The `EventEmitter` class is defined and exposed by the `events` module: @@ -178,6 +181,9 @@ All EventEmitters emit the event `'newListener'` when new listeners are added and `'removeListener'` when existing listeners are removed. ### Event: 'newListener' + * `eventName` {String|Symbol} The name of the event being listened for * `listener` {Function} The event handler function @@ -214,6 +220,9 @@ myEmitter.emit('event'); ``` ### Event: 'removeListener' + * `eventName` {String|Symbol} The event name * `listener` {Function} The event handler function @@ -221,8 +230,12 @@ myEmitter.emit('event'); The `'removeListener'` event is emitted *after* the `listener` is removed. ### EventEmitter.listenerCount(emitter, eventName) + - Stability: 0 - Deprecated: Use [`emitter.listenerCount()`][] instead. +> Stability: 0 - Deprecated: Use [`emitter.listenerCount()`][] instead. A class method that returns the number of listeners for the given `eventName` registered on the given `emitter`. @@ -236,6 +249,9 @@ console.log(EventEmitter.listenerCount(myEmitter, 'event')); ``` ### EventEmitter.defaultMaxListeners + By default, a maximum of `10` listeners can be registered for any single event. This limit can be changed for individual `EventEmitter` instances @@ -263,10 +279,16 @@ emitter.once('event', () => { ``` ### emitter.addListener(eventName, listener) + Alias for `emitter.on(eventName, listener)`. ### emitter.emit(eventName[, arg1][, arg2][, ...]) + Synchronously calls each of the listeners registered for the event named `eventName`, in the order they were registered, passing the supplied arguments @@ -275,6 +297,9 @@ to each. Returns `true` if the event had listeners, `false` otherwise. ### emitter.eventNames() + Returns an array listing the events for which the emitter has registered listeners. The values in the array will be strings or Symbols. @@ -293,18 +318,27 @@ console.log(myEE.eventNames()); ``` ### emitter.getMaxListeners() + Returns the current max listener value for the `EventEmitter` which is either set by [`emitter.setMaxListeners(n)`][] or defaults to [`EventEmitter.defaultMaxListeners`][]. ### emitter.listenerCount(eventName) + * `eventName` {String|Symbol} The name of the event being listened for Returns the number of listeners listening to the event named `eventName`. ### emitter.listeners(eventName) + Returns a copy of the array of listeners for the event named `eventName`. @@ -317,6 +351,9 @@ console.log(util.inspect(server.listeners('connection'))); ``` ### emitter.on(eventName, listener) + * `eventName` {String|Symbol} The name of the event. * `listener` {Function} The callback function @@ -350,6 +387,9 @@ myEE.emit('foo'); ``` ### emitter.once(eventName, listener) + * `eventName` {String|Symbol} The name of the event. * `listener` {Function} The callback function @@ -380,6 +420,9 @@ myEE.emit('foo'); ``` ### emitter.prependListener(eventName, listener) + * `eventName` {String|Symbol} The name of the event. * `listener` {Function} The callback function @@ -399,6 +442,9 @@ server.prependListener('connection', (stream) => { Returns a reference to the `EventEmitter`, so that calls can be chained. ### emitter.prependOnceListener(eventName, listener) + * `eventName` {String|Symbol} The name of the event. * `listener` {Function} The callback function @@ -416,6 +462,9 @@ server.prependOnceListener('connection', (stream) => { Returns a reference to the `EventEmitter`, so that calls can be chained. ### emitter.removeAllListeners([eventName]) + Removes all listeners, or those of the specified `eventName`. @@ -426,6 +475,9 @@ component or module (e.g. sockets or file streams). Returns a reference to the `EventEmitter`, so that calls can be chained. ### emitter.removeListener(eventName, listener) + Removes the specified `listener` from the listener array for the event named `eventName`. @@ -490,6 +542,9 @@ the `emitter.listeners()` method will need to be recreated. Returns a reference to the `EventEmitter`, so that calls can be chained. ### emitter.setMaxListeners(n) + By default EventEmitters will print a warning if more than `10` listeners are added for a particular event. This is a useful default that helps finding diff --git a/doc/api/fs.md b/doc/api/fs.md index 0c84c44b58e..40b8a990631 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1,6 +1,6 @@ # File System - Stability: 2 - Stable +> Stability: 2 - Stable @@ -181,6 +181,13 @@ added: v0.1.93 Emitted when the `ReadStream`'s underlying file descriptor has been closed using the `fs.close()` method. +### readStream.bytesRead + + +The number of bytes read so far. + ### readStream.path - Stability: 0 - Deprecated: Use [`fs.stat()`][] or [`fs.access()`][] instead. +> Stability: 0 - Deprecated: Use [`fs.stat()`][] or [`fs.access()`][] instead. * `path` {String | Buffer} * `callback` {Function} @@ -610,8 +618,8 @@ added: v0.1.21 deprecated: v1.0.0 --> - Stability: 0 - Deprecated: Use [`fs.statSync()`][] or [`fs.accessSync()`][] - instead. +> Stability: 0 - Deprecated: Use [`fs.statSync()`][] or [`fs.accessSync()`][] +> instead. * `path` {String | Buffer} @@ -1136,7 +1144,8 @@ fs.readFile('/etc/passwd', 'utf8', callback); Any specified file descriptor has to support reading. -_Note: Specified file descriptors will not be closed automatically._ +_Note: If a file descriptor is specified as the `file`, it will not be closed +automatically._ ## fs.readFileSync(file[, options]) 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 `0` to have the operating system assign an available port. +(`::`) when IPv6 is available, or any IPv4 address (`0.0.0.0`) otherwise. +Omit the port argument, or use a port value of `0`, to have the operating system +assign a random port, which can be retrieved by using `server.address().port` +after the `'listening'` event has been emitted. To listen to a unix socket, supply a filename instead of port and hostname. @@ -1331,7 +1333,7 @@ added: v0.1.13 deprecated: v0.3.6 --> - Stability: 0 - Deprecated: Use [`http.request()`][] instead. +> Stability: 0 - Deprecated: Use [`http.request()`][] instead. Constructs a new HTTP client. `port` and `host` refer to the server to be connected to. diff --git a/doc/api/https.md b/doc/api/https.md index 620b6b36c74..bc0e4114c39 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -1,6 +1,6 @@ # HTTPS - Stability: 2 - Stable +> Stability: 2 - Stable HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module. @@ -107,8 +107,8 @@ Example: const https = require('https'); https.get('https://encrypted.google.com/', (res) => { - console.log('statusCode: ', res.statusCode); - console.log('headers: ', res.headers); + console.log('statusCode:', res.statusCode); + console.log('headers:', res.headers); res.on('data', (d) => { process.stdout.write(d); @@ -151,8 +151,8 @@ var options = { }; var req = https.request(options, (res) => { - console.log('statusCode: ', res.statusCode); - console.log('headers: ', res.headers); + console.log('statusCode:', res.statusCode); + console.log('headers:', res.headers); res.on('data', (d) => { process.stdout.write(d); diff --git a/doc/api/modules.md b/doc/api/modules.md index 9f6093aaece..3cba97a9763 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -1,6 +1,6 @@ # Modules - Stability: 3 - Locked +> Stability: 3 - Locked @@ -12,7 +12,7 @@ The contents of `foo.js`: ```js const circle = require('./circle.js'); -console.log( `The area of a circle of radius 4 is ${circle.area(4)}`); +console.log(`The area of a circle of radius 4 is ${circle.area(4)}`); ``` The contents of `circle.js`: diff --git a/doc/api/net.md b/doc/api/net.md index e3160ff4616..d58d00edbdb 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -1,6 +1,6 @@ # net - Stability: 2 - Stable +> Stability: 2 - Stable The `net` module provides you with an asynchronous network wrapper. It contains functions for creating both servers and clients (called streams). You can include @@ -73,8 +73,7 @@ var server = net.createServer((socket) => { // grab a random port. server.listen(() => { - address = server.address(); - console.log('opened server on %j', address); + console.log('opened server on', server.address()); }); ``` @@ -98,7 +97,7 @@ added: v0.2.0 deprecated: v0.9.7 --> - Stability: 0 - Deprecated: Use [`server.getConnections()`][] instead. +> Stability: 0 - Deprecated: Use [`server.getConnections()`][] instead. The number of concurrent connections on the server. @@ -140,7 +139,7 @@ The last parameter `callback` will be added as a listener for the [`'listening'`][] event. The parameter `backlog` behaves the same as in -[`server.listen(port[, hostname][, backlog][, callback])`][`server.listen(port, host, backlog, callback)`]. +[`server.listen([port][, hostname][, backlog][, callback])`][`server.listen(port, host, backlog, callback)`]. ### server.listen(options[, 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 `0` to have the operating system assign an available port. +(`::`) when IPv6 is available, or any IPv4 address (`0.0.0.0`) otherwise. +Omit the port argument, or use a port value of `0`, to have the operating system +assign a random port, which can be retrieved by using `server.address().port` +after the `'listening'` event has been emitted. Backlog is the maximum length of the queue of pending connections. The actual length will be determined by the OS through sysctl settings such as diff --git a/doc/api/os.md b/doc/api/os.md index 8a9c00971a1..98390bb387c 100644 --- a/doc/api/os.md +++ b/doc/api/os.md @@ -1,6 +1,6 @@ # OS - Stability: 2 - Stable +> Stability: 2 - Stable The `os` module provides a number of operating system-related utility methods. It can be accessed using: diff --git a/doc/api/path.md b/doc/api/path.md index fd07cd6802d..6617f0e9e76 100644 --- a/doc/api/path.md +++ b/doc/api/path.md @@ -1,6 +1,6 @@ # Path - Stability: 2 - Stable +> Stability: 2 - Stable The `path` module provides utilities for working with file and directory paths. It can be accessed using: @@ -367,7 +367,7 @@ path.parse('/home/user/dir/file.txt') │ root │ │ name │ ext │ " / home/user/dir / file .txt " └──────┴──────────────┴──────┴─────┘ -(all spaces in the "" line should be ignored -- they're purely for formatting) +(all spaces in the "" line should be ignored -- they are purely for formatting) ``` On Windows: @@ -391,7 +391,7 @@ path.parse('C:\\path\\dir\\file.txt') │ root │ │ name │ ext │ " C:\ path\dir \ file .txt " └──────┴──────────────┴──────┴─────┘ -(all spaces in the "" line should be ignored -- they're purely for formatting) +(all spaces in the "" line should be ignored -- they are purely for formatting) ``` A [`TypeError`][] is thrown if `path` is not a string. diff --git a/doc/api/process.md b/doc/api/process.md index 12eb9b47c66..df8dc095ea8 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -223,8 +223,8 @@ For example: ```js process.on('unhandledRejection', (reason, p) => { - console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason); - // application specific logging, throwing an error, or other logic here + console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); + // application specific logging, throwing an error, or other logic here }); somePromise.then((res) => { @@ -457,9 +457,10 @@ added: v0.1.27 The `process.argv` property returns an array containing the command line arguments passed when the Node.js process was launched. The first element will -be [`process.execPath`]. The second element will be the path to the -JavaScript file being executed. The remaining elements will be any additional -command line arguments. +be [`process.execPath`]. See `process.argv0` if access to the original value of +`argv[0]` is needed. The second element will be the path to the JavaScript +file being executed. The remaining elements will be any additional command line +arguments. For example, assuming the following script for `process-args.js`: @@ -486,6 +487,22 @@ Would generate the output: 4: four ``` +## process.argv0 + + +The `process.argv0` property stores a read-only copy of the original value of +`argv[0]` passed when Node.js starts. + +```js +$ bash -c 'exec -a customArgv0 ./node' +> process.argv[0] +'/Volumes/code/external/node/out/Release/node' +> process.argv0 +'customArgv0' +``` + ## process.chdir(directory) @@ -58,7 +58,7 @@ For example, the query string `'foo=bar&abc=xyz&abc=123'` is parsed into: *Note*: The object returned by the `querystring.parse()` method _does not_ prototypically extend from the JavaScript `Object`. This means that the -typical `Object` methods such as `obj.toString()`, `obj.hashOwnProperty()`, +typical `Object` methods such as `obj.toString()`, `obj.hasOwnProperty()`, and others are not defined and *will not work*. By default, percent-encoded characters within the query string will be assumed diff --git a/doc/api/readline.md b/doc/api/readline.md index 9025f6fe7da..c01397d5710 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -1,6 +1,6 @@ # Readline - Stability: 2 - Stable +> Stability: 2 - Stable The `readline` module provides an interface for reading data from a [Readable][] stream (such as [`process.stdin`]) one line at a time. It can be accessed using: diff --git a/doc/api/repl.md b/doc/api/repl.md index 124106e642e..d8b86f9ef6a 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -1,6 +1,6 @@ # REPL - Stability: 2 - Stable +> Stability: 2 - Stable The `repl` module provides a Read-Eval-Print-Loop (REPL) implementation that is available both as a standalone program or includable in other applications. @@ -38,6 +38,21 @@ The following special commands are supported by all REPL instances: `> .save ./file/to/save.js` * `.load` - Load a file into the current REPL session. `> .load ./file/to/load.js` +* `.editor` - Enter editor mode (`-D` to finish, `-C` to cancel) + +```js +> .editor +// Entering editor mode (^D to finish, ^C to cancel) +function welcome(name) { + return `Hello ${name}!`; +} + +welcome('Node.js User'); + +// ^D +'Hello Node.js User!' +> +``` The following key combinations in the REPL have these special effects: @@ -392,9 +407,9 @@ added: v0.1.91 equivalent to prefacing every repl statement with `'use strict'`. * `repl.REPL_MODE_MAGIC` - attempt to evaluates expressions in default mode. If expressions fail to parse, re-try in strict mode. - * `breakEvalOnSigint` - Stop evaluating the current piece of code when - `SIGINT` is received, i.e. `Ctrl+C` is pressed. This cannot be used together - with a custom `eval` function. Defaults to `false`. + * `breakEvalOnSigint` - Stop evaluating the current piece of code when + `SIGINT` is received, i.e. `Ctrl+C` is pressed. This cannot be used together + with a custom `eval` function. Defaults to `false`. The `repl.start()` method creates and starts a `repl.REPLServer` instance. @@ -444,7 +459,7 @@ added: v2.0.0 deprecated: v3.0.0 --> - Stability: 0 - Deprecated: Use `NODE_REPL_HISTORY` instead. +> Stability: 0 - Deprecated: Use `NODE_REPL_HISTORY` instead. Previously in Node.js/io.js v2.x, REPL history was controlled by using a `NODE_REPL_HISTORY_FILE` environment variable, and the history was saved in JSON diff --git a/doc/api/stream.md b/doc/api/stream.md index 9f84ad1177e..1bee1c58c49 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -1,6 +1,6 @@ # Stream - Stability: 2 - Stable +> Stability: 2 - Stable A stream is an abstract interface for working with streaming data in Node.js. The `stream` module provides a base API that makes it easy to build objects diff --git a/doc/api/string_decoder.md b/doc/api/string_decoder.md index 6bd5a57502b..b557ffab972 100644 --- a/doc/api/string_decoder.md +++ b/doc/api/string_decoder.md @@ -1,6 +1,6 @@ # StringDecoder - Stability: 2 - Stable +> Stability: 2 - Stable The `string_decoder` module provides an API for decoding `Buffer` objects into strings in a manner that preserves encoded multi-byte UTF-8 and UTF-16 diff --git a/doc/api/timers.md b/doc/api/timers.md index a311edd744e..cd10f4f1356 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -1,6 +1,6 @@ # Timers - Stability: 3 - Locked +> Stability: 3 - Locked The `timer` module exposes a global API for scheduling functions to be called at some future period of time. Because the timer functions are diff --git a/doc/api/tls.md b/doc/api/tls.md index a0ece6e58cc..7feaff2acb2 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -1,6 +1,6 @@ # TLS (SSL) - Stability: 2 - Stable +> Stability: 2 - Stable The `tls` module provides an implementation of the Transport Layer Security (TLS) and Secure Socket Layer (SSL) protocols that is built on top of OpenSSL. @@ -1153,7 +1153,7 @@ added: v0.3.4 deprecated: v0.11.3 --> - Stability: 0 - Deprecated: Use [`tls.TLSSocket`][] instead. +> Stability: 0 - Deprecated: Use [`tls.TLSSocket`][] instead. The `tls.CryptoStream` class represents a stream of encrypted data. This class has been deprecated and should no longer be used. @@ -1174,7 +1174,7 @@ added: v0.3.2 deprecated: v0.11.3 --> - Stability: 0 - Deprecated: Use [`tls.TLSSocket`][] instead. +> Stability: 0 - Deprecated: Use [`tls.TLSSocket`][] instead. Returned by [`tls.createSecurePair()`][]. @@ -1197,7 +1197,7 @@ added: v0.3.2 deprecated: v0.11.3 --> - Stability: 0 - Deprecated: Use [`tls.TLSSocket`][] instead. +> Stability: 0 - Deprecated: Use [`tls.TLSSocket`][] instead. * `context` {Object} A secure context object as returned by `tls.createSecureContext()` diff --git a/doc/api/tty.md b/doc/api/tty.md index 372f29b6ce0..f9be1fc4ffd 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -1,6 +1,6 @@ # TTY - Stability: 2 - Stable +> Stability: 2 - Stable The `tty` module provides the `tty.ReadStream` and `tty.WriteStream` classes. In most cases, it will not be necessary or possible to use this module directly. diff --git a/doc/api/url.md b/doc/api/url.md index 76b0a3794d5..023697803dd 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -1,6 +1,6 @@ # URL - Stability: 2 - Stable +> Stability: 2 - Stable The `url` module provides utilities for URL resolution and parsing. It can be accessed using: diff --git a/doc/api/util.md b/doc/api/util.md index 34c68393332..5b59824b625 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1,6 +1,6 @@ # util - Stability: 2 - Stable +> Stability: 2 - Stable The `util` module is primarily designed to support the needs of Node.js' own internal APIs. However, many of the utilities are useful for application and @@ -46,7 +46,7 @@ environment variable. For example: `NODE_DEBUG=fs,net,tls`. ## util.deprecate(function, string) -The `util.deprecate()` method wraps the given `function` in such a way that +The `util.deprecate()` method wraps the given `function` or class in such a way that it is marked as deprecated. ```js @@ -271,6 +271,23 @@ util.inspect(obj); // "{ bar: 'baz' }" ``` +### util.inspect.defaultOptions + +The `defaultOptions` value allows customization of the default options used by +`util.inspect`. This is useful for functions like `console.log` or +`util.format` which implicitly call into `util.inspect`. It shall be set to an +object containing one or more valid [`util.inspect()`][] options. Setting +option properties directly is also supported. + +```js +const util = require('util'); +const arr = Array(101); + +console.log(arr); // logs the truncated array +util.inspect.defaultOptions.maxArrayLength = null; +console.log(arr); // logs the full array +``` + ## Deprecated APIs The following APIs have been deprecated and should no longer be used. Existing @@ -278,7 +295,7 @@ applications and modules should be updated to find alternative approaches. ### util.debug(string) - Stability: 0 - Deprecated: Use [`console.error()`][] instead. +> Stability: 0 - Deprecated: Use [`console.error()`][] instead. * `string` {string} The message to print to `stderr` @@ -286,7 +303,7 @@ Deprecated predecessor of `console.error`. ### util.error([...]) - Stability: 0 - Deprecated: Use [`console.error()`][] instead. +> Stability: 0 - Deprecated: Use [`console.error()`][] instead. * `string` {string} The message to print to `stderr` @@ -294,7 +311,7 @@ Deprecated predecessor of `console.error`. ### util.isArray(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -315,7 +332,7 @@ util.isArray({}); ### util.isBoolean(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -334,7 +351,7 @@ util.isBoolean(false); ### util.isBuffer(object) - Stability: 0 - Deprecated: Use [`Buffer.isBuffer()`][] instead. +> Stability: 0 - Deprecated: Use [`Buffer.isBuffer()`][] instead. * `object` {any} @@ -353,7 +370,7 @@ util.isBuffer(Buffer.from('hello world')); ### util.isDate(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -372,7 +389,7 @@ util.isDate({}); ### util.isError(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -407,7 +424,7 @@ util.isError(obj); ### util.isFunction(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -430,7 +447,7 @@ util.isFunction(Bar); ### util.isNull(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -450,7 +467,7 @@ util.isNull(null); ### util.isNullOrUndefined(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -470,7 +487,7 @@ util.isNullOrUndefined(null); ### util.isNumber(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -491,7 +508,7 @@ util.isNumber(NaN); ### util.isObject(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -513,7 +530,7 @@ util.isObject(function(){}); ### util.isPrimitive(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -545,7 +562,7 @@ util.isPrimitive(new Date()); ### util.isRegExp(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -564,7 +581,7 @@ util.isRegExp({}); ### util.isString(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -585,7 +602,7 @@ util.isString(5); ### util.isSymbol(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -604,7 +621,7 @@ util.isSymbol(Symbol('foo')); ### util.isUndefined(object) - Stability: 0 - Deprecated +> Stability: 0 - Deprecated * `object` {any} @@ -624,7 +641,7 @@ util.isUndefined(null); ### util.log(string) - Stability: 0 - Deprecated: Use a third party module instead. +> Stability: 0 - Deprecated: Use a third party module instead. * `string` {string} @@ -639,19 +656,19 @@ util.log('Timestamped message.'); ### util.print([...]) - Stability: 0 - Deprecated: Use [`console.log()`][] instead. +> Stability: 0 - Deprecated: Use [`console.log()`][] instead. Deprecated predecessor of `console.log`. ### util.puts([...]) - Stability: 0 - Deprecated: Use [`console.log()`][] instead. +> Stability: 0 - Deprecated: Use [`console.log()`][] instead. Deprecated predecessor of `console.log`. ### util._extend(obj) - Stability: 0 - Deprecated: Use [`Object.assign()`] instead. +> Stability: 0 - Deprecated: Use [`Object.assign()`] instead. The `util._extend()` method was never intended to be used outside of internal Node.js modules. The community found and used it anyway. @@ -662,6 +679,7 @@ similar built-in functionality through [`Object.assign()`]. [`Array.isArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray [constructor]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor [semantically incompatible]: https://github.com/nodejs/node/issues/4179 +[`util.inspect()`]: #util_util_inspect_object_options [Customizing `util.inspect` colors]: #util_customizing_util_inspect_colors [`Error`]: errors.html#errors_class_error [`console.log()`]: console.html#console_console_log_data diff --git a/doc/api/vm.md b/doc/api/vm.md index c774ebe6a44..be3a490336b 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -1,6 +1,6 @@ # Executing JavaScript - Stability: 2 - Stable +> Stability: 2 - Stable @@ -321,7 +321,7 @@ added: v0.3.1 before terminating execution. If execution is terminated, an [`Error`][] will be thrown. -The `vm.runInContext()` first contextifies the given `sandbox` object (or +The `vm.runInNewContext()` first contextifies the given `sandbox` object (or creates a new `sandbox` if passed as `undefined`), compiles the `code`, runs it within the context of the created context, then returns the result. Running code does not have access to the local scope. @@ -376,12 +376,12 @@ const vm = require('vm'); var localVar = 'initial value'; const vmResult = vm.runInThisContext('localVar = "vm";'); -console.log('vmResult: ', vmResult); -console.log('localVar: ', localVar); +console.log('vmResult:', vmResult); +console.log('localVar:', localVar); const evalResult = eval('localVar = "eval";'); -console.log('evalResult: ', evalResult); -console.log('localVar: ', localVar); +console.log('evalResult:', evalResult); +console.log('localVar:', localVar); // vmResult: 'vm', localVar: 'initial value' // evalResult: 'eval', localVar: 'eval' diff --git a/doc/api/zlib.md b/doc/api/zlib.md index e421841d67a..b8efe148624 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -1,6 +1,6 @@ # Zlib - Stability: 2 - Stable +> Stability: 2 - Stable The `zlib` module provides compression functionality implemented using Gzip and Deflate/Inflate. It can be accessed using: diff --git a/doc/changelogs/CHANGELOG_ARCHIVE.md b/doc/changelogs/CHANGELOG_ARCHIVE.md index 1552086ce26..eb32a8287e7 100644 --- a/doc/changelogs/CHANGELOG_ARCHIVE.md +++ b/doc/changelogs/CHANGELOG_ARCHIVE.md @@ -1314,13 +1314,13 @@ https://github.com/nodejs/node/commit/8b8a7a7f9b41e74e1e810d0330738ad06fc302ec https://github.com/nodejs/node/commit/a72120190a8ffdbcd3d6ad2a2e6ceecd2087111e * npm: Upgrade to 1.1.30 - - Improved 'npm init' - - Fix the 'cb never called' error from 'oudated' and 'update' - - Add --save-bundle|-B config - - Fix isaacs/npm[#2465](https://github.com/joyent/node/issues/2465): Make npm script and windows shims cygwin-aware - - Fix isaacs/npm[#2452](https://github.com/joyent/node/issues/2452) Use --save(-dev|-optional) in npm rm - - `logstream` option to replace removed `logfd` (Rod Vagg) - - Read default descriptions from README.md files + - Improved 'npm init' + - Fix the 'cb never called' error from 'oudated' and 'update' + - Add --save-bundle|-B config + - Fix isaacs/npm[#2465](https://github.com/joyent/node/issues/2465): Make npm script and windows shims cygwin-aware + - Fix isaacs/npm[#2452](https://github.com/joyent/node/issues/2452) Use --save(-dev|-optional) in npm rm + - `logstream` option to replace removed `logfd` (Rod Vagg) + - Read default descriptions from README.md files * Shims to support deprecated ev_* and eio_* methods (Ben Noordhuis) * [#3118](https://github.com/joyent/node/issues/3118) net.Socket: Delay pause/resume until after connect (isaacs) @@ -1381,9 +1381,9 @@ https://github.com/nodejs/node/commit/12a32a48a30182621b3f8e9b9695d1946b53c131 * child_process: new stdio API for .spawn() method (Fedor Indutny) * child_process: spawn().ref() and spawn().unref() (Fedor Indutny) * Upgrade npm to 1.1.25 - - Enable npm link on windows - - Properly remove sh-shim on Windows - - Abstract out registry client and logger + - Enable npm link on windows + - Properly remove sh-shim on Windows + - Abstract out registry client and logger ## 2012.05.28, Version 0.7.9 (unstable) @@ -1981,7 +1981,7 @@ https://github.com/nodejs/node/commit/865b077819a9271a29f982faaef99dc635b57fbc https://github.com/nodejs/node/commit/220e61c1f65bf4db09699fcf6399c0809c0bc446 * Remove cmake build system, support for Cygwin, legacy code base, - process.ENV, process.ARGV, process.memoryUsage().vsize, os.openOSHandle + process.ENV, process.ARGV, process.memoryUsage().vsize, os.openOSHandle * Documentation improvements (Igor Zinkovsky, Bert Belder, Ilya Dmitrichenko, koichik, Maciej Małecki, Guglielmo Ferri, isaacs) @@ -2207,7 +2207,7 @@ https://github.com/nodejs/node/commit/4585330afef44ddfb6a4054bd9b0f190b352628b * Add support for TLS SNI (Fedor Indutny) * New http agent implementation. Off by default the command line flag --use-http2 will enable it. "make test-http2" will run the tests - for the new implementation. (Mikeal Rogers) + for the new implementation. (Mikeal Rogers) * Revert AMD compatibility. (isaacs) * Windows: improvements, child_process support. @@ -2375,7 +2375,7 @@ https://github.com/nodejs/node/commit/7dd22c26e4365698dc3efddf138c4d399cb912c8 * [#983](https://github.com/joyent/node/issues/983) Better JSON.parse error detection in REPL (isaacs) * [#836](https://github.com/joyent/node/issues/836) Agent socket errors bubble up to req only if req exists * [#1041](https://github.com/joyent/node/issues/1041) Fix event listener leak check timing (koichik) -* [#1038](https://github.com/joyent/node/issues/1038) Fix dns.resolve() with 'PTR' throws Error: Unknown type "PTR" +* [#1038](https://github.com/joyent/node/issues/1038) Fix dns.resolve() with 'PTR' throws Error: Unknown type "PTR" (koichik) * [#1073](https://github.com/joyent/node/issues/1073) Share SSL context between server connections (Fedor Indutny) @@ -2389,7 +2389,7 @@ https://github.com/nodejs/node/commit/7dd22c26e4365698dc3efddf138c4d399cb912c8 * Doc improvements * cleartextstream.destroy() should close(2) the socket. Previously was being - mapped to a shutdown(2) syscall. + mapped to a shutdown(2) syscall. * No longer compile out asserts and debug statements in normal build. * Debugger improvements. @@ -2417,16 +2417,16 @@ https://github.com/nodejs/node/commit/58002d56bc79410c5ff397fc0e1ffec0665db38a * Don't error on ENOTCONN from shutdown() [#670](https://github.com/joyent/node/issues/670) * Auto completion of built-in debugger suggests prefix match rather than - partial match. (koichik) + partial match. (koichik) * circular reference in vm modules. [#822](https://github.com/joyent/node/issues/822) (Jakub Lekstan) * http response.readable should be false after 'end' [#867](https://github.com/joyent/node/issues/867) (Abe Fettig) * Implement os.cpus() and os.uptime() on Solaris (Scott McWhirter) * fs.ReadStream: Allow omission of end option for range reads [#801](https://github.com/joyent/node/issues/801) - (Felix Geisendörfer) + (Felix Geisendörfer) * Buffer.write() with UCS-2 should not be write partial char - [#916](https://github.com/joyent/node/issues/916) (koichik) + [#916](https://github.com/joyent/node/issues/916) (koichik) * Pass secureProtocol through on tls.Server creation (Theo Schlossnagle) * TLS use RC4-SHA by default @@ -2467,7 +2467,7 @@ https://github.com/nodejs/node/commit/25122b986a90ba0982697b7abcb0158c302a1019 https://github.com/nodejs/node/commit/c095ce1a1b41ca015758a713283bf1f0bd41e4c4 * Don't decrease server connection counter again if destroy() is called more - than once GH-431 (Andreas Reich, Anders Conbere) + than once GH-431 (Andreas Reich, Anders Conbere) * Documentation improvements (koichik) * Fix bug with setMaxListeners GH-682 @@ -2794,7 +2794,7 @@ https://github.com/nodejs/node/commit/b14dd49222687c12f3e8eac597cff4f2674f84e8 * Set cwd for child processes (Bert Belder) * Tab completion for readline (Trent Mick) * process.title getter/setter for OSX, Linux, Cygwin. - (Rasmus Andersson, Bert Belder) + (Rasmus Andersson, Bert Belder) * Upgrade V8 to 2.3.6 diff --git a/doc/changelogs/CHANGELOG_IOJS.md b/doc/changelogs/CHANGELOG_IOJS.md index 975d046fbcd..bef00e45a29 100644 --- a/doc/changelogs/CHANGELOG_IOJS.md +++ b/doc/changelogs/CHANGELOG_IOJS.md @@ -67,1416 +67,1416 @@ * [0.10.x](CHANGELOG_V010.md) * [Archive](CHANGELOG_ARCHIVE.md) - - - ## 2015-09-15, io.js Version 3.3.1 @rvagg - - ### Notable changes - - * **buffer**: Fixed a minor errors that was causing crashes (Michaël Zasso) [#2635](https://github.com/nodejs/node/pull/2635), - * **child_process**: Fix error that was causing crashes (Evan Lucas) [#2727](https://github.com/nodejs/node/pull/2727) - * **crypto**: Replace use of rwlocks, unsafe on Windows XP / 2003 (Ben Noordhuis) [#2723](https://github.com/nodejs/node/pull/2723) - * **libuv**: Upgrade from 1.7.3 to 1.7.4 (Saúl Ibarra Corretgé) [#2817](https://github.com/nodejs/node/pull/2817) - * **node**: Fix faulty `process.release.libUrl` on Windows (Rod Vagg) [#2699](https://github.com/nodejs/node/pull/2699) - * **node-gyp**: Float v3.0.3 which has improved support for Node.js and io.js v0.10 to v4+ (Rod Vagg) [#2700](https://github.com/nodejs/node/pull/2700) - * **npm**: Upgrade to version 2.14.3 from 2.13.3, includes a security update, see https://github.com/npm/npm/releases/tag/v2.14.2 for more details, (Kat Marchán) [#2696](https://github.com/nodejs/node/pull/2696). - * **timers**: Improved timer performance from porting the 0.12 implementation, plus minor fixes (Jeremiah Senkpiel) [#2540](https://github.com/nodejs/node/pull/2540), (Julien Gilli) [nodejs/node-v0.x-archive#8751](https://github.com/nodejs/node-v0.x-archive/pull/8751) [nodejs/node-v0.x-archive#8905](https://github.com/nodejs/node-v0.x-archive/pull/8905) - - ### Known issues - - See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. - - * Some uses of computed object shorthand properties are not handled correctly by the current version of V8. e.g. `[{ [prop]: val }]` evaluates to `[{}]`. [#2507](https://github.com/nodejs/node/issues/2507) - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). - - ### Commits - - * [[`b73ff52fe6`](https://github.com/nodejs/node/commit/b73ff52fe6)] - **bindings**: close after reading module struct (Fedor Indutny) [#2792](https://github.com/nodejs/node/pull/2792) - * [[`aa1140e59a`](https://github.com/nodejs/node/commit/aa1140e59a)] - **buffer**: SlowBuffer only accept valid numeric values (Michaël Zasso) [#2635](https://github.com/nodejs/node/pull/2635) - * [[`574475d56e`](https://github.com/nodejs/node/commit/574475d56e)] - **build**: clean up the generated tap file (Sakthipriyan Vairamani) [#2837](https://github.com/nodejs/node/pull/2837) - * [[`aa0001271e`](https://github.com/nodejs/node/commit/aa0001271e)] - **build**: remote commands on staging in single session (Rod Vagg) [#2717](https://github.com/nodejs/node/pull/2717) - * [[`1428661095`](https://github.com/nodejs/node/commit/1428661095)] - **build**: fix v8_enable_handle_zapping override (Karl Skomski) [#2731](https://github.com/nodejs/node/pull/2731) - * [[`5a51edd718`](https://github.com/nodejs/node/commit/5a51edd718)] - **build**: add --enable-asan with builtin leakcheck (Karl Skomski) [#2376](https://github.com/nodejs/node/pull/2376) - * [[`618caa5de0`](https://github.com/nodejs/node/commit/618caa5de0)] - **child_process**: use stdio.fd even if it is 0 (Evan Lucas) [#2727](https://github.com/nodejs/node/pull/2727) - * [[`7be4e49cb6`](https://github.com/nodejs/node/commit/7be4e49cb6)] - **child_process**: check execFile and fork args (James M Snell) [#2667](https://github.com/nodejs/node/pull/2667) - * [[`7f5d6e72c6`](https://github.com/nodejs/node/commit/7f5d6e72c6)] - **cluster**: allow shared reused dgram sockets (Fedor Indutny) [#2548](https://github.com/nodejs/node/pull/2548) - * [[`e68c7ec498`](https://github.com/nodejs/node/commit/e68c7ec498)] - **contextify**: ignore getters during initialization (Fedor Indutny) [nodejs/io.js#2091](https://github.com/nodejs/io.js/pull/2091) - * [[`610fa964aa`](https://github.com/nodejs/node/commit/610fa964aa)] - **cpplint**: make it possible to run outside git repo (Ben Noordhuis) [#2710](https://github.com/nodejs/node/pull/2710) - * [[`4237373dd7`](https://github.com/nodejs/node/commit/4237373dd7)] - **crypto**: replace rwlocks with simple mutexes (Ben Noordhuis) [#2723](https://github.com/nodejs/node/pull/2723) - * [[`777eb00306`](https://github.com/nodejs/node/commit/777eb00306)] - **deps**: upgraded to node-gyp@3.0.3 in npm (Kat Marchán) [#2822](https://github.com/nodejs/node/pull/2822) - * [[`b729ad384b`](https://github.com/nodejs/node/commit/b729ad384b)] - **deps**: upgrade to npm 2.14.3 (Kat Marchán) [#2822](https://github.com/nodejs/node/pull/2822) - * [[`b09fde761c`](https://github.com/nodejs/node/commit/b09fde761c)] - **deps**: update libuv to version 1.7.4 (Saúl Ibarra Corretgé) [#2817](https://github.com/nodejs/node/pull/2817) - * [[`4cf225daad`](https://github.com/nodejs/node/commit/4cf225daad)] - **deps**: float node-gyp v3.0.0 (Rod Vagg) [#2700](https://github.com/nodejs/node/pull/2700) - * [[`118f48c0f3`](https://github.com/nodejs/node/commit/118f48c0f3)] - **deps**: create .npmrc during npm tests (Kat Marchán) [#2696](https://github.com/nodejs/node/pull/2696) - * [[`b3fee8e6a6`](https://github.com/nodejs/node/commit/b3fee8e6a6)] - **deps**: upgrade to npm 2.14.2 (Kat Marchán) [#2696](https://github.com/nodejs/node/pull/2696) - * [[`4593539b92`](https://github.com/nodejs/node/commit/4593539b92)] - **deps**: backport 75e43a6 from v8 upstream (saper) [#2636](https://github.com/nodejs/node/pull/2636) - * [[`2d1438cfe0`](https://github.com/nodejs/node/commit/2d1438cfe0)] - **doc**: fix broken link in repl.markdown (Danny Nemer) [#2827](https://github.com/nodejs/node/pull/2827) - * [[`9dd9c85a48`](https://github.com/nodejs/node/commit/9dd9c85a48)] - **doc**: fix typos in README (Ionică Bizău) [#2852](https://github.com/nodejs/node/pull/2852) - * [[`476125d403`](https://github.com/nodejs/node/commit/476125d403)] - **doc**: add tunniclm as a collaborator (Mike Tunnicliffe) [#2826](https://github.com/nodejs/node/pull/2826) - * [[`0603a92d48`](https://github.com/nodejs/node/commit/0603a92d48)] - **doc**: fix two doc errors in stream and process (Jeremiah Senkpiel) [#2549](https://github.com/nodejs/node/pull/2549) - * [[`da2902ddfd`](https://github.com/nodejs/node/commit/da2902ddfd)] - **doc**: use "Calls" over "Executes" for consistency (Minwoo Jung) [#2800](https://github.com/nodejs/node/pull/2800) - * [[`5e93bc4fba`](https://github.com/nodejs/node/commit/5e93bc4fba)] - **doc**: use US English for consistency (Anne-Gaelle Colom) [#2784](https://github.com/nodejs/node/pull/2784) - * [[`3ee7fbcefd`](https://github.com/nodejs/node/commit/3ee7fbcefd)] - **doc**: use 3rd person singular for consistency (Anne-Gaelle Colom) [#2765](https://github.com/nodejs/node/pull/2765) - * [[`4fdccb9eb7`](https://github.com/nodejs/node/commit/4fdccb9eb7)] - **doc**: fix comma splice in Assertion Testing doc (Rich Trott) [#2728](https://github.com/nodejs/node/pull/2728) - * [[`28c2d310d6`](https://github.com/nodejs/node/commit/28c2d310d6)] - **doc**: update AUTHORS list (Rod Vagg) - * [[`324c073fb9`](https://github.com/nodejs/node/commit/324c073fb9)] - **doc**: add TSC meeting minutes 2015-09-02 (Rod Vagg) [#2674](https://github.com/nodejs/node/pull/2674) - * [[`8929445686`](https://github.com/nodejs/node/commit/8929445686)] - **doc**: update url doc to account for escaping (Jeremiah Senkpiel) [#2605](https://github.com/nodejs/node/pull/2605) - * [[`512dad6883`](https://github.com/nodejs/node/commit/512dad6883)] - **doc**: reorder collaborators by their usernames (Johan Bergström) [#2322](https://github.com/nodejs/node/pull/2322) - * [[`8372ea2ca5`](https://github.com/nodejs/node/commit/8372ea2ca5)] - **doc,test**: enable recursive file watching in Windows (Sakthipriyan Vairamani) [#2649](https://github.com/nodejs/node/pull/2649) - * [[`daf6c533cc`](https://github.com/nodejs/node/commit/daf6c533cc)] - **events,lib**: don't require EE#listenerCount() (Jeremiah Senkpiel) [#2661](https://github.com/nodejs/node/pull/2661) - * [[`d8371a801e`](https://github.com/nodejs/node/commit/d8371a801e)] - **http_server**: fix resume after socket close (Fedor Indutny) [#2824](https://github.com/nodejs/node/pull/2824) - * [[`7f7d4fdddd`](https://github.com/nodejs/node/commit/7f7d4fdddd)] - **node-gyp**: float 3.0.1, minor fix for download url (Rod Vagg) [#2737](https://github.com/nodejs/node/pull/2737) - * [[`91cee73294`](https://github.com/nodejs/node/commit/91cee73294)] - **src**: use ZCtxt as a source for v8::Isolates (Roman Klauke) [#2547](https://github.com/nodejs/node/pull/2547) - * [[`ac98e13b95`](https://github.com/nodejs/node/commit/ac98e13b95)] - **src**: s/ia32/x86 for process.release.libUrl for win (Rod Vagg) [#2699](https://github.com/nodejs/node/pull/2699) - * [[`ca6c3223e1`](https://github.com/nodejs/node/commit/ca6c3223e1)] - **src**: use standard conform snprintf on windows (Karl Skomski) [#2404](https://github.com/nodejs/node/pull/2404) - * [[`b028978a53`](https://github.com/nodejs/node/commit/b028978a53)] - **src**: fix buffer overflow for long exception lines (Karl Skomski) [#2404](https://github.com/nodejs/node/pull/2404) - * [[`e73eafd7e7`](https://github.com/nodejs/node/commit/e73eafd7e7)] - **src**: fix memory leak in ExternString (Karl Skomski) [#2402](https://github.com/nodejs/node/pull/2402) - * [[`d370306de1`](https://github.com/nodejs/node/commit/d370306de1)] - **src**: only set v8 flags if argc > 1 (Evan Lucas) [#2646](https://github.com/nodejs/node/pull/2646) - * [[`ed087836af`](https://github.com/nodejs/node/commit/ed087836af)] - **streams**: refactor LazyTransform to internal/ (Brendan Ashworth) [#2566](https://github.com/nodejs/node/pull/2566) - * [[`993c22fe0e`](https://github.com/nodejs/node/commit/993c22fe0e)] - **test**: remove disabled test (Rich Trott) [#2841](https://github.com/nodejs/node/pull/2841) - * [[`1474f29d1f`](https://github.com/nodejs/node/commit/1474f29d1f)] - **test**: split up internet dns tests (Rich Trott) [#2802](https://github.com/nodejs/node/pull/2802) - * [[`601a97622b`](https://github.com/nodejs/node/commit/601a97622b)] - **test**: increase dgram timeout for armv6 (Rich Trott) [#2808](https://github.com/nodejs/node/pull/2808) - * [[`1dad19ba81`](https://github.com/nodejs/node/commit/1dad19ba81)] - **test**: remove valid hostname check in test-dns.js (Rich Trott) [#2785](https://github.com/nodejs/node/pull/2785) - * [[`f3d5891a3f`](https://github.com/nodejs/node/commit/f3d5891a3f)] - **test**: expect error for test_lookup_ipv6_hint on FreeBSD (Rich Trott) [#2724](https://github.com/nodejs/node/pull/2724) - * [[`2ffb21baf1`](https://github.com/nodejs/node/commit/2ffb21baf1)] - **test**: fix use of `common` before required (Rod Vagg) [#2685](https://github.com/nodejs/node/pull/2685) - * [[`b2c5479a14`](https://github.com/nodejs/node/commit/b2c5479a14)] - **test**: refactor to eliminate flaky test (Rich Trott) [#2609](https://github.com/nodejs/node/pull/2609) - * [[`fcfd15f8f9`](https://github.com/nodejs/node/commit/fcfd15f8f9)] - **test**: mark eval_messages as flaky (Alexis Campailla) [#2648](https://github.com/nodejs/node/pull/2648) - * [[`1865cad7ae`](https://github.com/nodejs/node/commit/1865cad7ae)] - **test**: mark test-vm-syntax-error-stderr as flaky (João Reis) [#2662](https://github.com/nodejs/node/pull/2662) - * [[`b0014ecd27`](https://github.com/nodejs/node/commit/b0014ecd27)] - **test**: mark test-repl-persistent-history as flaky (João Reis) [#2659](https://github.com/nodejs/node/pull/2659) - * [[`74ff9bc86c`](https://github.com/nodejs/node/commit/74ff9bc86c)] - **timers**: minor _unrefActive fixes and improvements (Jeremiah Senkpiel) [#2540](https://github.com/nodejs/node/pull/2540) - * [[`5d14a6eca7`](https://github.com/nodejs/node/commit/5d14a6eca7)] - **timers**: don't mutate unref list while iterating it (Julien Gilli) [#2540](https://github.com/nodejs/node/pull/2540) - * [[`6e744c58f2`](https://github.com/nodejs/node/commit/6e744c58f2)] - **timers**: Avoid linear scan in _unrefActive. (Julien Gilli) [#2540](https://github.com/nodejs/node/pull/2540) - * [[`07fbf835ad`](https://github.com/nodejs/node/commit/07fbf835ad)] - **tools**: open `test.tap` file in write-binary mode (Sakthipriyan Vairamani) [#2837](https://github.com/nodejs/node/pull/2837) - * [[`6d9198f7f1`](https://github.com/nodejs/node/commit/6d9198f7f1)] - **tools**: add missing tick processor polyfill (Matt Loring) [#2694](https://github.com/nodejs/node/pull/2694) - * [[`7b16597527`](https://github.com/nodejs/node/commit/7b16597527)] - **tools**: fix flakiness in test-tick-processor (Matt Loring) [#2694](https://github.com/nodejs/node/pull/2694) - * [[`ef83029356`](https://github.com/nodejs/node/commit/ef83029356)] - **tools**: remove hyphen in TAP result (Sakthipriyan Vairamani) [#2718](https://github.com/nodejs/node/pull/2718) - * [[`ac45ef9157`](https://github.com/nodejs/node/commit/ac45ef9157)] - **win,msi**: fix documentation shortcut url (Brian White) [#2781](https://github.com/nodejs/node/pull/2781) - - - ## 2015-09-02, Version 3.3.0, @rvagg - - ### Notable changes - - * **build**: Add a `--link-module` option to `configure` that can be used to bundle additional JavaScript modules into a built binary (Bradley Meck) [#2497](https://github.com/nodejs/node/pull/2497) - * **docs**: Merge outstanding doc updates from joyent/node (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * **http_parser**: Significant performance improvement by having `http.Server` consume all initial data from its `net.Socket` and parsing directly without having to enter JavaScript. Any `'data'` listeners on the `net.Socket` will result in the data being "unconsumed" into JavaScript, thereby undoing any performance gains. (Fedor Indutny) [#2355](https://github.com/nodejs/node/pull/2355) - * **libuv**: Upgrade to 1.7.3 (from 1.6.1), see [ChangeLog](https://github.com/libuv/libuv/blob/v1.x/ChangeLog) for details (Saúl Ibarra Corretgé) [#2310](https://github.com/nodejs/node/pull/2310) - * **V8**: Upgrade to 4.4.63.30 (from 4.4.63.26) (Michaël Zasso) [#2482](https://github.com/nodejs/node/pull/2482) - - ### Known issues - - See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. - - * Some uses of computed object shorthand properties are not handled correctly by the current version of V8. e.g. `[{ [prop]: val }]` evaluates to `[{}]`. [#2507](https://github.com/nodejs/node/issues/2507) - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). - - ### Commits - - * [[`1a531b4e44`](https://github.com/nodejs/node/commit/1a531b4e44)] - **(SEMVER-MINOR)** Introduce --link-module to ./configure (Bradley Meck) [#2497](https://github.com/nodejs/node/pull/2497) - * [[`d2f314c190`](https://github.com/nodejs/node/commit/d2f314c190)] - **build**: fix borked chmod call for release uploads (Rod Vagg) [#2645](https://github.com/nodejs/node/pull/2645) - * [[`3172e9c541`](https://github.com/nodejs/node/commit/3172e9c541)] - **build**: set file permissions before uploading (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) - * [[`a860d7fae1`](https://github.com/nodejs/node/commit/a860d7fae1)] - **build**: change staging directory on new server (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) - * [[`50c0baa8d7`](https://github.com/nodejs/node/commit/50c0baa8d7)] - **build**: rename 'doc' directory to 'docs' for upload (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) - * [[`0a0577cf5f`](https://github.com/nodejs/node/commit/0a0577cf5f)] - **build**: fix bad cherry-pick for vcbuild.bat build-release (Rod Vagg) [#2625](https://github.com/nodejs/node/pull/2625) - * [[`34de90194b`](https://github.com/nodejs/node/commit/34de90194b)] - **build**: only define NODE_V8_OPTIONS if not empty (Evan Lucas) [#2532](https://github.com/nodejs/node/pull/2532) - * [[`944174b189`](https://github.com/nodejs/node/commit/944174b189)] - **build**: make ci test addons in test/addons (Ben Noordhuis) [#2428](https://github.com/nodejs/node/pull/2428) - * [[`e955f9a1b0`](https://github.com/nodejs/node/commit/e955f9a1b0)] - **crypto**: Use OPENSSL_cleanse to shred the data. (Сковорода Никита Андреевич) [#2575](https://github.com/nodejs/node/pull/2575) - * [[`395d736b9d`](https://github.com/nodejs/node/commit/395d736b9d)] - **debugger**: use strict equality comparison (Minwoo Jung) [#2558](https://github.com/nodejs/node/pull/2558) - * [[`1d0e5210a8`](https://github.com/nodejs/node/commit/1d0e5210a8)] - **deps**: upgrade libuv to 1.7.3 (Saúl Ibarra Corretgé) [#2310](https://github.com/nodejs/node/pull/2310) - * [[`34ef53364f`](https://github.com/nodejs/node/commit/34ef53364f)] - **deps**: update V8 to 4.4.63.30 (Michaël Zasso) [#2482](https://github.com/nodejs/node/pull/2482) - * [[`23579a5f4a`](https://github.com/nodejs/node/commit/23579a5f4a)] - **doc**: add TSC meeting minutes 2015-08-12 (Rod Vagg) [#2438](https://github.com/nodejs/node/pull/2438) - * [[`0cc59299a4`](https://github.com/nodejs/node/commit/0cc59299a4)] - **doc**: add TSC meeting minutes 2015-08-26 (Rod Vagg) [#2591](https://github.com/nodejs/node/pull/2591) - * [[`6efa96e33a`](https://github.com/nodejs/node/commit/6efa96e33a)] - **doc**: merge CHANGELOG.md with joyent/node ChangeLog (Minqi Pan) [#2536](https://github.com/nodejs/node/pull/2536) - * [[`f75d54607b`](https://github.com/nodejs/node/commit/f75d54607b)] - **doc**: clarify cluster behaviour with no workers (Jeremiah Senkpiel) [#2606](https://github.com/nodejs/node/pull/2606) - * [[`8936302121`](https://github.com/nodejs/node/commit/8936302121)] - **doc**: minor clarification in buffer.markdown (Сковорода Никита Андреевич) [#2574](https://github.com/nodejs/node/pull/2574) - * [[`0db0e53753`](https://github.com/nodejs/node/commit/0db0e53753)] - **doc**: add @jasnell and @sam-github to release team (Rod Vagg) [#2455](https://github.com/nodejs/node/pull/2455) - * [[`c16e100593`](https://github.com/nodejs/node/commit/c16e100593)] - **doc**: reorg release team to separate section (Rod Vagg) [#2455](https://github.com/nodejs/node/pull/2455) - * [[`e3e00143fd`](https://github.com/nodejs/node/commit/e3e00143fd)] - **doc**: fix bad merge on modules.markdown (James M Snell) - * [[`2f62455880`](https://github.com/nodejs/node/commit/2f62455880)] - **doc**: minor additional corrections and improvements (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`3bd08aac4b`](https://github.com/nodejs/node/commit/3bd08aac4b)] - **doc**: minor grammatical update in crypto.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`f707189370`](https://github.com/nodejs/node/commit/f707189370)] - **doc**: minor grammatical update (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`6c98cf0266`](https://github.com/nodejs/node/commit/6c98cf0266)] - **doc**: remove repeated statement in globals.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`48e6ccf8c2`](https://github.com/nodejs/node/commit/48e6ccf8c2)] - **doc**: remove 'dudes' from documentation (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`b5d68f8076`](https://github.com/nodejs/node/commit/b5d68f8076)] - **doc**: update tense in child_process.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`242e3fe3ba`](https://github.com/nodejs/node/commit/242e3fe3ba)] - **doc**: fixed worker.id type (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`ea9ee15c21`](https://github.com/nodejs/node/commit/ea9ee15c21)] - **doc**: port is optional for socket.bind() (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`0ff6657a50`](https://github.com/nodejs/node/commit/0ff6657a50)] - **doc**: fix minor types and grammar in fs docs (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`94d83c04f2`](https://github.com/nodejs/node/commit/94d83c04f2)] - **doc**: update parameter name in net.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`04111ce40f`](https://github.com/nodejs/node/commit/04111ce40f)] - **doc**: small typo in domain.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`c9fdd1bbbf`](https://github.com/nodejs/node/commit/c9fdd1bbbf)] - **doc**: fixed typo in net.markdown (missing comma) (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`27c07b3f8e`](https://github.com/nodejs/node/commit/27c07b3f8e)] - **doc**: update description of fs.exists in fs.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`52018e73d9`](https://github.com/nodejs/node/commit/52018e73d9)] - **doc**: clarification on the 'close' event (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`f6d3b87a25`](https://github.com/nodejs/node/commit/f6d3b87a25)] - **doc**: improve working in stream.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`b5da89431a`](https://github.com/nodejs/node/commit/b5da89431a)] - **doc**: update path.extname documentation (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`1d4ea609db`](https://github.com/nodejs/node/commit/1d4ea609db)] - **doc**: small clarifications to modules.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`c888985591`](https://github.com/nodejs/node/commit/c888985591)] - **doc**: code style cleanups in repl.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`105b493595`](https://github.com/nodejs/node/commit/105b493595)] - **doc**: correct grammar in cluster.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`51b86ccac7`](https://github.com/nodejs/node/commit/51b86ccac7)] - **doc**: Clarify the module.parent is set once (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) - * [[`d2ffecba2d`](https://github.com/nodejs/node/commit/d2ffecba2d)] - **doc**: add internal modules notice (Jeremiah Senkpiel) [#2523](https://github.com/nodejs/node/pull/2523) - * [[`b36debd5cb`](https://github.com/nodejs/node/commit/b36debd5cb)] - **env**: introduce `KickNextTick` (Fedor Indutny) [#2355](https://github.com/nodejs/node/pull/2355) - * [[`1bc446863f`](https://github.com/nodejs/node/commit/1bc446863f)] - **http_parser**: consume StreamBase instance (Fedor Indutny) [#2355](https://github.com/nodejs/node/pull/2355) - * [[`ce04b735cc`](https://github.com/nodejs/node/commit/ce04b735cc)] - **src**: only memcmp if length > 0 in Buffer::Compare (Karl Skomski) [#2544](https://github.com/nodejs/node/pull/2544) - * [[`31823e37c7`](https://github.com/nodejs/node/commit/31823e37c7)] - **src**: DRY getsockname/getpeername code (Ben Noordhuis) [#956](https://github.com/nodejs/node/pull/956) - * [[`13fd96dda3`](https://github.com/nodejs/node/commit/13fd96dda3)] - **src**: missing Exception::Error in node_http_parser (Jeremiah Senkpiel) [#2550](https://github.com/nodejs/node/pull/2550) - * [[`42e075ae02`](https://github.com/nodejs/node/commit/42e075ae02)] - **test**: improve performance of stringbytes test (Trevor Norris) [#2544](https://github.com/nodejs/node/pull/2544) - * [[`fc726399fd`](https://github.com/nodejs/node/commit/fc726399fd)] - **test**: unmark test-process-argv-0.js as flaky (Rich Trott) [#2613](https://github.com/nodejs/node/pull/2613) - * [[`7727ba1394`](https://github.com/nodejs/node/commit/7727ba1394)] - **test**: lint and refactor to avoid autocrlf issue (Roman Reiss) [#2494](https://github.com/nodejs/node/pull/2494) - * [[`c56aa829f0`](https://github.com/nodejs/node/commit/c56aa829f0)] - **test**: use tmpDir instead of fixturesDir (Sakthipriyan Vairamani) [#2583](https://github.com/nodejs/node/pull/2583) - * [[`5e65181ea4`](https://github.com/nodejs/node/commit/5e65181ea4)] - **test**: handling failure cases properly (Sakthipriyan Vairamani) [#2206](https://github.com/nodejs/node/pull/2206) - * [[`c48b95e847`](https://github.com/nodejs/node/commit/c48b95e847)] - **test**: initial list of flaky tests (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) - * [[`94e88498ba`](https://github.com/nodejs/node/commit/94e88498ba)] - **test**: pass args to test-ci via env variable (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) - * [[`09987c7a1c`](https://github.com/nodejs/node/commit/09987c7a1c)] - **test**: support flaky tests in test-ci (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) - * [[`08b83c8b45`](https://github.com/nodejs/node/commit/08b83c8b45)] - **test**: add test configuration templates (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) - * [[`8f8ab6fa57`](https://github.com/nodejs/node/commit/8f8ab6fa57)] - **test**: runner should return 0 on flaky tests (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) - * [[`0cfd3be9c6`](https://github.com/nodejs/node/commit/0cfd3be9c6)] - **test**: runner support for flaky tests (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) - * [[`3492d2d4c6`](https://github.com/nodejs/node/commit/3492d2d4c6)] - **test**: make test-process-argv-0 robust (Rich Trott) [#2541](https://github.com/nodejs/node/pull/2541) - * [[`a96cc31710`](https://github.com/nodejs/node/commit/a96cc31710)] - **test**: speed up test-child-process-spawnsync.js (Rich Trott) [#2542](https://github.com/nodejs/node/pull/2542) - * [[`856baf4c67`](https://github.com/nodejs/node/commit/856baf4c67)] - **test**: make spawnSync() test robust (Rich Trott) [#2535](https://github.com/nodejs/node/pull/2535) - * [[`3aa6bbb648`](https://github.com/nodejs/node/commit/3aa6bbb648)] - **tools**: update release.sh to work with new website (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) - * [[`f2f0fe45ff`](https://github.com/nodejs/node/commit/f2f0fe45ff)] - **tools**: make add-on scraper print filenames (Ben Noordhuis) [#2428](https://github.com/nodejs/node/pull/2428) - * [[`bb24c4a418`](https://github.com/nodejs/node/commit/bb24c4a418)] - **win,msi**: correct installation path registry keys (João Reis) [#2565](https://github.com/nodejs/node/pull/2565) - * [[`752977b888`](https://github.com/nodejs/node/commit/752977b888)] - **win,msi**: change InstallScope to perMachine (João Reis) [#2565](https://github.com/nodejs/node/pull/2565) - - - ## 2015-08-25, Version 3.2.0, @rvagg - - ### Notable changes - - * **events**: Added `EventEmitter#listenerCount(event)` as a replacement for `EventEmitter.listenerCount(emitter, event)`, which has now been marked as deprecated in the docs. (Sakthipriyan Vairamani) [#2349](https://github.com/nodejs/node/pull/2349) - * **module**: Fixed an error with preloaded modules when the current working directory doesn't exist. (Bradley Meck) [#2353](https://github.com/nodejs/node/pull/2353) - * **node**: Startup time is now about 5% faster when not passing V8 flags. (Evan Lucas) [#2483](https://github.com/nodejs/node/pull/2483) - * **repl**: Tab-completion now works better with arrays. (James M Snell) [#2409](https://github.com/nodejs/node/pull/2409) - * **string_bytes**: Fixed an unaligned write in the handling of UCS2 encoding. (Fedor Indutny) [#2480](https://github.com/nodejs/node/pull/2480) - * **tls**: Added a new `--tls-cipher-list` flag that can be used to override the built-in default cipher list. (James M Snell) [#2412](https://github.com/nodejs/node/pull/2412) _Note: it is suggested you use the built-in cipher list as it has been carefully selected to reflect current security best practices and risk mitigation._ - - ### Known issues - - See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. - - * Some uses of computed object shorthand properties are not handled correctly by the current version of V8. e.g. `[{ [prop]: val }]` evaluates to `[{}]`. [#2507](https://github.com/nodejs/node/issues/2507) - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). - - ### Commits - - * [[`1cd794f129`](https://github.com/nodejs/node/commit/1cd794f129)] - **buffer**: reapply 07c0667 (Fedor Indutny) [#2487](https://github.com/nodejs/node/pull/2487) - * [[`156781dedd`](https://github.com/nodejs/node/commit/156781dedd)] - **build**: use required platform in android-configure (Evan Lucas) [#2501](https://github.com/nodejs/node/pull/2501) - * [[`77075ec906`](https://github.com/nodejs/node/commit/77075ec906)] - **crypto**: fix mem {de}allocation in ExportChallenge (Karl Skomski) [#2359](https://github.com/nodejs/node/pull/2359) - * [[`cb30414d9e`](https://github.com/nodejs/node/commit/cb30414d9e)] - **doc**: sync CHANGELOG.md from master (Roman Reiss) [#2524](https://github.com/nodejs/node/pull/2524) - * [[`9330f5ef45`](https://github.com/nodejs/node/commit/9330f5ef45)] - **doc**: make the deprecations consistent (Sakthipriyan Vairamani) [#2450](https://github.com/nodejs/node/pull/2450) - * [[`09437e0146`](https://github.com/nodejs/node/commit/09437e0146)] - **doc**: fix comments in tls_wrap.cc and _http_client.js (Minwoo Jung) [#2489](https://github.com/nodejs/node/pull/2489) - * [[`c9867fed29`](https://github.com/nodejs/node/commit/c9867fed29)] - **doc**: document response.finished in http.markdown (hackerjs) [#2414](https://github.com/nodejs/node/pull/2414) - * [[`7f23a83c42`](https://github.com/nodejs/node/commit/7f23a83c42)] - **doc**: update AUTHORS list (Rod Vagg) [#2505](https://github.com/nodejs/node/pull/2505) - * [[`cd0c362f67`](https://github.com/nodejs/node/commit/cd0c362f67)] - **doc**: update AUTHORS list (Rod Vagg) [#2318](https://github.com/nodejs/node/pull/2318) - * [[`2c7b9257ea`](https://github.com/nodejs/node/commit/2c7b9257ea)] - **doc**: add TSC meeting minutes 2015-07-29 (Rod Vagg) [#2437](https://github.com/nodejs/node/pull/2437) - * [[`aaefde793e`](https://github.com/nodejs/node/commit/aaefde793e)] - **doc**: add TSC meeting minutes 2015-08-19 (Rod Vagg) [#2460](https://github.com/nodejs/node/pull/2460) - * [[`51ef9106f5`](https://github.com/nodejs/node/commit/51ef9106f5)] - **doc**: add TSC meeting minutes 2015-06-03 (Rod Vagg) [#2453](https://github.com/nodejs/node/pull/2453) - * [[`7130b4cf1d`](https://github.com/nodejs/node/commit/7130b4cf1d)] - **doc**: fix links to original converged repo (Rod Vagg) [#2454](https://github.com/nodejs/node/pull/2454) - * [[`14f2aee1df`](https://github.com/nodejs/node/commit/14f2aee1df)] - **doc**: fix links to original gh issues for TSC meetings (Rod Vagg) [#2454](https://github.com/nodejs/node/pull/2454) - * [[`87a9ef0a40`](https://github.com/nodejs/node/commit/87a9ef0a40)] - **doc**: add audio recording links to TSC meeting minutes (Rod Vagg) [#2454](https://github.com/nodejs/node/pull/2454) - * [[`f5cf24afbc`](https://github.com/nodejs/node/commit/f5cf24afbc)] - **doc**: add TSC meeting minutes 2015-07-22 (Rod Vagg) [#2436](https://github.com/nodejs/node/pull/2436) - * [[`3f821b96eb`](https://github.com/nodejs/node/commit/3f821b96eb)] - **doc**: fix spelling mistake in node.js comment (Jacob Edelman) [#2391](https://github.com/nodejs/node/pull/2391) - * [[`3e6a6fcdd6`](https://github.com/nodejs/node/commit/3e6a6fcdd6)] - **(SEMVER-MINOR)** **events**: deprecate static listenerCount function (Sakthipriyan Vairamani) [#2349](https://github.com/nodejs/node/pull/2349) - * [[`023386c852`](https://github.com/nodejs/node/commit/023386c852)] - **fs**: replace bad_args macro with concrete error msg (Roman Klauke) [#2495](https://github.com/nodejs/node/pull/2495) - * [[`d1c27b2e29`](https://github.com/nodejs/node/commit/d1c27b2e29)] - **module**: fix module preloading when cwd is ENOENT (Bradley Meck) [#2353](https://github.com/nodejs/node/pull/2353) - * [[`5d7486941b`](https://github.com/nodejs/node/commit/5d7486941b)] - **repl**: filter integer keys from repl tab complete list (James M Snell) [#2409](https://github.com/nodejs/node/pull/2409) - * [[`7f02443a9a`](https://github.com/nodejs/node/commit/7f02443a9a)] - **repl**: dont throw ENOENT on NODE_REPL_HISTORY_FILE (Todd Kennedy) [#2451](https://github.com/nodejs/node/pull/2451) - * [[`56a2ae9cef`](https://github.com/nodejs/node/commit/56a2ae9cef)] - **src**: improve startup time (Evan Lucas) [#2483](https://github.com/nodejs/node/pull/2483) - * [[`14653c7429`](https://github.com/nodejs/node/commit/14653c7429)] - **stream**: rename poorly named function (Ben Noordhuis) [#2479](https://github.com/nodejs/node/pull/2479) - * [[`1c6e014bfa`](https://github.com/nodejs/node/commit/1c6e014bfa)] - **stream**: micro-optimize high water mark calculation (Ben Noordhuis) [#2479](https://github.com/nodejs/node/pull/2479) - * [[`f1f4b4c46d`](https://github.com/nodejs/node/commit/f1f4b4c46d)] - **stream**: fix off-by-factor-16 error in comment (Ben Noordhuis) [#2479](https://github.com/nodejs/node/pull/2479) - * [[`2d3f09bd76`](https://github.com/nodejs/node/commit/2d3f09bd76)] - **stream_base**: various improvements (Fedor Indutny) [#2351](https://github.com/nodejs/node/pull/2351) - * [[`c1ce423b35`](https://github.com/nodejs/node/commit/c1ce423b35)] - **string_bytes**: fix unaligned write in UCS2 (Fedor Indutny) [#2480](https://github.com/nodejs/node/pull/2480) - * [[`e4d0e86165`](https://github.com/nodejs/node/commit/e4d0e86165)] - **test**: refactor test-https-simple.js (Rich Trott) [#2433](https://github.com/nodejs/node/pull/2433) - * [[`0ea5c8d737`](https://github.com/nodejs/node/commit/0ea5c8d737)] - **test**: remove test-timers-first-fire (João Reis) [#2458](https://github.com/nodejs/node/pull/2458) - * [[`536c3d0537`](https://github.com/nodejs/node/commit/536c3d0537)] - **test**: use reserved IP in test-net-connect-timeout (Rich Trott) [#2257](https://github.com/nodejs/node/pull/2257) - * [[`5df06fd8df`](https://github.com/nodejs/node/commit/5df06fd8df)] - **test**: add spaces after keywords (Brendan Ashworth) - * [[`e714b5620e`](https://github.com/nodejs/node/commit/e714b5620e)] - **test**: remove unreachable code (Michaël Zasso) [#2289](https://github.com/nodejs/node/pull/2289) - * [[`3579f3a2a4`](https://github.com/nodejs/node/commit/3579f3a2a4)] - **test**: disallow unreachable code (Michaël Zasso) [#2289](https://github.com/nodejs/node/pull/2289) - * [[`3545e236fc`](https://github.com/nodejs/node/commit/3545e236fc)] - **test**: reduce timeouts in test-net-keepalive (Brendan Ashworth) [#2429](https://github.com/nodejs/node/pull/2429) - * [[`b60e690023`](https://github.com/nodejs/node/commit/b60e690023)] - **test**: improve test-net-server-pause-on-connect (Brendan Ashworth) [#2429](https://github.com/nodejs/node/pull/2429) - * [[`11d1b8fcaf`](https://github.com/nodejs/node/commit/11d1b8fcaf)] - **test**: improve test-net-pingpong (Brendan Ashworth) [#2429](https://github.com/nodejs/node/pull/2429) - * [[`5fef5c6562`](https://github.com/nodejs/node/commit/5fef5c6562)] - **(SEMVER-MINOR)** **tls**: add --tls-cipher-list command line switch (James M Snell) [#2412](https://github.com/nodejs/node/pull/2412) - * [[`d9b70f9cbf`](https://github.com/nodejs/node/commit/d9b70f9cbf)] - **tls**: handle empty cert in checkServerIndentity (Mike Atkins) [#2343](https://github.com/nodejs/node/pull/2343) - * [[`4f8e34c202`](https://github.com/nodejs/node/commit/4f8e34c202)] - **tools**: add license boilerplate to check-imports.sh (James M Snell) [#2386](https://github.com/nodejs/node/pull/2386) - * [[`b76b9197f9`](https://github.com/nodejs/node/commit/b76b9197f9)] - **tools**: enable space-after-keywords in eslint (Brendan Ashworth) - * [[`64a8f30a70`](https://github.com/nodejs/node/commit/64a8f30a70)] - **tools**: fix anchors in generated documents (Sakthipriyan Vairamani) [#2491](https://github.com/nodejs/node/pull/2491) - * [[`22e344ea10`](https://github.com/nodejs/node/commit/22e344ea10)] - **win**: fix custom actions for WiX older than 3.9 (João Reis) [#2365](https://github.com/nodejs/node/pull/2365) - * [[`b5bd3ebfc8`](https://github.com/nodejs/node/commit/b5bd3ebfc8)] - **win**: fix custom actions on Visual Studio != 2013 (Julien Gilli) [#2365](https://github.com/nodejs/node/pull/2365) - - - ## 2015-08-18, Version 3.1.0, @Fishrock123 - - ### Notable changes - - * **buffer**: Fixed a couple large memory leaks (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352). - * **crypto**: - - Fixed a couple of minor memory leaks (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375). - - Signing now checks for OpenSSL errors (Minqi Pan) [#2342](https://github.com/nodejs/node/pull/2342). **Note that this may expose previously hidden errors in user code.** - * **intl**: Intl support using small-icu is now enabled by default in builds (Steven R. Loomis) [#2264](https://github.com/nodejs/node/pull/2264). - - [`String#normalize()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) can now be used for unicode normalization. - - The [`Intl`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl) object and various `String` and `Number` methods are present, but only support the English locale. - - For support of all locales, node must be built with [full-icu](https://github.com/nodejs/node#build-with-full-icu-support-all-locales-supported-by-icu). - * **tls**: Fixed tls throughput being much lower after an incorrect merge (Fedor Indutny) [#2381](https://github.com/nodejs/node/pull/2381). - * **tools**: The v8 tick processor now comes bundled with node (Matt Loring) [#2090](https://github.com/nodejs/node/pull/2090). - - This can be used by producing performance profiling output by running node with `--perf`, then running your appropriate platform's script on the output as found in [tools/v8-prof](https://github.com/nodejs/node/tree/master/tools/v8-prof). - * **util**: `util.inspect(obj)` now prints the constructor name of the object if there is one (Christopher Monsanto) [#1935](https://github.com/nodejs/io.js/pull/1935). - - ### Known issues - - See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). - - ### Commits - - * [[`3645dc62ed`](https://github.com/nodejs/node/commit/3645dc62ed)] - **build**: work around VS2015 issue in ICU <56 (Steven R. Loomis) [#2283](https://github.com/nodejs/node/pull/2283) - * [[`1f12e03266`](https://github.com/nodejs/node/commit/1f12e03266)] - **(SEMVER-MINOR)** **build**: intl: converge from joyent/node (Steven R. Loomis) [#2264](https://github.com/nodejs/node/pull/2264) - * [[`071640abdd`](https://github.com/nodejs/node/commit/071640abdd)] - **build**: Intl: bump ICU4C from 54 to 55 (Steven R. Loomis) [#2293](https://github.com/nodejs/node/pull/2293) - * [[`07a88b0c8b`](https://github.com/nodejs/node/commit/07a88b0c8b)] - **build**: update manifest to include Windows 10 (Lucien Greathouse) [#2332](https://github.com/nodejs/io.js/pull/2332) - * [[`0bb099f444`](https://github.com/nodejs/node/commit/0bb099f444)] - **build**: expand ~ in install prefix early (Ben Noordhuis) [#2307](https://github.com/nodejs/io.js/pull/2307) - * [[`7fe6dd8f5d`](https://github.com/nodejs/node/commit/7fe6dd8f5d)] - **crypto**: check for OpenSSL errors when signing (Minqi Pan) [#2342](https://github.com/nodejs/node/pull/2342) - * [[`605f6ee904`](https://github.com/nodejs/node/commit/605f6ee904)] - **crypto**: fix memory leak in PBKDF2Request (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) - * [[`ba6eb8af12`](https://github.com/nodejs/node/commit/ba6eb8af12)] - **crypto**: fix memory leak in ECDH::SetPrivateKey (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) - * [[`6a16368611`](https://github.com/nodejs/node/commit/6a16368611)] - **crypto**: fix memory leak in PublicKeyCipher::Cipher (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) - * [[`a760a87803`](https://github.com/nodejs/node/commit/a760a87803)] - **crypto**: fix memory leak in SafeX509ExtPrint (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) - * [[`f45487cd6e`](https://github.com/nodejs/node/commit/f45487cd6e)] - **crypto**: fix memory leak in SetDHParam (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) - * [[`2ff183dd86`](https://github.com/nodejs/node/commit/2ff183dd86)] - **doc**: Update FIPS instructions in README.md (Michael Dawson) [#2278](https://github.com/nodejs/node/pull/2278) - * [[`6483bc2e8f`](https://github.com/nodejs/node/commit/6483bc2e8f)] - **doc**: clarify options for fs.watchFile() (Rich Trott) [#2425](https://github.com/nodejs/node/pull/2425) - * [[`e76822f454`](https://github.com/nodejs/node/commit/e76822f454)] - **doc**: multiple documentation updates cherry picked from v0.12 (James M Snell) [#2302](https://github.com/nodejs/io.js/pull/2302) - * [[`1738c9680b`](https://github.com/nodejs/node/commit/1738c9680b)] - **net**: ensure Socket reported address is current (Ryan Graham) [#2095](https://github.com/nodejs/io.js/pull/2095) - * [[`844d3f0e3e`](https://github.com/nodejs/node/commit/844d3f0e3e)] - **path**: use '===' instead of '==' for comparison (Sam Stites) [#2388](https://github.com/nodejs/node/pull/2388) - * [[`7118b8a882`](https://github.com/nodejs/node/commit/7118b8a882)] - **path**: remove dead code in favor of unit tests (Nathan Woltman) [#2282](https://github.com/nodejs/io.js/pull/2282) - * [[`34f2cfa806`](https://github.com/nodejs/node/commit/34f2cfa806)] - **src**: better error message on failed Buffer malloc (Karl Skomski) [#2422](https://github.com/nodejs/node/pull/2422) - * [[`b196c1da3c`](https://github.com/nodejs/node/commit/b196c1da3c)] - **src**: fix memory leak in DLOpen (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) - * [[`d1307b2995`](https://github.com/nodejs/node/commit/d1307b2995)] - **src**: don't use fopen() in require() fast path (Ben Noordhuis) [#2377](https://github.com/nodejs/node/pull/2377) - * [[`455ec570d1`](https://github.com/nodejs/node/commit/455ec570d1)] - **src**: rename Buffer::Use() to Buffer::New() (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) - * [[`fd63e1ce2b`](https://github.com/nodejs/node/commit/fd63e1ce2b)] - **src**: introduce internal Buffer::Copy() function (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) - * [[`5586ceca13`](https://github.com/nodejs/node/commit/5586ceca13)] - **src**: move internal functions out of node_buffer.h (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) - * [[`bff9bcddb6`](https://github.com/nodejs/node/commit/bff9bcddb6)] - **src**: plug memory leaks (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) - * [[`ccf12df4f3`](https://github.com/nodejs/node/commit/ccf12df4f3)] - **(SEMVER-MINOR)** **src**: add total_available_size to v8 statistics (Roman Klauke) [#2348](https://github.com/nodejs/io.js/pull/2348) - * [[`194eeb841b`](https://github.com/nodejs/node/commit/194eeb841b)] - **test**: drop Isolate::GetCurrent() from addon tests (Ben Noordhuis) [#2427](https://github.com/nodejs/node/pull/2427) - * [[`46cdb2f6e2`](https://github.com/nodejs/node/commit/46cdb2f6e2)] - **test**: lint addon tests (Ben Noordhuis) [#2427](https://github.com/nodejs/node/pull/2427) - * [[`850c794882`](https://github.com/nodejs/node/commit/850c794882)] - **test**: refactor test-fs-watchfile.js (Rich Trott) [#2393](https://github.com/nodejs/node/pull/2393) - * [[`a3160c0a33`](https://github.com/nodejs/node/commit/a3160c0a33)] - **test**: correct spelling of 'childProcess' (muddletoes) [#2389](https://github.com/nodejs/node/pull/2389) - * [[`e51f90d747`](https://github.com/nodejs/node/commit/e51f90d747)] - **test**: option to run a subset of tests (João Reis) [#2260](https://github.com/nodejs/io.js/pull/2260) - * [[`cc46d3bca3`](https://github.com/nodejs/node/commit/cc46d3bca3)] - **test**: clarify dropMembership() call (Rich Trott) [#2062](https://github.com/nodejs/io.js/pull/2062) - * [[`0ee4df9c7a`](https://github.com/nodejs/node/commit/0ee4df9c7a)] - **test**: make listen-fd-cluster/server more robust (Sam Roberts) [#1944](https://github.com/nodejs/io.js/pull/1944) - * [[`cf9ba81398`](https://github.com/nodejs/node/commit/cf9ba81398)] - **test**: address timing issues in simple http tests (Gireesh Punathil) [#2294](https://github.com/nodejs/io.js/pull/2294) - * [[`cbb75c4f86`](https://github.com/nodejs/node/commit/cbb75c4f86)] - **tls**: fix throughput issues after incorrect merge (Fedor Indutny) [#2381](https://github.com/nodejs/node/pull/2381) - * [[`94b765f409`](https://github.com/nodejs/node/commit/94b765f409)] - **tls**: fix check for reused session (Fedor Indutny) [#2312](https://github.com/nodejs/io.js/pull/2312) - * [[`e83a41ad65`](https://github.com/nodejs/node/commit/e83a41ad65)] - **tls**: introduce internal `onticketkeycallback` (Fedor Indutny) [#2312](https://github.com/nodejs/io.js/pull/2312) - * [[`fb0f5d733f`](https://github.com/nodejs/node/commit/fb0f5d733f)] - **(SEMVER-MINOR)** **tools**: run the tick processor without building v8 (Matt Loring) [#2090](https://github.com/nodejs/node/pull/2090) - * [[`7606bdb897`](https://github.com/nodejs/node/commit/7606bdb897)] - **(SEMVER-MINOR)** **util**: display constructor when inspecting objects (Christopher Monsanto) [#1935](https://github.com/nodejs/io.js/pull/1935) - - - ## 2015-08-04, Version 3.0.0, @rvagg - - ### Notable changes - - * **buffer**: - - Due to changes in V8, it has been necessary to reimplement `Buffer` on top of V8's `Uint8Array`. Every effort has been made to minimize the performance impact, however `Buffer` instantiation is measurably slower. Access operations may be faster in some circumstances but the exact performance profile and difference over previous versions will depend on how `Buffer` is used within applications. (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825). - - `Buffer` can now take `ArrayBuffer`s as a constructor argument (Trevor Norris) [#2002](https://github.com/nodejs/node/pull/2002). - - When a single buffer is passed to `Buffer.concat()`, a new, copied `Buffer` object will be returned; previous behavior was to return the original `Buffer` object (Sakthipriyan Vairamani) [#1937](https://github.com/nodejs/node/pull/1937). - * **build**: PPC support has been added to core to allow compiling on pLinux BE and LE (AIX support coming soon) (Michael Dawson) [#2124](https://github.com/nodejs/node/pull/2124). - * **dgram**: If an error occurs within `socket.send()` and a callback has been provided, the error is only passed as the first argument to the callback and not emitted on the `socket` object; previous behavior was to do both (Matteo Collina & Chris Dickinson) [#1796](https://github.com/nodejs/node/pull/1796) - * **freelist**: Deprecate the undocumented `freelist` core module (Sakthipriyan Vairamani) [#2176](https://github.com/nodejs/node/pull/2176). - * **http**: - - Status codes now all use the official [IANA names](http://www.iana.org/assignments/http-status-codes) as per [RFC7231](https://tools.ietf.org/html/rfc7231), e.g. `http.STATUS_CODES[414]` now returns `'URI Too Long'` rather than `'Request-URI Too Large'` (jomo) [#1470](https://github.com/nodejs/node/pull/1470). - - Calling .getName() on an HTTP agent no longer returns a trailing colon, HTTPS agents will no longer return an extra colon near the middle of the string (Brendan Ashworth) [#1617](https://github.com/nodejs/node/pull/1617). - * **node**: - - `NODE_MODULE_VERSION` has been bumped to `45` to reflect the break in ABI (Rod Vagg) [#2096](https://github.com/nodejs/node/pull/2096). - - Introduce a new `process.release` object that contains a `name` property set to `'io.js'` and `sourceUrl`, `headersUrl` and `libUrl` (Windows only) properties containing URLs for the relevant resources; this is intended to be used by node-gyp (Rod Vagg) [#2154](https://github.com/nodejs/node/pull/2154). - - The version of node-gyp bundled with io.js now downloads and uses a tarball of header files from iojs.org rather than the full source for compiling native add-ons; it is hoped this is a temporary floating patch and the change will be upstreamed to node-gyp soon (Rod Vagg) [#2066](https://github.com/nodejs/node/pull/2066). - * **repl**: Persistent history is now enabled by default. The history file is located at ~/.node_repl_history, which can be overridden by the new environment variable `NODE_REPL_HISTORY`. This deprecates the previous `NODE_REPL_HISTORY_FILE` variable. Additionally, the format of the file has been changed to plain text to better handle file corruption. (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224). - * **smalloc**: The `smalloc` module has been removed as it is no longer possible to provide the API due to changes in V8 (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022). - * **tls**: Add `server.getTicketKeys()` and `server.setTicketKeys()` methods for [TLS session key](https://www.ietf.org/rfc/rfc5077.txt) rotation (Fedor Indutny) [#2227](https://github.com/nodejs/node/pull/2227). - * **v8**: Upgraded to 4.4.63.26 - - ES6: Enabled [computed property names](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names) - - ES6: `Array` can now be subclassed in strict mode - - ES6: Implement [rest parameters](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/rest_parameters) in staging, use the `--harmony-rest-parameters` command line flag - - ES6: Implement the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) in staging, use the `--harmony-spreadcalls` command line flag - - Removed `SetIndexedPropertiesToExternalArrayData` and related APIs, forcing a shift to `Buffer` to be reimplemented based on `Uint8Array` - - Introduction of `Maybe` and `MaybeLocal` C++ API for objects which _may_ or _may not_ have a value. - - Added support for PPC - - See also https://github.com/nodejs/node/wiki/Breaking-Changes#300-from-2x for a summary of the breaking changes (SEMVER-MAJOR). - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`60a974d200`](https://github.com/nodejs/node/commit/60a974d200)] - **buffer**: fix missing null/undefined check (Trevor Norris) [#2195](https://github.com/nodejs/node/pull/2195) - * [[`e6ab2d92bc`](https://github.com/nodejs/node/commit/e6ab2d92bc)] - **buffer**: fix not return on error (Trevor Norris) [#2225](https://github.com/nodejs/node/pull/2225) - * [[`1057d1186b`](https://github.com/nodejs/node/commit/1057d1186b)] - **buffer**: rename internal/buffer_new.js to buffer.js (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) - * [[`4643b8b667`](https://github.com/nodejs/node/commit/4643b8b667)] - **(SEMVER-MINOR)** **buffer**: allow ArrayBuffer as Buffer argument (Trevor Norris) [#2002](https://github.com/nodejs/node/pull/2002) - * [[`e5ada116cd`](https://github.com/nodejs/node/commit/e5ada116cd)] - **buffer**: minor cleanup from rebase (Trevor Norris) [#2003](https://github.com/nodejs/node/pull/2003) - * [[`b625ab4242`](https://github.com/nodejs/node/commit/b625ab4242)] - **buffer**: fix usage of kMaxLength (Trevor Norris) [#2003](https://github.com/nodejs/node/pull/2003) - * [[`eea66e2a7b`](https://github.com/nodejs/node/commit/eea66e2a7b)] - **(SEMVER-MAJOR)** **buffer**: fix case of one buffer passed to concat (Sakthipriyan Vairamani) [#1937](https://github.com/nodejs/node/pull/1937) - * [[`8664084166`](https://github.com/nodejs/node/commit/8664084166)] - **buffer**: make additional changes to native API (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) - * [[`36f78f4c1c`](https://github.com/nodejs/node/commit/36f78f4c1c)] - **buffer**: switch API to return MaybeLocal (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) - * [[`571ec13841`](https://github.com/nodejs/node/commit/571ec13841)] - **buffer**: switch to using Maybe API (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) - * [[`d75f5c8d0e`](https://github.com/nodejs/node/commit/d75f5c8d0e)] - **buffer**: finish implementing FreeCallback (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) - * [[`63da0dfd3a`](https://github.com/nodejs/node/commit/63da0dfd3a)] - **buffer**: implement Uint8Array backed Buffer (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) - * [[`23be6ca189`](https://github.com/nodejs/node/commit/23be6ca189)] - **buffer**: allow ARGS_THIS to accept a name (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) - * [[`971de5e417`](https://github.com/nodejs/node/commit/971de5e417)] - **build**: prepare Windows installer for i18n support (Frederic Hemberger) [#2247](https://github.com/nodejs/node/pull/2247) - * [[`2ba8b23661`](https://github.com/nodejs/node/commit/2ba8b23661)] - **build**: add 'x86' option back in to configure (Rod Vagg) [#2233](https://github.com/nodejs/node/pull/2233) - * [[`b4226e797a`](https://github.com/nodejs/node/commit/b4226e797a)] - **build**: first set of updates to enable PPC support (Michael Dawson) [#2124](https://github.com/nodejs/node/pull/2124) - * [[`24dd016deb`](https://github.com/nodejs/node/commit/24dd016deb)] - **build**: produce symbol map files on windows (Ali Ijaz Sheikh) [#2243](https://github.com/nodejs/node/pull/2243) - * [[`423d8944ce`](https://github.com/nodejs/node/commit/423d8944ce)] - **cluster**: do not unconditionally set --debug-port (cjihrig) [#1949](https://github.com/nodejs/node/pull/1949) - * [[`fa98b97171`](https://github.com/nodejs/node/commit/fa98b97171)] - **cluster**: add handle ref/unref stubs in rr mode (Ben Noordhuis) [#2274](https://github.com/nodejs/node/pull/2274) - * [[`944f68046c`](https://github.com/nodejs/node/commit/944f68046c)] - **crypto**: remove kMaxLength on randomBytes() (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) - * [[`3d3c687012`](https://github.com/nodejs/node/commit/3d3c687012)] - **deps**: update V8 to 4.4.63.26 (Michaël Zasso) [#2220](https://github.com/nodejs/node/pull/2220) - * [[`3aad4fa89a`](https://github.com/nodejs/node/commit/3aad4fa89a)] - **deps**: upgrade v8 to 4.4.63.12 (Ben Noordhuis) [#2092](https://github.com/nodejs/node/pull/2092) - * [[`70d1f32f56`](https://github.com/nodejs/node/commit/70d1f32f56)] - **(SEMVER-MAJOR)** **deps**: update v8 to 4.4.63.9 (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) - * [[`deb7ee93a7`](https://github.com/nodejs/node/commit/deb7ee93a7)] - **deps**: backport 7b24219346 from v8 upstream (Rod Vagg) [#1805](https://github.com/nodejs/node/pull/1805) - * [[`d58e780504`](https://github.com/nodejs/node/commit/d58e780504)] - **(SEMVER-MAJOR)** **deps**: update v8 to 4.3.61.21 (Chris Dickinson) [iojs/io.js#1632](https://github.com/iojs/io.js/pull/1632) - * [[`2a63cf612b`](https://github.com/nodejs/node/commit/2a63cf612b)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`bf63266460`](https://github.com/nodejs/node/commit/bf63266460)] - **deps**: upgrade to npm 2.13.3 (Kat Marchán) [#2284](https://github.com/nodejs/node/pull/2284) - * [[`ef2c8cd4ec`](https://github.com/nodejs/node/commit/ef2c8cd4ec)] - **(SEMVER-MAJOR)** **dgram**: make send cb act as "error" event handler (Matteo Collina) [#1796](https://github.com/nodejs/node/pull/1796) - * [[`3da057fef6`](https://github.com/nodejs/node/commit/3da057fef6)] - **(SEMVER-MAJOR)** **dgram**: make send cb act as "error" event handler (Chris Dickinson) [#1796](https://github.com/nodejs/node/pull/1796) - * [[`df1994fe53`](https://github.com/nodejs/node/commit/df1994fe53)] - ***Revert*** "**dns**: remove AI_V4MAPPED hint flag on FreeBSD" (cjihrig) [iojs/io.js#1555](https://github.com/iojs/io.js/pull/1555) - * [[`1721968b22`](https://github.com/nodejs/node/commit/1721968b22)] - **doc**: document repl persistent history changes (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) - * [[`d12df7f159`](https://github.com/nodejs/node/commit/d12df7f159)] - **doc**: update v8 flags in man page (Michaël Zasso) [iojs/io.js#1701](https://github.com/iojs/io.js/pull/1701) - * [[`d168d01b04`](https://github.com/nodejs/node/commit/d168d01b04)] - **doc**: properly inheriting from EventEmitter (Sakthipriyan Vairamani) [#2168](https://github.com/nodejs/node/pull/2168) - * [[`500f2538cc`](https://github.com/nodejs/node/commit/500f2538cc)] - **doc**: a listener, not "an" listener (Sam Roberts) [#1025](https://github.com/nodejs/node/pull/1025) - * [[`54627a919d`](https://github.com/nodejs/node/commit/54627a919d)] - **doc**: server close event does not have an argument (Sam Roberts) [#1025](https://github.com/nodejs/node/pull/1025) - * [[`ed85c95a9c`](https://github.com/nodejs/node/commit/ed85c95a9c)] - **doc,test**: documents behaviour of non-existent file (Sakthipriyan Vairamani) [#2169](https://github.com/nodejs/node/pull/2169) - * [[`2965442308`](https://github.com/nodejs/node/commit/2965442308)] - **(SEMVER-MAJOR)** **http**: fix agent.getName() and add tests (Brendan Ashworth) [#1617](https://github.com/nodejs/node/pull/1617) - * [[`2d9456e3e6`](https://github.com/nodejs/node/commit/2d9456e3e6)] - **(SEMVER-MAJOR)** **http**: use official IANA Status Codes (jomo) [#1470](https://github.com/nodejs/node/pull/1470) - * [[`11e4249227`](https://github.com/nodejs/node/commit/11e4249227)] - **(SEMVER-MAJOR)** **http_server**: `prefinish` vs `finish` (Fedor Indutny) [#1411](https://github.com/nodejs/node/pull/1411) - * [[`9bc2e26720`](https://github.com/nodejs/node/commit/9bc2e26720)] - **net**: do not set V4MAPPED on FreeBSD (Julien Gilli) [iojs/io.js#1555](https://github.com/iojs/io.js/pull/1555) - * [[`ba9ccf227e`](https://github.com/nodejs/node/commit/ba9ccf227e)] - **node**: remove redundant --use-old-buffer (Rod Vagg) [#2275](https://github.com/nodejs/node/pull/2275) - * [[`ef65321083`](https://github.com/nodejs/node/commit/ef65321083)] - **(SEMVER-MAJOR)** **node**: do not override `message`/`stack` of error (Fedor Indutny) [#2108](https://github.com/nodejs/node/pull/2108) - * [[`9f727f5e03`](https://github.com/nodejs/node/commit/9f727f5e03)] - **node-gyp**: detect RC build with x.y.z-rc.n format (Rod Vagg) [#2171](https://github.com/nodejs/node/pull/2171) - * [[`e52f963632`](https://github.com/nodejs/node/commit/e52f963632)] - **node-gyp**: download header tarball for compile (Rod Vagg) [#2066](https://github.com/nodejs/node/pull/2066) - * [[`902c9ca51d`](https://github.com/nodejs/node/commit/902c9ca51d)] - **node-gyp**: make aware of nightly, next-nightly & rc (Rod Vagg) [#2066](https://github.com/nodejs/node/pull/2066) - * [[`4cffaa3f55`](https://github.com/nodejs/node/commit/4cffaa3f55)] - **(SEMVER-MINOR)** **readline**: allow tabs in input (Rich Trott) [#1761](https://github.com/nodejs/node/pull/1761) - * [[`ed6c249104`](https://github.com/nodejs/node/commit/ed6c249104)] - **(SEMVER-MAJOR)** **repl**: persist history in plain text (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) - * [[`f7d5e4c618`](https://github.com/nodejs/node/commit/f7d5e4c618)] - **(SEMVER-MINOR)** **repl**: default persistence to ~/.node_repl_history (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) - * [[`ea05e760cd`](https://github.com/nodejs/node/commit/ea05e760cd)] - **repl**: don't clobber RegExp.$ properties (Sakthipriyan Vairamani) [#2137](https://github.com/nodejs/node/pull/2137) - * [[`d20093246b`](https://github.com/nodejs/node/commit/d20093246b)] - **src**: disable vector ICs on arm (Michaël Zasso) [#2220](https://github.com/nodejs/node/pull/2220) - * [[`04fd4fad46`](https://github.com/nodejs/node/commit/04fd4fad46)] - **(SEMVER-MINOR)** **src**: introduce process.release object (Rod Vagg) [#2154](https://github.com/nodejs/node/pull/2154) - * [[`9d34bd1147`](https://github.com/nodejs/node/commit/9d34bd1147)] - **src**: increment NODE_MODULE_VERSION to 45 (Rod Vagg) [#2096](https://github.com/nodejs/node/pull/2096) - * [[`ceee8d2807`](https://github.com/nodejs/node/commit/ceee8d2807)] - **test**: add tests for persistent repl history (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) - * [[`8e1a8ffe24`](https://github.com/nodejs/node/commit/8e1a8ffe24)] - **test**: remove two obsolete pummel tests (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) - * [[`ae731ec0fa`](https://github.com/nodejs/node/commit/ae731ec0fa)] - **test**: don't use arguments.callee (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) - * [[`21d31c08e7`](https://github.com/nodejs/node/commit/21d31c08e7)] - **test**: remove obsolete harmony flags (Chris Dickinson) - * [[`64cf71195c`](https://github.com/nodejs/node/commit/64cf71195c)] - **test**: change the hostname to an invalid name (Sakthipriyan Vairamani) [#2287](https://github.com/nodejs/node/pull/2287) - * [[`80a1cf7425`](https://github.com/nodejs/node/commit/80a1cf7425)] - **test**: fix messages and use return to skip tests (Sakthipriyan Vairamani) [#2290](https://github.com/nodejs/node/pull/2290) - * [[`d5ab92bcc1`](https://github.com/nodejs/node/commit/d5ab92bcc1)] - **test**: use common.isWindows consistently (Sakthipriyan Vairamani) [#2269](https://github.com/nodejs/node/pull/2269) - * [[`bc733f7065`](https://github.com/nodejs/node/commit/bc733f7065)] - **test**: fix fs.readFile('/dev/stdin') tests (Ben Noordhuis) [#2265](https://github.com/nodejs/node/pull/2265) - * [[`3cbb5870e5`](https://github.com/nodejs/node/commit/3cbb5870e5)] - **tools**: expose skip output to test runner (Johan Bergström) [#2130](https://github.com/nodejs/node/pull/2130) - * [[`3b021efe11`](https://github.com/nodejs/node/commit/3b021efe11)] - **vm**: fix symbol access (Domenic Denicola) [#1773](https://github.com/nodejs/node/pull/1773) - * [[`7b81e4ba36`](https://github.com/nodejs/node/commit/7b81e4ba36)] - **vm**: remove unnecessary access checks (Domenic Denicola) [#1773](https://github.com/nodejs/node/pull/1773) - * [[`659dadd410`](https://github.com/nodejs/node/commit/659dadd410)] - **vm**: fix property descriptors of sandbox properties (Domenic Denicola) [#1773](https://github.com/nodejs/node/pull/1773) - * [[`9bac1dbae9`](https://github.com/nodejs/node/commit/9bac1dbae9)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - - - ## 2015-07-28, Version 2.5.0, @cjihrig - - ### Notable changes - - * **https**: TLS sessions in Agent are reused (Fedor Indutny) [#2228](https://github.com/nodejs/node/pull/2228) - * **src**: base64 decoding is now 50% faster (Ben Noordhuis) [#2193](https://github.com/nodejs/node/pull/2193) - * **npm**: Upgraded to v2.13.2, release notes can be found in (Kat Marchán) [#2241](https://github.com/nodejs/node/pull/2241). - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Using multiple REPL instances in parallel may cause some REPL history corruption or loss. [#1634](https://github.com/nodejs/node/issues/1634) - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`bf2cd225a8`](https://github.com/nodejs/node/commit/bf2cd225a8)] - **process**: resize stderr on SIGWINCH (Jeremiah Senkpiel) [#2231](https://github.com/nodejs/node/pull/2231) - * [[`99d9d7e716`](https://github.com/nodejs/node/commit/99d9d7e716)] - **benchmark**: add remaining path benchmarks & optimize (Nathan Woltman) [#2103](https://github.com/nodejs/node/pull/2103) - * [[`66fc8ca22b`](https://github.com/nodejs/node/commit/66fc8ca22b)] - **(SEMVER-MINOR)** **cluster**: emit 'message' event on cluster master (Sam Roberts) [#861](https://github.com/nodejs/node/pull/861) - * [[`eb35968de7`](https://github.com/nodejs/node/commit/eb35968de7)] - **crypto**: fix legacy SNICallback (Fedor Indutny) [#1720](https://github.com/nodejs/node/pull/1720) - * [[`fef190cea6`](https://github.com/nodejs/node/commit/fef190cea6)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`b73a7465c5`](https://github.com/nodejs/node/commit/b73a7465c5)] - **deps**: upgrade to npm 2.13.2 (Kat Marchán) [#2241](https://github.com/nodejs/node/pull/2241) - * [[`0a7bf81d2f`](https://github.com/nodejs/node/commit/0a7bf81d2f)] - **deps**: update V8 to 4.2.77.21 (Ali Ijaz Sheikh) [#2238](https://github.com/nodejs/node/issues/2238) - * [[`73cdcdd581`](https://github.com/nodejs/node/commit/73cdcdd581)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`04893a736d`](https://github.com/nodejs/node/commit/04893a736d)] - **deps**: upgrade to npm 2.13.1 (Kat Marchán) [#2210](https://github.com/nodejs/node/pull/2210) - * [[`a3c1b9720e`](https://github.com/nodejs/node/commit/a3c1b9720e)] - **doc**: add GPG fingerprint for cjihrig (cjihrig) [#2217](https://github.com/nodejs/node/pull/2217) - * [[`d9f857df3b`](https://github.com/nodejs/node/commit/d9f857df3b)] - **doc**: note about custom inspect functions (Sakthipriyan Vairamani) [#2142](https://github.com/nodejs/node/pull/2142) - * [[`4ef2b5fbfb`](https://github.com/nodejs/node/commit/4ef2b5fbfb)] - **doc**: Replace util.debug with console.error (Yosuke Furukawa) [#2214](https://github.com/nodejs/node/pull/2214) - * [[`b612f085ec`](https://github.com/nodejs/node/commit/b612f085ec)] - **doc**: add joaocgreis as a collaborator (João Reis) [#2208](https://github.com/nodejs/node/pull/2208) - * [[`6b85d5a4b3`](https://github.com/nodejs/node/commit/6b85d5a4b3)] - **doc**: add TSC meeting minutes 2015-07-15 (Rod Vagg) [#2191](https://github.com/nodejs/node/pull/2191) - * [[`c7d8b09162`](https://github.com/nodejs/node/commit/c7d8b09162)] - **doc**: recompile before testing core module changes (Phillip Johnsen) [#2051](https://github.com/nodejs/node/pull/2051) - * [[`9afee6785e`](https://github.com/nodejs/node/commit/9afee6785e)] - **http**: Check this.connection before using it (Sakthipriyan Vairamani) [#2172](https://github.com/nodejs/node/pull/2172) - * [[`2ca5a3db47`](https://github.com/nodejs/node/commit/2ca5a3db47)] - **https**: reuse TLS sessions in Agent (Fedor Indutny) [#2228](https://github.com/nodejs/node/pull/2228) - * [[`fef87fee1d`](https://github.com/nodejs/node/commit/fef87fee1d)] - **(SEMVER-MINOR)** **lib,test**: add freelist deprecation and test (Sakthipriyan Vairamani) [#2176](https://github.com/nodejs/node/pull/2176) - * [[`503b089dd8`](https://github.com/nodejs/node/commit/503b089dd8)] - **net**: don't throw on immediately destroyed socket (Evan Lucas) [#2251](https://github.com/nodejs/node/pull/2251) - * [[`93660c8b8e`](https://github.com/nodejs/node/commit/93660c8b8e)] - **node**: remove bad fn call and check (Trevor Norris) [#2157](https://github.com/nodejs/node/pull/2157) - * [[`afd7e37ee0`](https://github.com/nodejs/node/commit/afd7e37ee0)] - **repl**: better empty line handling (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) - * [[`81ea52aa01`](https://github.com/nodejs/node/commit/81ea52aa01)] - **repl**: improving line continuation handling (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) - * [[`30edb5aee9`](https://github.com/nodejs/node/commit/30edb5aee9)] - **repl**: preventing REPL crash with inherited properties (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) - * [[`77fa385e5d`](https://github.com/nodejs/node/commit/77fa385e5d)] - **repl**: fixing `undefined` in invalid REPL keyword error (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) - * [[`8fd3ce100e`](https://github.com/nodejs/node/commit/8fd3ce100e)] - **src**: make base64 decoding 50% faster (Ben Noordhuis) [#2193](https://github.com/nodejs/node/pull/2193) - * [[`c786d6341d`](https://github.com/nodejs/node/commit/c786d6341d)] - **test**: do not use public IPs for timeout testing (Rich Trott) [#2057](https://github.com/nodejs/node/pull/2057) - * [[`4e78cd71c0`](https://github.com/nodejs/node/commit/4e78cd71c0)] - **test**: skip IPv6 part before testing it (Sakthipriyan Vairamani) [#2226](https://github.com/nodejs/node/pull/2226) - * [[`ac70bc8240`](https://github.com/nodejs/node/commit/ac70bc8240)] - **test**: fix valgrind uninitialized memory warning (Ben Noordhuis) [#2193](https://github.com/nodejs/node/pull/2193) - * [[`ac7d3fa0d9`](https://github.com/nodejs/node/commit/ac7d3fa0d9)] - **test**: add -no_rand_screen to s_client opts on Win (Shigeki Ohtsu) [#2209](https://github.com/nodejs/node/pull/2209) - * [[`79c865a53f`](https://github.com/nodejs/node/commit/79c865a53f)] - **test**: changing process.exit to return while skipping tests (Sakthipriyan Vairamani) [#2109](https://github.com/nodejs/node/pull/2109) - * [[`69298d36cf`](https://github.com/nodejs/node/commit/69298d36cf)] - **test**: formatting skip messages for TAP parsing (Sakthipriyan Vairamani) [#2109](https://github.com/nodejs/node/pull/2109) - * [[`543dabb609`](https://github.com/nodejs/node/commit/543dabb609)] - **timers**: improve Timer.now() performance (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) - * [[`3663b124e6`](https://github.com/nodejs/node/commit/3663b124e6)] - **timers**: remove unused Timer.again() (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) - * [[`bcce5cf9bb`](https://github.com/nodejs/node/commit/bcce5cf9bb)] - **timers**: remove unused Timer.getRepeat() (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) - * [[`f2c83bd202`](https://github.com/nodejs/node/commit/f2c83bd202)] - **timers**: remove unused Timer.setRepeat() (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) - * [[`e11fc67225`](https://github.com/nodejs/node/commit/e11fc67225)] - **(SEMVER-MINOR)** **tls**: add `getTicketKeys()`/`setTicketKeys()` (Fedor Indutny) [#2227](https://github.com/nodejs/node/pull/2227) - * [[`68b06e94e3`](https://github.com/nodejs/node/commit/68b06e94e3)] - **tools**: use local or specified $NODE for test-npm (Jeremiah Senkpiel) [#1984](https://github.com/nodejs/node/pull/1984) - * [[`ab479659c7`](https://github.com/nodejs/node/commit/ab479659c7)] - **util**: delay creation of debug context (Ali Ijaz Sheikh) [#2248](https://github.com/nodejs/node/pull/2248) - * [[`6391f4d2fd`](https://github.com/nodejs/node/commit/6391f4d2fd)] - **util**: removing redundant checks in is* functions (Sakthipriyan Vairamani) [#2179](https://github.com/nodejs/node/pull/2179) - * [[`b148c0dff3`](https://github.com/nodejs/node/commit/b148c0dff3)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - * [[`f90f1e75bb`](https://github.com/nodejs/node/commit/f90f1e75bb)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - - - ## 2015-07-17, Version 2.4.0, @Fishrock123 - - ### Notable changes - - * **src**: Added a new `--track-heap-objects` flag to track heap object allocations for heap snapshots (Bradley Meck) [#2135](https://github.com/nodejs/node/pull/2135). - * **readline**: Fixed a freeze that affected the repl if the keypress event handler threw (Alex Kocharin) [#2107](https://github.com/nodejs/node/pull/2107). - * **npm**: Upgraded to v2.13.0, release notes can be found in (Forrest L Norvell) [#2152](https://github.com/nodejs/node/pull/2152). - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`f95f9ef6ea`](https://github.com/nodejs/node/commit/f95f9ef6ea)] - **build**: always use prefix=/ for tar-headers (Rod Vagg) [#2082](https://github.com/nodejs/node/pull/2082) - * [[`12bc397207`](https://github.com/nodejs/node/commit/12bc397207)] - **build**: run-ci makefile rule (Alexis Campailla) [#2134](https://github.com/nodejs/node/pull/2134) - * [[`84012c99e0`](https://github.com/nodejs/node/commit/84012c99e0)] - **build**: fix vcbuild merge issues (Alexis Campailla) [#2131](https://github.com/nodejs/node/pull/2131) - * [[`47e2c5c828`](https://github.com/nodejs/node/commit/47e2c5c828)] - **build**: bail early if clean is invoked (Johan Bergström) [#2127](https://github.com/nodejs/node/pull/2127) - * [[`5acad6b163`](https://github.com/nodejs/node/commit/5acad6b163)] - **child_process**: fix arguments comments (Roman Reiss) [#2161](https://github.com/nodejs/node/pull/2161) - * [[`3c4121c418`](https://github.com/nodejs/node/commit/3c4121c418)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`938cc757bb`](https://github.com/nodejs/node/commit/938cc757bb)] - **deps**: upgrade to npm 2.13.0 (Forrest L Norvell) [#2152](https://github.com/nodejs/node/pull/2152) - * [[`6f306e0ed2`](https://github.com/nodejs/node/commit/6f306e0ed2)] - **doc**: add targos as a collaborator (Michaël Zasso) [#2200](https://github.com/nodejs/node/pull/2200) - * [[`c019d9a239`](https://github.com/nodejs/node/commit/c019d9a239)] - **doc**: add thefourtheye as a collaborator (Sakthipriyan Vairamani) [#2199](https://github.com/nodejs/node/pull/2199) - * [[`4e92dbc26b`](https://github.com/nodejs/node/commit/4e92dbc26b)] - **doc**: add TSC members from the combined project (Jeremiah Senkpiel) [#2085](https://github.com/nodejs/node/pull/2085) - * [[`6c3aabf455`](https://github.com/nodejs/node/commit/6c3aabf455)] - **doc**: add TSC meeting minutes 2015-07-08 (Rod Vagg) [#2184](https://github.com/nodejs/node/pull/2184) - * [[`30a0d47d51`](https://github.com/nodejs/node/commit/30a0d47d51)] - **doc**: add TSC meeting minutes 2015-07-01 (Rod Vagg) [#2132](https://github.com/nodejs/node/pull/2132) - * [[`23efb05cc3`](https://github.com/nodejs/node/commit/23efb05cc3)] - **doc**: document fs.watchFile behaviour on ENOENT (Brendan Ashworth) [#2093](https://github.com/nodejs/node/pull/2093) - * [[`65963ec26f`](https://github.com/nodejs/node/commit/65963ec26f)] - **doc,test**: empty strings in path module (Sakthipriyan Vairamani) [#2106](https://github.com/nodejs/node/pull/2106) - * [[`0ab81e6f58`](https://github.com/nodejs/node/commit/0ab81e6f58)] - **docs**: link to more up-to-date v8 docs (Jeremiah Senkpiel) [#2196](https://github.com/nodejs/node/pull/2196) - * [[`1afc0c9e86`](https://github.com/nodejs/node/commit/1afc0c9e86)] - **fs**: fix error on bad listener type (Brendan Ashworth) [#2093](https://github.com/nodejs/node/pull/2093) - * [[`2ba84606a6`](https://github.com/nodejs/node/commit/2ba84606a6)] - **path**: assert path.join() arguments equally (Phillip Johnsen) [#2159](https://github.com/nodejs/node/pull/2159) - * [[`bd01603201`](https://github.com/nodejs/node/commit/bd01603201)] - **readline**: fix freeze if `keypress` event throws (Alex Kocharin) [#2107](https://github.com/nodejs/node/pull/2107) - * [[`59f6b5da2a`](https://github.com/nodejs/node/commit/59f6b5da2a)] - **repl**: Prevent crash when tab-completed with Proxy (Sakthipriyan Vairamani) [#2120](https://github.com/nodejs/node/pull/2120) - * [[`cf14a2427c`](https://github.com/nodejs/node/commit/cf14a2427c)] - **(SEMVER-MINOR)** **src**: add --track-heap-objects (Bradley Meck) [#2135](https://github.com/nodejs/node/pull/2135) - * [[`2b4b600660`](https://github.com/nodejs/node/commit/2b4b600660)] - **test**: fix test-debug-port-from-cmdline (João Reis) [#2186](https://github.com/nodejs/node/pull/2186) - * [[`d4ceb16da2`](https://github.com/nodejs/node/commit/d4ceb16da2)] - **test**: properly clean up temp directory (Roman Reiss) [#2164](https://github.com/nodejs/node/pull/2164) - * [[`842eb5b853`](https://github.com/nodejs/node/commit/842eb5b853)] - **test**: add test for dgram.setTTL (Evan Lucas) [#2121](https://github.com/nodejs/node/pull/2121) - * [[`cff7300a57`](https://github.com/nodejs/node/commit/cff7300a57)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - - - - ## 2015-07-09, Version 2.3.4, @Fishrock123 - - ### Notable changes - - * **openssl**: Upgrade to 1.0.2d, fixes CVE-2015-1793 (Alternate Chains Certificate Forgery) (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141). - * **npm**: Upgraded to v2.12.1, release notes can be found in and (Kat Marchán) [#2112](https://github.com/nodejs/node/pull/2112). - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`0d15161c24`](https://github.com/nodejs/node/commit/0d15161c24)] - **benchmark**: Add some path benchmarks for #1778 (Nathan Woltman) [#1778](https://github.com/nodejs/node/pull/1778) - * [[`c70e68fa32`](https://github.com/nodejs/node/commit/c70e68fa32)] - **deps**: update deps/openssl/conf/arch/*/opensslconf.h (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) - * [[`ca93f7f2e6`](https://github.com/nodejs/node/commit/ca93f7f2e6)] - **deps**: upgrade openssl sources to 1.0.2d (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) - * [[`b18c841ec1`](https://github.com/nodejs/node/commit/b18c841ec1)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`863cdbdd08`](https://github.com/nodejs/node/commit/863cdbdd08)] - **deps**: upgrade to npm 2.12.1 (Kat Marchán) [#2112](https://github.com/nodejs/node/pull/2112) - * [[`84b3915764`](https://github.com/nodejs/node/commit/84b3915764)] - **doc**: document current release procedure (Rod Vagg) [#2099](https://github.com/nodejs/node/pull/2099) - * [[`46140334cd`](https://github.com/nodejs/node/commit/46140334cd)] - **doc**: update AUTHORS list (Rod Vagg) [#2100](https://github.com/nodejs/node/pull/2100) - * [[`bca53dce76`](https://github.com/nodejs/node/commit/bca53dce76)] - **path**: refactor for performance and consistency (Nathan Woltman) [#1778](https://github.com/nodejs/node/pull/1778) - * [[`6bef15afe7`](https://github.com/nodejs/node/commit/6bef15afe7)] - **src**: remove traceSyncIO property from process (Bradley Meck) [#2143](https://github.com/nodejs/node/pull/2143) - * [[`2ba1740ba1`](https://github.com/nodejs/node/commit/2ba1740ba1)] - **test**: add missing crypto checks (Johan Bergström) [#2129](https://github.com/nodejs/node/pull/2129) - * [[`180fd392ca`](https://github.com/nodejs/node/commit/180fd392ca)] - **test**: refactor test-repl-tab-complete (Sakthipriyan Vairamani) [#2122](https://github.com/nodejs/node/pull/2122) - * [[`fb05c8e27d`](https://github.com/nodejs/node/commit/fb05c8e27d)] - ***Revert*** "**test**: add test for missing `close`/`finish` event" (Fedor Indutny) - * [[`9436a860cb`](https://github.com/nodejs/node/commit/9436a860cb)] - **test**: add test for missing `close`/`finish` event (Mark Plomer) [iojs/io.js#1373](https://github.com/iojs/io.js/pull/1373) - * [[`ee3ce2ed88`](https://github.com/nodejs/node/commit/ee3ce2ed88)] - **tools**: install gdbinit from v8 to $PREFIX/share (Ali Ijaz Sheikh) [#2123](https://github.com/nodejs/node/pull/2123) - * [[`dd523c75da`](https://github.com/nodejs/node/commit/dd523c75da)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - - - - ## 2015-07-09, Version 1.8.4, @Fishrock123 - - **Maintenance release** - - ### Notable changes - - * **openssl**: Upgrade to 1.0.2d, fixes CVE-2015-1793 (Alternate Chains Certificate Forgery) [#2141](https://github.com/nodejs/node/pull/2141). - - ### Known issues - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - * readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) + +## 2015-09-15, io.js Version 3.3.1 @rvagg - ### Commits +### Notable changes + +* **buffer**: Fixed a minor errors that was causing crashes (Michaël Zasso) [#2635](https://github.com/nodejs/node/pull/2635), +* **child_process**: Fix error that was causing crashes (Evan Lucas) [#2727](https://github.com/nodejs/node/pull/2727) +* **crypto**: Replace use of rwlocks, unsafe on Windows XP / 2003 (Ben Noordhuis) [#2723](https://github.com/nodejs/node/pull/2723) +* **libuv**: Upgrade from 1.7.3 to 1.7.4 (Saúl Ibarra Corretgé) [#2817](https://github.com/nodejs/node/pull/2817) +* **node**: Fix faulty `process.release.libUrl` on Windows (Rod Vagg) [#2699](https://github.com/nodejs/node/pull/2699) +* **node-gyp**: Float v3.0.3 which has improved support for Node.js and io.js v0.10 to v4+ (Rod Vagg) [#2700](https://github.com/nodejs/node/pull/2700) +* **npm**: Upgrade to version 2.14.3 from 2.13.3, includes a security update, see https://github.com/npm/npm/releases/tag/v2.14.2 for more details, (Kat Marchán) [#2696](https://github.com/nodejs/node/pull/2696). +* **timers**: Improved timer performance from porting the 0.12 implementation, plus minor fixes (Jeremiah Senkpiel) [#2540](https://github.com/nodejs/node/pull/2540), (Julien Gilli) [nodejs/node-v0.x-archive#8751](https://github.com/nodejs/node-v0.x-archive/pull/8751) [nodejs/node-v0.x-archive#8905](https://github.com/nodejs/node-v0.x-archive/pull/8905) + +### Known issues + +See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. + +* Some uses of computed object shorthand properties are not handled correctly by the current version of V8. e.g. `[{ [prop]: val }]` evaluates to `[{}]`. [#2507](https://github.com/nodejs/node/issues/2507) +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). + +### Commits + +* [[`b73ff52fe6`](https://github.com/nodejs/node/commit/b73ff52fe6)] - **bindings**: close after reading module struct (Fedor Indutny) [#2792](https://github.com/nodejs/node/pull/2792) +* [[`aa1140e59a`](https://github.com/nodejs/node/commit/aa1140e59a)] - **buffer**: SlowBuffer only accept valid numeric values (Michaël Zasso) [#2635](https://github.com/nodejs/node/pull/2635) +* [[`574475d56e`](https://github.com/nodejs/node/commit/574475d56e)] - **build**: clean up the generated tap file (Sakthipriyan Vairamani) [#2837](https://github.com/nodejs/node/pull/2837) +* [[`aa0001271e`](https://github.com/nodejs/node/commit/aa0001271e)] - **build**: remote commands on staging in single session (Rod Vagg) [#2717](https://github.com/nodejs/node/pull/2717) +* [[`1428661095`](https://github.com/nodejs/node/commit/1428661095)] - **build**: fix v8_enable_handle_zapping override (Karl Skomski) [#2731](https://github.com/nodejs/node/pull/2731) +* [[`5a51edd718`](https://github.com/nodejs/node/commit/5a51edd718)] - **build**: add --enable-asan with builtin leakcheck (Karl Skomski) [#2376](https://github.com/nodejs/node/pull/2376) +* [[`618caa5de0`](https://github.com/nodejs/node/commit/618caa5de0)] - **child_process**: use stdio.fd even if it is 0 (Evan Lucas) [#2727](https://github.com/nodejs/node/pull/2727) +* [[`7be4e49cb6`](https://github.com/nodejs/node/commit/7be4e49cb6)] - **child_process**: check execFile and fork args (James M Snell) [#2667](https://github.com/nodejs/node/pull/2667) +* [[`7f5d6e72c6`](https://github.com/nodejs/node/commit/7f5d6e72c6)] - **cluster**: allow shared reused dgram sockets (Fedor Indutny) [#2548](https://github.com/nodejs/node/pull/2548) +* [[`e68c7ec498`](https://github.com/nodejs/node/commit/e68c7ec498)] - **contextify**: ignore getters during initialization (Fedor Indutny) [nodejs/io.js#2091](https://github.com/nodejs/io.js/pull/2091) +* [[`610fa964aa`](https://github.com/nodejs/node/commit/610fa964aa)] - **cpplint**: make it possible to run outside git repo (Ben Noordhuis) [#2710](https://github.com/nodejs/node/pull/2710) +* [[`4237373dd7`](https://github.com/nodejs/node/commit/4237373dd7)] - **crypto**: replace rwlocks with simple mutexes (Ben Noordhuis) [#2723](https://github.com/nodejs/node/pull/2723) +* [[`777eb00306`](https://github.com/nodejs/node/commit/777eb00306)] - **deps**: upgraded to node-gyp@3.0.3 in npm (Kat Marchán) [#2822](https://github.com/nodejs/node/pull/2822) +* [[`b729ad384b`](https://github.com/nodejs/node/commit/b729ad384b)] - **deps**: upgrade to npm 2.14.3 (Kat Marchán) [#2822](https://github.com/nodejs/node/pull/2822) +* [[`b09fde761c`](https://github.com/nodejs/node/commit/b09fde761c)] - **deps**: update libuv to version 1.7.4 (Saúl Ibarra Corretgé) [#2817](https://github.com/nodejs/node/pull/2817) +* [[`4cf225daad`](https://github.com/nodejs/node/commit/4cf225daad)] - **deps**: float node-gyp v3.0.0 (Rod Vagg) [#2700](https://github.com/nodejs/node/pull/2700) +* [[`118f48c0f3`](https://github.com/nodejs/node/commit/118f48c0f3)] - **deps**: create .npmrc during npm tests (Kat Marchán) [#2696](https://github.com/nodejs/node/pull/2696) +* [[`b3fee8e6a6`](https://github.com/nodejs/node/commit/b3fee8e6a6)] - **deps**: upgrade to npm 2.14.2 (Kat Marchán) [#2696](https://github.com/nodejs/node/pull/2696) +* [[`4593539b92`](https://github.com/nodejs/node/commit/4593539b92)] - **deps**: backport 75e43a6 from v8 upstream (saper) [#2636](https://github.com/nodejs/node/pull/2636) +* [[`2d1438cfe0`](https://github.com/nodejs/node/commit/2d1438cfe0)] - **doc**: fix broken link in repl.markdown (Danny Nemer) [#2827](https://github.com/nodejs/node/pull/2827) +* [[`9dd9c85a48`](https://github.com/nodejs/node/commit/9dd9c85a48)] - **doc**: fix typos in README (Ionică Bizău) [#2852](https://github.com/nodejs/node/pull/2852) +* [[`476125d403`](https://github.com/nodejs/node/commit/476125d403)] - **doc**: add tunniclm as a collaborator (Mike Tunnicliffe) [#2826](https://github.com/nodejs/node/pull/2826) +* [[`0603a92d48`](https://github.com/nodejs/node/commit/0603a92d48)] - **doc**: fix two doc errors in stream and process (Jeremiah Senkpiel) [#2549](https://github.com/nodejs/node/pull/2549) +* [[`da2902ddfd`](https://github.com/nodejs/node/commit/da2902ddfd)] - **doc**: use "Calls" over "Executes" for consistency (Minwoo Jung) [#2800](https://github.com/nodejs/node/pull/2800) +* [[`5e93bc4fba`](https://github.com/nodejs/node/commit/5e93bc4fba)] - **doc**: use US English for consistency (Anne-Gaelle Colom) [#2784](https://github.com/nodejs/node/pull/2784) +* [[`3ee7fbcefd`](https://github.com/nodejs/node/commit/3ee7fbcefd)] - **doc**: use 3rd person singular for consistency (Anne-Gaelle Colom) [#2765](https://github.com/nodejs/node/pull/2765) +* [[`4fdccb9eb7`](https://github.com/nodejs/node/commit/4fdccb9eb7)] - **doc**: fix comma splice in Assertion Testing doc (Rich Trott) [#2728](https://github.com/nodejs/node/pull/2728) +* [[`28c2d310d6`](https://github.com/nodejs/node/commit/28c2d310d6)] - **doc**: update AUTHORS list (Rod Vagg) +* [[`324c073fb9`](https://github.com/nodejs/node/commit/324c073fb9)] - **doc**: add TSC meeting minutes 2015-09-02 (Rod Vagg) [#2674](https://github.com/nodejs/node/pull/2674) +* [[`8929445686`](https://github.com/nodejs/node/commit/8929445686)] - **doc**: update url doc to account for escaping (Jeremiah Senkpiel) [#2605](https://github.com/nodejs/node/pull/2605) +* [[`512dad6883`](https://github.com/nodejs/node/commit/512dad6883)] - **doc**: reorder collaborators by their usernames (Johan Bergström) [#2322](https://github.com/nodejs/node/pull/2322) +* [[`8372ea2ca5`](https://github.com/nodejs/node/commit/8372ea2ca5)] - **doc,test**: enable recursive file watching in Windows (Sakthipriyan Vairamani) [#2649](https://github.com/nodejs/node/pull/2649) +* [[`daf6c533cc`](https://github.com/nodejs/node/commit/daf6c533cc)] - **events,lib**: don't require EE#listenerCount() (Jeremiah Senkpiel) [#2661](https://github.com/nodejs/node/pull/2661) +* [[`d8371a801e`](https://github.com/nodejs/node/commit/d8371a801e)] - **http_server**: fix resume after socket close (Fedor Indutny) [#2824](https://github.com/nodejs/node/pull/2824) +* [[`7f7d4fdddd`](https://github.com/nodejs/node/commit/7f7d4fdddd)] - **node-gyp**: float 3.0.1, minor fix for download url (Rod Vagg) [#2737](https://github.com/nodejs/node/pull/2737) +* [[`91cee73294`](https://github.com/nodejs/node/commit/91cee73294)] - **src**: use ZCtxt as a source for v8::Isolates (Roman Klauke) [#2547](https://github.com/nodejs/node/pull/2547) +* [[`ac98e13b95`](https://github.com/nodejs/node/commit/ac98e13b95)] - **src**: s/ia32/x86 for process.release.libUrl for win (Rod Vagg) [#2699](https://github.com/nodejs/node/pull/2699) +* [[`ca6c3223e1`](https://github.com/nodejs/node/commit/ca6c3223e1)] - **src**: use standard conform snprintf on windows (Karl Skomski) [#2404](https://github.com/nodejs/node/pull/2404) +* [[`b028978a53`](https://github.com/nodejs/node/commit/b028978a53)] - **src**: fix buffer overflow for long exception lines (Karl Skomski) [#2404](https://github.com/nodejs/node/pull/2404) +* [[`e73eafd7e7`](https://github.com/nodejs/node/commit/e73eafd7e7)] - **src**: fix memory leak in ExternString (Karl Skomski) [#2402](https://github.com/nodejs/node/pull/2402) +* [[`d370306de1`](https://github.com/nodejs/node/commit/d370306de1)] - **src**: only set v8 flags if argc > 1 (Evan Lucas) [#2646](https://github.com/nodejs/node/pull/2646) +* [[`ed087836af`](https://github.com/nodejs/node/commit/ed087836af)] - **streams**: refactor LazyTransform to internal/ (Brendan Ashworth) [#2566](https://github.com/nodejs/node/pull/2566) +* [[`993c22fe0e`](https://github.com/nodejs/node/commit/993c22fe0e)] - **test**: remove disabled test (Rich Trott) [#2841](https://github.com/nodejs/node/pull/2841) +* [[`1474f29d1f`](https://github.com/nodejs/node/commit/1474f29d1f)] - **test**: split up internet dns tests (Rich Trott) [#2802](https://github.com/nodejs/node/pull/2802) +* [[`601a97622b`](https://github.com/nodejs/node/commit/601a97622b)] - **test**: increase dgram timeout for armv6 (Rich Trott) [#2808](https://github.com/nodejs/node/pull/2808) +* [[`1dad19ba81`](https://github.com/nodejs/node/commit/1dad19ba81)] - **test**: remove valid hostname check in test-dns.js (Rich Trott) [#2785](https://github.com/nodejs/node/pull/2785) +* [[`f3d5891a3f`](https://github.com/nodejs/node/commit/f3d5891a3f)] - **test**: expect error for test_lookup_ipv6_hint on FreeBSD (Rich Trott) [#2724](https://github.com/nodejs/node/pull/2724) +* [[`2ffb21baf1`](https://github.com/nodejs/node/commit/2ffb21baf1)] - **test**: fix use of `common` before required (Rod Vagg) [#2685](https://github.com/nodejs/node/pull/2685) +* [[`b2c5479a14`](https://github.com/nodejs/node/commit/b2c5479a14)] - **test**: refactor to eliminate flaky test (Rich Trott) [#2609](https://github.com/nodejs/node/pull/2609) +* [[`fcfd15f8f9`](https://github.com/nodejs/node/commit/fcfd15f8f9)] - **test**: mark eval_messages as flaky (Alexis Campailla) [#2648](https://github.com/nodejs/node/pull/2648) +* [[`1865cad7ae`](https://github.com/nodejs/node/commit/1865cad7ae)] - **test**: mark test-vm-syntax-error-stderr as flaky (João Reis) [#2662](https://github.com/nodejs/node/pull/2662) +* [[`b0014ecd27`](https://github.com/nodejs/node/commit/b0014ecd27)] - **test**: mark test-repl-persistent-history as flaky (João Reis) [#2659](https://github.com/nodejs/node/pull/2659) +* [[`74ff9bc86c`](https://github.com/nodejs/node/commit/74ff9bc86c)] - **timers**: minor _unrefActive fixes and improvements (Jeremiah Senkpiel) [#2540](https://github.com/nodejs/node/pull/2540) +* [[`5d14a6eca7`](https://github.com/nodejs/node/commit/5d14a6eca7)] - **timers**: don't mutate unref list while iterating it (Julien Gilli) [#2540](https://github.com/nodejs/node/pull/2540) +* [[`6e744c58f2`](https://github.com/nodejs/node/commit/6e744c58f2)] - **timers**: Avoid linear scan in _unrefActive. (Julien Gilli) [#2540](https://github.com/nodejs/node/pull/2540) +* [[`07fbf835ad`](https://github.com/nodejs/node/commit/07fbf835ad)] - **tools**: open `test.tap` file in write-binary mode (Sakthipriyan Vairamani) [#2837](https://github.com/nodejs/node/pull/2837) +* [[`6d9198f7f1`](https://github.com/nodejs/node/commit/6d9198f7f1)] - **tools**: add missing tick processor polyfill (Matt Loring) [#2694](https://github.com/nodejs/node/pull/2694) +* [[`7b16597527`](https://github.com/nodejs/node/commit/7b16597527)] - **tools**: fix flakiness in test-tick-processor (Matt Loring) [#2694](https://github.com/nodejs/node/pull/2694) +* [[`ef83029356`](https://github.com/nodejs/node/commit/ef83029356)] - **tools**: remove hyphen in TAP result (Sakthipriyan Vairamani) [#2718](https://github.com/nodejs/node/pull/2718) +* [[`ac45ef9157`](https://github.com/nodejs/node/commit/ac45ef9157)] - **win,msi**: fix documentation shortcut url (Brian White) [#2781](https://github.com/nodejs/node/pull/2781) + + +## 2015-09-02, Version 3.3.0, @rvagg + +### Notable changes + +* **build**: Add a `--link-module` option to `configure` that can be used to bundle additional JavaScript modules into a built binary (Bradley Meck) [#2497](https://github.com/nodejs/node/pull/2497) +* **docs**: Merge outstanding doc updates from joyent/node (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* **http_parser**: Significant performance improvement by having `http.Server` consume all initial data from its `net.Socket` and parsing directly without having to enter JavaScript. Any `'data'` listeners on the `net.Socket` will result in the data being "unconsumed" into JavaScript, thereby undoing any performance gains. (Fedor Indutny) [#2355](https://github.com/nodejs/node/pull/2355) +* **libuv**: Upgrade to 1.7.3 (from 1.6.1), see [ChangeLog](https://github.com/libuv/libuv/blob/v1.x/ChangeLog) for details (Saúl Ibarra Corretgé) [#2310](https://github.com/nodejs/node/pull/2310) +* **V8**: Upgrade to 4.4.63.30 (from 4.4.63.26) (Michaël Zasso) [#2482](https://github.com/nodejs/node/pull/2482) + +### Known issues + +See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. + +* Some uses of computed object shorthand properties are not handled correctly by the current version of V8. e.g. `[{ [prop]: val }]` evaluates to `[{}]`. [#2507](https://github.com/nodejs/node/issues/2507) +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). + +### Commits + +* [[`1a531b4e44`](https://github.com/nodejs/node/commit/1a531b4e44)] - **(SEMVER-MINOR)** Introduce --link-module to ./configure (Bradley Meck) [#2497](https://github.com/nodejs/node/pull/2497) +* [[`d2f314c190`](https://github.com/nodejs/node/commit/d2f314c190)] - **build**: fix borked chmod call for release uploads (Rod Vagg) [#2645](https://github.com/nodejs/node/pull/2645) +* [[`3172e9c541`](https://github.com/nodejs/node/commit/3172e9c541)] - **build**: set file permissions before uploading (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) +* [[`a860d7fae1`](https://github.com/nodejs/node/commit/a860d7fae1)] - **build**: change staging directory on new server (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) +* [[`50c0baa8d7`](https://github.com/nodejs/node/commit/50c0baa8d7)] - **build**: rename 'doc' directory to 'docs' for upload (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) +* [[`0a0577cf5f`](https://github.com/nodejs/node/commit/0a0577cf5f)] - **build**: fix bad cherry-pick for vcbuild.bat build-release (Rod Vagg) [#2625](https://github.com/nodejs/node/pull/2625) +* [[`34de90194b`](https://github.com/nodejs/node/commit/34de90194b)] - **build**: only define NODE_V8_OPTIONS if not empty (Evan Lucas) [#2532](https://github.com/nodejs/node/pull/2532) +* [[`944174b189`](https://github.com/nodejs/node/commit/944174b189)] - **build**: make ci test addons in test/addons (Ben Noordhuis) [#2428](https://github.com/nodejs/node/pull/2428) +* [[`e955f9a1b0`](https://github.com/nodejs/node/commit/e955f9a1b0)] - **crypto**: Use OPENSSL_cleanse to shred the data. (Сковорода Никита Андреевич) [#2575](https://github.com/nodejs/node/pull/2575) +* [[`395d736b9d`](https://github.com/nodejs/node/commit/395d736b9d)] - **debugger**: use strict equality comparison (Minwoo Jung) [#2558](https://github.com/nodejs/node/pull/2558) +* [[`1d0e5210a8`](https://github.com/nodejs/node/commit/1d0e5210a8)] - **deps**: upgrade libuv to 1.7.3 (Saúl Ibarra Corretgé) [#2310](https://github.com/nodejs/node/pull/2310) +* [[`34ef53364f`](https://github.com/nodejs/node/commit/34ef53364f)] - **deps**: update V8 to 4.4.63.30 (Michaël Zasso) [#2482](https://github.com/nodejs/node/pull/2482) +* [[`23579a5f4a`](https://github.com/nodejs/node/commit/23579a5f4a)] - **doc**: add TSC meeting minutes 2015-08-12 (Rod Vagg) [#2438](https://github.com/nodejs/node/pull/2438) +* [[`0cc59299a4`](https://github.com/nodejs/node/commit/0cc59299a4)] - **doc**: add TSC meeting minutes 2015-08-26 (Rod Vagg) [#2591](https://github.com/nodejs/node/pull/2591) +* [[`6efa96e33a`](https://github.com/nodejs/node/commit/6efa96e33a)] - **doc**: merge CHANGELOG.md with joyent/node ChangeLog (Minqi Pan) [#2536](https://github.com/nodejs/node/pull/2536) +* [[`f75d54607b`](https://github.com/nodejs/node/commit/f75d54607b)] - **doc**: clarify cluster behaviour with no workers (Jeremiah Senkpiel) [#2606](https://github.com/nodejs/node/pull/2606) +* [[`8936302121`](https://github.com/nodejs/node/commit/8936302121)] - **doc**: minor clarification in buffer.markdown (Сковорода Никита Андреевич) [#2574](https://github.com/nodejs/node/pull/2574) +* [[`0db0e53753`](https://github.com/nodejs/node/commit/0db0e53753)] - **doc**: add @jasnell and @sam-github to release team (Rod Vagg) [#2455](https://github.com/nodejs/node/pull/2455) +* [[`c16e100593`](https://github.com/nodejs/node/commit/c16e100593)] - **doc**: reorg release team to separate section (Rod Vagg) [#2455](https://github.com/nodejs/node/pull/2455) +* [[`e3e00143fd`](https://github.com/nodejs/node/commit/e3e00143fd)] - **doc**: fix bad merge on modules.markdown (James M Snell) +* [[`2f62455880`](https://github.com/nodejs/node/commit/2f62455880)] - **doc**: minor additional corrections and improvements (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`3bd08aac4b`](https://github.com/nodejs/node/commit/3bd08aac4b)] - **doc**: minor grammatical update in crypto.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`f707189370`](https://github.com/nodejs/node/commit/f707189370)] - **doc**: minor grammatical update (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`6c98cf0266`](https://github.com/nodejs/node/commit/6c98cf0266)] - **doc**: remove repeated statement in globals.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`48e6ccf8c2`](https://github.com/nodejs/node/commit/48e6ccf8c2)] - **doc**: remove 'dudes' from documentation (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`b5d68f8076`](https://github.com/nodejs/node/commit/b5d68f8076)] - **doc**: update tense in child_process.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`242e3fe3ba`](https://github.com/nodejs/node/commit/242e3fe3ba)] - **doc**: fixed worker.id type (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`ea9ee15c21`](https://github.com/nodejs/node/commit/ea9ee15c21)] - **doc**: port is optional for socket.bind() (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`0ff6657a50`](https://github.com/nodejs/node/commit/0ff6657a50)] - **doc**: fix minor types and grammar in fs docs (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`94d83c04f2`](https://github.com/nodejs/node/commit/94d83c04f2)] - **doc**: update parameter name in net.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`04111ce40f`](https://github.com/nodejs/node/commit/04111ce40f)] - **doc**: small typo in domain.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`c9fdd1bbbf`](https://github.com/nodejs/node/commit/c9fdd1bbbf)] - **doc**: fixed typo in net.markdown (missing comma) (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`27c07b3f8e`](https://github.com/nodejs/node/commit/27c07b3f8e)] - **doc**: update description of fs.exists in fs.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`52018e73d9`](https://github.com/nodejs/node/commit/52018e73d9)] - **doc**: clarification on the 'close' event (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`f6d3b87a25`](https://github.com/nodejs/node/commit/f6d3b87a25)] - **doc**: improve working in stream.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`b5da89431a`](https://github.com/nodejs/node/commit/b5da89431a)] - **doc**: update path.extname documentation (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`1d4ea609db`](https://github.com/nodejs/node/commit/1d4ea609db)] - **doc**: small clarifications to modules.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`c888985591`](https://github.com/nodejs/node/commit/c888985591)] - **doc**: code style cleanups in repl.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`105b493595`](https://github.com/nodejs/node/commit/105b493595)] - **doc**: correct grammar in cluster.markdown (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`51b86ccac7`](https://github.com/nodejs/node/commit/51b86ccac7)] - **doc**: Clarify the module.parent is set once (James M Snell) [#2378](https://github.com/nodejs/node/pull/2378) +* [[`d2ffecba2d`](https://github.com/nodejs/node/commit/d2ffecba2d)] - **doc**: add internal modules notice (Jeremiah Senkpiel) [#2523](https://github.com/nodejs/node/pull/2523) +* [[`b36debd5cb`](https://github.com/nodejs/node/commit/b36debd5cb)] - **env**: introduce `KickNextTick` (Fedor Indutny) [#2355](https://github.com/nodejs/node/pull/2355) +* [[`1bc446863f`](https://github.com/nodejs/node/commit/1bc446863f)] - **http_parser**: consume StreamBase instance (Fedor Indutny) [#2355](https://github.com/nodejs/node/pull/2355) +* [[`ce04b735cc`](https://github.com/nodejs/node/commit/ce04b735cc)] - **src**: only memcmp if length > 0 in Buffer::Compare (Karl Skomski) [#2544](https://github.com/nodejs/node/pull/2544) +* [[`31823e37c7`](https://github.com/nodejs/node/commit/31823e37c7)] - **src**: DRY getsockname/getpeername code (Ben Noordhuis) [#956](https://github.com/nodejs/node/pull/956) +* [[`13fd96dda3`](https://github.com/nodejs/node/commit/13fd96dda3)] - **src**: missing Exception::Error in node_http_parser (Jeremiah Senkpiel) [#2550](https://github.com/nodejs/node/pull/2550) +* [[`42e075ae02`](https://github.com/nodejs/node/commit/42e075ae02)] - **test**: improve performance of stringbytes test (Trevor Norris) [#2544](https://github.com/nodejs/node/pull/2544) +* [[`fc726399fd`](https://github.com/nodejs/node/commit/fc726399fd)] - **test**: unmark test-process-argv-0.js as flaky (Rich Trott) [#2613](https://github.com/nodejs/node/pull/2613) +* [[`7727ba1394`](https://github.com/nodejs/node/commit/7727ba1394)] - **test**: lint and refactor to avoid autocrlf issue (Roman Reiss) [#2494](https://github.com/nodejs/node/pull/2494) +* [[`c56aa829f0`](https://github.com/nodejs/node/commit/c56aa829f0)] - **test**: use tmpDir instead of fixturesDir (Sakthipriyan Vairamani) [#2583](https://github.com/nodejs/node/pull/2583) +* [[`5e65181ea4`](https://github.com/nodejs/node/commit/5e65181ea4)] - **test**: handling failure cases properly (Sakthipriyan Vairamani) [#2206](https://github.com/nodejs/node/pull/2206) +* [[`c48b95e847`](https://github.com/nodejs/node/commit/c48b95e847)] - **test**: initial list of flaky tests (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) +* [[`94e88498ba`](https://github.com/nodejs/node/commit/94e88498ba)] - **test**: pass args to test-ci via env variable (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) +* [[`09987c7a1c`](https://github.com/nodejs/node/commit/09987c7a1c)] - **test**: support flaky tests in test-ci (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) +* [[`08b83c8b45`](https://github.com/nodejs/node/commit/08b83c8b45)] - **test**: add test configuration templates (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) +* [[`8f8ab6fa57`](https://github.com/nodejs/node/commit/8f8ab6fa57)] - **test**: runner should return 0 on flaky tests (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) +* [[`0cfd3be9c6`](https://github.com/nodejs/node/commit/0cfd3be9c6)] - **test**: runner support for flaky tests (Alexis Campailla) [#2424](https://github.com/nodejs/node/pull/2424) +* [[`3492d2d4c6`](https://github.com/nodejs/node/commit/3492d2d4c6)] - **test**: make test-process-argv-0 robust (Rich Trott) [#2541](https://github.com/nodejs/node/pull/2541) +* [[`a96cc31710`](https://github.com/nodejs/node/commit/a96cc31710)] - **test**: speed up test-child-process-spawnsync.js (Rich Trott) [#2542](https://github.com/nodejs/node/pull/2542) +* [[`856baf4c67`](https://github.com/nodejs/node/commit/856baf4c67)] - **test**: make spawnSync() test robust (Rich Trott) [#2535](https://github.com/nodejs/node/pull/2535) +* [[`3aa6bbb648`](https://github.com/nodejs/node/commit/3aa6bbb648)] - **tools**: update release.sh to work with new website (Rod Vagg) [#2623](https://github.com/nodejs/node/pull/2623) +* [[`f2f0fe45ff`](https://github.com/nodejs/node/commit/f2f0fe45ff)] - **tools**: make add-on scraper print filenames (Ben Noordhuis) [#2428](https://github.com/nodejs/node/pull/2428) +* [[`bb24c4a418`](https://github.com/nodejs/node/commit/bb24c4a418)] - **win,msi**: correct installation path registry keys (João Reis) [#2565](https://github.com/nodejs/node/pull/2565) +* [[`752977b888`](https://github.com/nodejs/node/commit/752977b888)] - **win,msi**: change InstallScope to perMachine (João Reis) [#2565](https://github.com/nodejs/node/pull/2565) + + +## 2015-08-25, Version 3.2.0, @rvagg + +### Notable changes + +* **events**: Added `EventEmitter#listenerCount(event)` as a replacement for `EventEmitter.listenerCount(emitter, event)`, which has now been marked as deprecated in the docs. (Sakthipriyan Vairamani) [#2349](https://github.com/nodejs/node/pull/2349) +* **module**: Fixed an error with preloaded modules when the current working directory doesn't exist. (Bradley Meck) [#2353](https://github.com/nodejs/node/pull/2353) +* **node**: Startup time is now about 5% faster when not passing V8 flags. (Evan Lucas) [#2483](https://github.com/nodejs/node/pull/2483) +* **repl**: Tab-completion now works better with arrays. (James M Snell) [#2409](https://github.com/nodejs/node/pull/2409) +* **string_bytes**: Fixed an unaligned write in the handling of UCS2 encoding. (Fedor Indutny) [#2480](https://github.com/nodejs/node/pull/2480) +* **tls**: Added a new `--tls-cipher-list` flag that can be used to override the built-in default cipher list. (James M Snell) [#2412](https://github.com/nodejs/node/pull/2412) _Note: it is suggested you use the built-in cipher list as it has been carefully selected to reflect current security best practices and risk mitigation._ + +### Known issues + +See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. + +* Some uses of computed object shorthand properties are not handled correctly by the current version of V8. e.g. `[{ [prop]: val }]` evaluates to `[{}]`. [#2507](https://github.com/nodejs/node/issues/2507) +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). + +### Commits + +* [[`1cd794f129`](https://github.com/nodejs/node/commit/1cd794f129)] - **buffer**: reapply 07c0667 (Fedor Indutny) [#2487](https://github.com/nodejs/node/pull/2487) +* [[`156781dedd`](https://github.com/nodejs/node/commit/156781dedd)] - **build**: use required platform in android-configure (Evan Lucas) [#2501](https://github.com/nodejs/node/pull/2501) +* [[`77075ec906`](https://github.com/nodejs/node/commit/77075ec906)] - **crypto**: fix mem {de}allocation in ExportChallenge (Karl Skomski) [#2359](https://github.com/nodejs/node/pull/2359) +* [[`cb30414d9e`](https://github.com/nodejs/node/commit/cb30414d9e)] - **doc**: sync CHANGELOG.md from master (Roman Reiss) [#2524](https://github.com/nodejs/node/pull/2524) +* [[`9330f5ef45`](https://github.com/nodejs/node/commit/9330f5ef45)] - **doc**: make the deprecations consistent (Sakthipriyan Vairamani) [#2450](https://github.com/nodejs/node/pull/2450) +* [[`09437e0146`](https://github.com/nodejs/node/commit/09437e0146)] - **doc**: fix comments in tls_wrap.cc and _http_client.js (Minwoo Jung) [#2489](https://github.com/nodejs/node/pull/2489) +* [[`c9867fed29`](https://github.com/nodejs/node/commit/c9867fed29)] - **doc**: document response.finished in http.markdown (hackerjs) [#2414](https://github.com/nodejs/node/pull/2414) +* [[`7f23a83c42`](https://github.com/nodejs/node/commit/7f23a83c42)] - **doc**: update AUTHORS list (Rod Vagg) [#2505](https://github.com/nodejs/node/pull/2505) +* [[`cd0c362f67`](https://github.com/nodejs/node/commit/cd0c362f67)] - **doc**: update AUTHORS list (Rod Vagg) [#2318](https://github.com/nodejs/node/pull/2318) +* [[`2c7b9257ea`](https://github.com/nodejs/node/commit/2c7b9257ea)] - **doc**: add TSC meeting minutes 2015-07-29 (Rod Vagg) [#2437](https://github.com/nodejs/node/pull/2437) +* [[`aaefde793e`](https://github.com/nodejs/node/commit/aaefde793e)] - **doc**: add TSC meeting minutes 2015-08-19 (Rod Vagg) [#2460](https://github.com/nodejs/node/pull/2460) +* [[`51ef9106f5`](https://github.com/nodejs/node/commit/51ef9106f5)] - **doc**: add TSC meeting minutes 2015-06-03 (Rod Vagg) [#2453](https://github.com/nodejs/node/pull/2453) +* [[`7130b4cf1d`](https://github.com/nodejs/node/commit/7130b4cf1d)] - **doc**: fix links to original converged repo (Rod Vagg) [#2454](https://github.com/nodejs/node/pull/2454) +* [[`14f2aee1df`](https://github.com/nodejs/node/commit/14f2aee1df)] - **doc**: fix links to original gh issues for TSC meetings (Rod Vagg) [#2454](https://github.com/nodejs/node/pull/2454) +* [[`87a9ef0a40`](https://github.com/nodejs/node/commit/87a9ef0a40)] - **doc**: add audio recording links to TSC meeting minutes (Rod Vagg) [#2454](https://github.com/nodejs/node/pull/2454) +* [[`f5cf24afbc`](https://github.com/nodejs/node/commit/f5cf24afbc)] - **doc**: add TSC meeting minutes 2015-07-22 (Rod Vagg) [#2436](https://github.com/nodejs/node/pull/2436) +* [[`3f821b96eb`](https://github.com/nodejs/node/commit/3f821b96eb)] - **doc**: fix spelling mistake in node.js comment (Jacob Edelman) [#2391](https://github.com/nodejs/node/pull/2391) +* [[`3e6a6fcdd6`](https://github.com/nodejs/node/commit/3e6a6fcdd6)] - **(SEMVER-MINOR)** **events**: deprecate static listenerCount function (Sakthipriyan Vairamani) [#2349](https://github.com/nodejs/node/pull/2349) +* [[`023386c852`](https://github.com/nodejs/node/commit/023386c852)] - **fs**: replace bad_args macro with concrete error msg (Roman Klauke) [#2495](https://github.com/nodejs/node/pull/2495) +* [[`d1c27b2e29`](https://github.com/nodejs/node/commit/d1c27b2e29)] - **module**: fix module preloading when cwd is ENOENT (Bradley Meck) [#2353](https://github.com/nodejs/node/pull/2353) +* [[`5d7486941b`](https://github.com/nodejs/node/commit/5d7486941b)] - **repl**: filter integer keys from repl tab complete list (James M Snell) [#2409](https://github.com/nodejs/node/pull/2409) +* [[`7f02443a9a`](https://github.com/nodejs/node/commit/7f02443a9a)] - **repl**: dont throw ENOENT on NODE_REPL_HISTORY_FILE (Todd Kennedy) [#2451](https://github.com/nodejs/node/pull/2451) +* [[`56a2ae9cef`](https://github.com/nodejs/node/commit/56a2ae9cef)] - **src**: improve startup time (Evan Lucas) [#2483](https://github.com/nodejs/node/pull/2483) +* [[`14653c7429`](https://github.com/nodejs/node/commit/14653c7429)] - **stream**: rename poorly named function (Ben Noordhuis) [#2479](https://github.com/nodejs/node/pull/2479) +* [[`1c6e014bfa`](https://github.com/nodejs/node/commit/1c6e014bfa)] - **stream**: micro-optimize high water mark calculation (Ben Noordhuis) [#2479](https://github.com/nodejs/node/pull/2479) +* [[`f1f4b4c46d`](https://github.com/nodejs/node/commit/f1f4b4c46d)] - **stream**: fix off-by-factor-16 error in comment (Ben Noordhuis) [#2479](https://github.com/nodejs/node/pull/2479) +* [[`2d3f09bd76`](https://github.com/nodejs/node/commit/2d3f09bd76)] - **stream_base**: various improvements (Fedor Indutny) [#2351](https://github.com/nodejs/node/pull/2351) +* [[`c1ce423b35`](https://github.com/nodejs/node/commit/c1ce423b35)] - **string_bytes**: fix unaligned write in UCS2 (Fedor Indutny) [#2480](https://github.com/nodejs/node/pull/2480) +* [[`e4d0e86165`](https://github.com/nodejs/node/commit/e4d0e86165)] - **test**: refactor test-https-simple.js (Rich Trott) [#2433](https://github.com/nodejs/node/pull/2433) +* [[`0ea5c8d737`](https://github.com/nodejs/node/commit/0ea5c8d737)] - **test**: remove test-timers-first-fire (João Reis) [#2458](https://github.com/nodejs/node/pull/2458) +* [[`536c3d0537`](https://github.com/nodejs/node/commit/536c3d0537)] - **test**: use reserved IP in test-net-connect-timeout (Rich Trott) [#2257](https://github.com/nodejs/node/pull/2257) +* [[`5df06fd8df`](https://github.com/nodejs/node/commit/5df06fd8df)] - **test**: add spaces after keywords (Brendan Ashworth) +* [[`e714b5620e`](https://github.com/nodejs/node/commit/e714b5620e)] - **test**: remove unreachable code (Michaël Zasso) [#2289](https://github.com/nodejs/node/pull/2289) +* [[`3579f3a2a4`](https://github.com/nodejs/node/commit/3579f3a2a4)] - **test**: disallow unreachable code (Michaël Zasso) [#2289](https://github.com/nodejs/node/pull/2289) +* [[`3545e236fc`](https://github.com/nodejs/node/commit/3545e236fc)] - **test**: reduce timeouts in test-net-keepalive (Brendan Ashworth) [#2429](https://github.com/nodejs/node/pull/2429) +* [[`b60e690023`](https://github.com/nodejs/node/commit/b60e690023)] - **test**: improve test-net-server-pause-on-connect (Brendan Ashworth) [#2429](https://github.com/nodejs/node/pull/2429) +* [[`11d1b8fcaf`](https://github.com/nodejs/node/commit/11d1b8fcaf)] - **test**: improve test-net-pingpong (Brendan Ashworth) [#2429](https://github.com/nodejs/node/pull/2429) +* [[`5fef5c6562`](https://github.com/nodejs/node/commit/5fef5c6562)] - **(SEMVER-MINOR)** **tls**: add --tls-cipher-list command line switch (James M Snell) [#2412](https://github.com/nodejs/node/pull/2412) +* [[`d9b70f9cbf`](https://github.com/nodejs/node/commit/d9b70f9cbf)] - **tls**: handle empty cert in checkServerIndentity (Mike Atkins) [#2343](https://github.com/nodejs/node/pull/2343) +* [[`4f8e34c202`](https://github.com/nodejs/node/commit/4f8e34c202)] - **tools**: add license boilerplate to check-imports.sh (James M Snell) [#2386](https://github.com/nodejs/node/pull/2386) +* [[`b76b9197f9`](https://github.com/nodejs/node/commit/b76b9197f9)] - **tools**: enable space-after-keywords in eslint (Brendan Ashworth) +* [[`64a8f30a70`](https://github.com/nodejs/node/commit/64a8f30a70)] - **tools**: fix anchors in generated documents (Sakthipriyan Vairamani) [#2491](https://github.com/nodejs/node/pull/2491) +* [[`22e344ea10`](https://github.com/nodejs/node/commit/22e344ea10)] - **win**: fix custom actions for WiX older than 3.9 (João Reis) [#2365](https://github.com/nodejs/node/pull/2365) +* [[`b5bd3ebfc8`](https://github.com/nodejs/node/commit/b5bd3ebfc8)] - **win**: fix custom actions on Visual Studio != 2013 (Julien Gilli) [#2365](https://github.com/nodejs/node/pull/2365) + + +## 2015-08-18, Version 3.1.0, @Fishrock123 + +### Notable changes + +* **buffer**: Fixed a couple large memory leaks (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352). +* **crypto**: + - Fixed a couple of minor memory leaks (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375). + - Signing now checks for OpenSSL errors (Minqi Pan) [#2342](https://github.com/nodejs/node/pull/2342). **Note that this may expose previously hidden errors in user code.** +* **intl**: Intl support using small-icu is now enabled by default in builds (Steven R. Loomis) [#2264](https://github.com/nodejs/node/pull/2264). + - [`String#normalize()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) can now be used for unicode normalization. + - The [`Intl`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl) object and various `String` and `Number` methods are present, but only support the English locale. + - For support of all locales, node must be built with [full-icu](https://github.com/nodejs/node#build-with-full-icu-support-all-locales-supported-by-icu). +* **tls**: Fixed tls throughput being much lower after an incorrect merge (Fedor Indutny) [#2381](https://github.com/nodejs/node/pull/2381). +* **tools**: The v8 tick processor now comes bundled with node (Matt Loring) [#2090](https://github.com/nodejs/node/pull/2090). + - This can be used by producing performance profiling output by running node with `--perf`, then running your appropriate platform's script on the output as found in [tools/v8-prof](https://github.com/nodejs/node/tree/master/tools/v8-prof). +* **util**: `util.inspect(obj)` now prints the constructor name of the object if there is one (Christopher Monsanto) [#1935](https://github.com/nodejs/io.js/pull/1935). + +### Known issues + +See https://github.com/nodejs/io.js/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/io.js/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/io.js/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/io.js/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/io.js/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/io.js/issues/1435). + +### Commits + +* [[`3645dc62ed`](https://github.com/nodejs/node/commit/3645dc62ed)] - **build**: work around VS2015 issue in ICU <56 (Steven R. Loomis) [#2283](https://github.com/nodejs/node/pull/2283) +* [[`1f12e03266`](https://github.com/nodejs/node/commit/1f12e03266)] - **(SEMVER-MINOR)** **build**: intl: converge from joyent/node (Steven R. Loomis) [#2264](https://github.com/nodejs/node/pull/2264) +* [[`071640abdd`](https://github.com/nodejs/node/commit/071640abdd)] - **build**: Intl: bump ICU4C from 54 to 55 (Steven R. Loomis) [#2293](https://github.com/nodejs/node/pull/2293) +* [[`07a88b0c8b`](https://github.com/nodejs/node/commit/07a88b0c8b)] - **build**: update manifest to include Windows 10 (Lucien Greathouse) [#2332](https://github.com/nodejs/io.js/pull/2332) +* [[`0bb099f444`](https://github.com/nodejs/node/commit/0bb099f444)] - **build**: expand ~ in install prefix early (Ben Noordhuis) [#2307](https://github.com/nodejs/io.js/pull/2307) +* [[`7fe6dd8f5d`](https://github.com/nodejs/node/commit/7fe6dd8f5d)] - **crypto**: check for OpenSSL errors when signing (Minqi Pan) [#2342](https://github.com/nodejs/node/pull/2342) +* [[`605f6ee904`](https://github.com/nodejs/node/commit/605f6ee904)] - **crypto**: fix memory leak in PBKDF2Request (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`ba6eb8af12`](https://github.com/nodejs/node/commit/ba6eb8af12)] - **crypto**: fix memory leak in ECDH::SetPrivateKey (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`6a16368611`](https://github.com/nodejs/node/commit/6a16368611)] - **crypto**: fix memory leak in PublicKeyCipher::Cipher (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`a760a87803`](https://github.com/nodejs/node/commit/a760a87803)] - **crypto**: fix memory leak in SafeX509ExtPrint (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`f45487cd6e`](https://github.com/nodejs/node/commit/f45487cd6e)] - **crypto**: fix memory leak in SetDHParam (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`2ff183dd86`](https://github.com/nodejs/node/commit/2ff183dd86)] - **doc**: Update FIPS instructions in README.md (Michael Dawson) [#2278](https://github.com/nodejs/node/pull/2278) +* [[`6483bc2e8f`](https://github.com/nodejs/node/commit/6483bc2e8f)] - **doc**: clarify options for fs.watchFile() (Rich Trott) [#2425](https://github.com/nodejs/node/pull/2425) +* [[`e76822f454`](https://github.com/nodejs/node/commit/e76822f454)] - **doc**: multiple documentation updates cherry picked from v0.12 (James M Snell) [#2302](https://github.com/nodejs/io.js/pull/2302) +* [[`1738c9680b`](https://github.com/nodejs/node/commit/1738c9680b)] - **net**: ensure Socket reported address is current (Ryan Graham) [#2095](https://github.com/nodejs/io.js/pull/2095) +* [[`844d3f0e3e`](https://github.com/nodejs/node/commit/844d3f0e3e)] - **path**: use '===' instead of '==' for comparison (Sam Stites) [#2388](https://github.com/nodejs/node/pull/2388) +* [[`7118b8a882`](https://github.com/nodejs/node/commit/7118b8a882)] - **path**: remove dead code in favor of unit tests (Nathan Woltman) [#2282](https://github.com/nodejs/io.js/pull/2282) +* [[`34f2cfa806`](https://github.com/nodejs/node/commit/34f2cfa806)] - **src**: better error message on failed Buffer malloc (Karl Skomski) [#2422](https://github.com/nodejs/node/pull/2422) +* [[`b196c1da3c`](https://github.com/nodejs/node/commit/b196c1da3c)] - **src**: fix memory leak in DLOpen (Karl Skomski) [#2375](https://github.com/nodejs/node/pull/2375) +* [[`d1307b2995`](https://github.com/nodejs/node/commit/d1307b2995)] - **src**: don't use fopen() in require() fast path (Ben Noordhuis) [#2377](https://github.com/nodejs/node/pull/2377) +* [[`455ec570d1`](https://github.com/nodejs/node/commit/455ec570d1)] - **src**: rename Buffer::Use() to Buffer::New() (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`fd63e1ce2b`](https://github.com/nodejs/node/commit/fd63e1ce2b)] - **src**: introduce internal Buffer::Copy() function (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`5586ceca13`](https://github.com/nodejs/node/commit/5586ceca13)] - **src**: move internal functions out of node_buffer.h (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`bff9bcddb6`](https://github.com/nodejs/node/commit/bff9bcddb6)] - **src**: plug memory leaks (Ben Noordhuis) [#2352](https://github.com/nodejs/node/pull/2352) +* [[`ccf12df4f3`](https://github.com/nodejs/node/commit/ccf12df4f3)] - **(SEMVER-MINOR)** **src**: add total_available_size to v8 statistics (Roman Klauke) [#2348](https://github.com/nodejs/io.js/pull/2348) +* [[`194eeb841b`](https://github.com/nodejs/node/commit/194eeb841b)] - **test**: drop Isolate::GetCurrent() from addon tests (Ben Noordhuis) [#2427](https://github.com/nodejs/node/pull/2427) +* [[`46cdb2f6e2`](https://github.com/nodejs/node/commit/46cdb2f6e2)] - **test**: lint addon tests (Ben Noordhuis) [#2427](https://github.com/nodejs/node/pull/2427) +* [[`850c794882`](https://github.com/nodejs/node/commit/850c794882)] - **test**: refactor test-fs-watchfile.js (Rich Trott) [#2393](https://github.com/nodejs/node/pull/2393) +* [[`a3160c0a33`](https://github.com/nodejs/node/commit/a3160c0a33)] - **test**: correct spelling of 'childProcess' (muddletoes) [#2389](https://github.com/nodejs/node/pull/2389) +* [[`e51f90d747`](https://github.com/nodejs/node/commit/e51f90d747)] - **test**: option to run a subset of tests (João Reis) [#2260](https://github.com/nodejs/io.js/pull/2260) +* [[`cc46d3bca3`](https://github.com/nodejs/node/commit/cc46d3bca3)] - **test**: clarify dropMembership() call (Rich Trott) [#2062](https://github.com/nodejs/io.js/pull/2062) +* [[`0ee4df9c7a`](https://github.com/nodejs/node/commit/0ee4df9c7a)] - **test**: make listen-fd-cluster/server more robust (Sam Roberts) [#1944](https://github.com/nodejs/io.js/pull/1944) +* [[`cf9ba81398`](https://github.com/nodejs/node/commit/cf9ba81398)] - **test**: address timing issues in simple http tests (Gireesh Punathil) [#2294](https://github.com/nodejs/io.js/pull/2294) +* [[`cbb75c4f86`](https://github.com/nodejs/node/commit/cbb75c4f86)] - **tls**: fix throughput issues after incorrect merge (Fedor Indutny) [#2381](https://github.com/nodejs/node/pull/2381) +* [[`94b765f409`](https://github.com/nodejs/node/commit/94b765f409)] - **tls**: fix check for reused session (Fedor Indutny) [#2312](https://github.com/nodejs/io.js/pull/2312) +* [[`e83a41ad65`](https://github.com/nodejs/node/commit/e83a41ad65)] - **tls**: introduce internal `onticketkeycallback` (Fedor Indutny) [#2312](https://github.com/nodejs/io.js/pull/2312) +* [[`fb0f5d733f`](https://github.com/nodejs/node/commit/fb0f5d733f)] - **(SEMVER-MINOR)** **tools**: run the tick processor without building v8 (Matt Loring) [#2090](https://github.com/nodejs/node/pull/2090) +* [[`7606bdb897`](https://github.com/nodejs/node/commit/7606bdb897)] - **(SEMVER-MINOR)** **util**: display constructor when inspecting objects (Christopher Monsanto) [#1935](https://github.com/nodejs/io.js/pull/1935) + + +## 2015-08-04, Version 3.0.0, @rvagg + +### Notable changes + +* **buffer**: + - Due to changes in V8, it has been necessary to reimplement `Buffer` on top of V8's `Uint8Array`. Every effort has been made to minimize the performance impact, however `Buffer` instantiation is measurably slower. Access operations may be faster in some circumstances but the exact performance profile and difference over previous versions will depend on how `Buffer` is used within applications. (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825). + - `Buffer` can now take `ArrayBuffer`s as a constructor argument (Trevor Norris) [#2002](https://github.com/nodejs/node/pull/2002). + - When a single buffer is passed to `Buffer.concat()`, a new, copied `Buffer` object will be returned; previous behavior was to return the original `Buffer` object (Sakthipriyan Vairamani) [#1937](https://github.com/nodejs/node/pull/1937). +* **build**: PPC support has been added to core to allow compiling on pLinux BE and LE (AIX support coming soon) (Michael Dawson) [#2124](https://github.com/nodejs/node/pull/2124). +* **dgram**: If an error occurs within `socket.send()` and a callback has been provided, the error is only passed as the first argument to the callback and not emitted on the `socket` object; previous behavior was to do both (Matteo Collina & Chris Dickinson) [#1796](https://github.com/nodejs/node/pull/1796) +* **freelist**: Deprecate the undocumented `freelist` core module (Sakthipriyan Vairamani) [#2176](https://github.com/nodejs/node/pull/2176). +* **http**: + - Status codes now all use the official [IANA names](http://www.iana.org/assignments/http-status-codes) as per [RFC7231](https://tools.ietf.org/html/rfc7231), e.g. `http.STATUS_CODES[414]` now returns `'URI Too Long'` rather than `'Request-URI Too Large'` (jomo) [#1470](https://github.com/nodejs/node/pull/1470). + - Calling .getName() on an HTTP agent no longer returns a trailing colon, HTTPS agents will no longer return an extra colon near the middle of the string (Brendan Ashworth) [#1617](https://github.com/nodejs/node/pull/1617). +* **node**: + - `NODE_MODULE_VERSION` has been bumped to `45` to reflect the break in ABI (Rod Vagg) [#2096](https://github.com/nodejs/node/pull/2096). + - Introduce a new `process.release` object that contains a `name` property set to `'io.js'` and `sourceUrl`, `headersUrl` and `libUrl` (Windows only) properties containing URLs for the relevant resources; this is intended to be used by node-gyp (Rod Vagg) [#2154](https://github.com/nodejs/node/pull/2154). + - The version of node-gyp bundled with io.js now downloads and uses a tarball of header files from iojs.org rather than the full source for compiling native add-ons; it is hoped this is a temporary floating patch and the change will be upstreamed to node-gyp soon (Rod Vagg) [#2066](https://github.com/nodejs/node/pull/2066). +* **repl**: Persistent history is now enabled by default. The history file is located at ~/.node_repl_history, which can be overridden by the new environment variable `NODE_REPL_HISTORY`. This deprecates the previous `NODE_REPL_HISTORY_FILE` variable. Additionally, the format of the file has been changed to plain text to better handle file corruption. (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224). +* **smalloc**: The `smalloc` module has been removed as it is no longer possible to provide the API due to changes in V8 (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022). +* **tls**: Add `server.getTicketKeys()` and `server.setTicketKeys()` methods for [TLS session key](https://www.ietf.org/rfc/rfc5077.txt) rotation (Fedor Indutny) [#2227](https://github.com/nodejs/node/pull/2227). +* **v8**: Upgraded to 4.4.63.26 + - ES6: Enabled [computed property names](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names) + - ES6: `Array` can now be subclassed in strict mode + - ES6: Implement [rest parameters](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/rest_parameters) in staging, use the `--harmony-rest-parameters` command line flag + - ES6: Implement the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) in staging, use the `--harmony-spreadcalls` command line flag + - Removed `SetIndexedPropertiesToExternalArrayData` and related APIs, forcing a shift to `Buffer` to be reimplemented based on `Uint8Array` + - Introduction of `Maybe` and `MaybeLocal` C++ API for objects which _may_ or _may not_ have a value. + - Added support for PPC + +See also https://github.com/nodejs/node/wiki/Breaking-Changes#300-from-2x for a summary of the breaking changes (SEMVER-MAJOR). + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`60a974d200`](https://github.com/nodejs/node/commit/60a974d200)] - **buffer**: fix missing null/undefined check (Trevor Norris) [#2195](https://github.com/nodejs/node/pull/2195) +* [[`e6ab2d92bc`](https://github.com/nodejs/node/commit/e6ab2d92bc)] - **buffer**: fix not return on error (Trevor Norris) [#2225](https://github.com/nodejs/node/pull/2225) +* [[`1057d1186b`](https://github.com/nodejs/node/commit/1057d1186b)] - **buffer**: rename internal/buffer_new.js to buffer.js (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) +* [[`4643b8b667`](https://github.com/nodejs/node/commit/4643b8b667)] - **(SEMVER-MINOR)** **buffer**: allow ArrayBuffer as Buffer argument (Trevor Norris) [#2002](https://github.com/nodejs/node/pull/2002) +* [[`e5ada116cd`](https://github.com/nodejs/node/commit/e5ada116cd)] - **buffer**: minor cleanup from rebase (Trevor Norris) [#2003](https://github.com/nodejs/node/pull/2003) +* [[`b625ab4242`](https://github.com/nodejs/node/commit/b625ab4242)] - **buffer**: fix usage of kMaxLength (Trevor Norris) [#2003](https://github.com/nodejs/node/pull/2003) +* [[`eea66e2a7b`](https://github.com/nodejs/node/commit/eea66e2a7b)] - **(SEMVER-MAJOR)** **buffer**: fix case of one buffer passed to concat (Sakthipriyan Vairamani) [#1937](https://github.com/nodejs/node/pull/1937) +* [[`8664084166`](https://github.com/nodejs/node/commit/8664084166)] - **buffer**: make additional changes to native API (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) +* [[`36f78f4c1c`](https://github.com/nodejs/node/commit/36f78f4c1c)] - **buffer**: switch API to return MaybeLocal (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) +* [[`571ec13841`](https://github.com/nodejs/node/commit/571ec13841)] - **buffer**: switch to using Maybe API (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) +* [[`d75f5c8d0e`](https://github.com/nodejs/node/commit/d75f5c8d0e)] - **buffer**: finish implementing FreeCallback (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) +* [[`63da0dfd3a`](https://github.com/nodejs/node/commit/63da0dfd3a)] - **buffer**: implement Uint8Array backed Buffer (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) +* [[`23be6ca189`](https://github.com/nodejs/node/commit/23be6ca189)] - **buffer**: allow ARGS_THIS to accept a name (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) +* [[`971de5e417`](https://github.com/nodejs/node/commit/971de5e417)] - **build**: prepare Windows installer for i18n support (Frederic Hemberger) [#2247](https://github.com/nodejs/node/pull/2247) +* [[`2ba8b23661`](https://github.com/nodejs/node/commit/2ba8b23661)] - **build**: add 'x86' option back in to configure (Rod Vagg) [#2233](https://github.com/nodejs/node/pull/2233) +* [[`b4226e797a`](https://github.com/nodejs/node/commit/b4226e797a)] - **build**: first set of updates to enable PPC support (Michael Dawson) [#2124](https://github.com/nodejs/node/pull/2124) +* [[`24dd016deb`](https://github.com/nodejs/node/commit/24dd016deb)] - **build**: produce symbol map files on windows (Ali Ijaz Sheikh) [#2243](https://github.com/nodejs/node/pull/2243) +* [[`423d8944ce`](https://github.com/nodejs/node/commit/423d8944ce)] - **cluster**: do not unconditionally set --debug-port (cjihrig) [#1949](https://github.com/nodejs/node/pull/1949) +* [[`fa98b97171`](https://github.com/nodejs/node/commit/fa98b97171)] - **cluster**: add handle ref/unref stubs in rr mode (Ben Noordhuis) [#2274](https://github.com/nodejs/node/pull/2274) +* [[`944f68046c`](https://github.com/nodejs/node/commit/944f68046c)] - **crypto**: remove kMaxLength on randomBytes() (Trevor Norris) [#1825](https://github.com/nodejs/node/pull/1825) +* [[`3d3c687012`](https://github.com/nodejs/node/commit/3d3c687012)] - **deps**: update V8 to 4.4.63.26 (Michaël Zasso) [#2220](https://github.com/nodejs/node/pull/2220) +* [[`3aad4fa89a`](https://github.com/nodejs/node/commit/3aad4fa89a)] - **deps**: upgrade v8 to 4.4.63.12 (Ben Noordhuis) [#2092](https://github.com/nodejs/node/pull/2092) +* [[`70d1f32f56`](https://github.com/nodejs/node/commit/70d1f32f56)] - **(SEMVER-MAJOR)** **deps**: update v8 to 4.4.63.9 (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) +* [[`deb7ee93a7`](https://github.com/nodejs/node/commit/deb7ee93a7)] - **deps**: backport 7b24219346 from v8 upstream (Rod Vagg) [#1805](https://github.com/nodejs/node/pull/1805) +* [[`d58e780504`](https://github.com/nodejs/node/commit/d58e780504)] - **(SEMVER-MAJOR)** **deps**: update v8 to 4.3.61.21 (Chris Dickinson) [iojs/io.js#1632](https://github.com/iojs/io.js/pull/1632) +* [[`2a63cf612b`](https://github.com/nodejs/node/commit/2a63cf612b)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`bf63266460`](https://github.com/nodejs/node/commit/bf63266460)] - **deps**: upgrade to npm 2.13.3 (Kat Marchán) [#2284](https://github.com/nodejs/node/pull/2284) +* [[`ef2c8cd4ec`](https://github.com/nodejs/node/commit/ef2c8cd4ec)] - **(SEMVER-MAJOR)** **dgram**: make send cb act as "error" event handler (Matteo Collina) [#1796](https://github.com/nodejs/node/pull/1796) +* [[`3da057fef6`](https://github.com/nodejs/node/commit/3da057fef6)] - **(SEMVER-MAJOR)** **dgram**: make send cb act as "error" event handler (Chris Dickinson) [#1796](https://github.com/nodejs/node/pull/1796) +* [[`df1994fe53`](https://github.com/nodejs/node/commit/df1994fe53)] - ***Revert*** "**dns**: remove AI_V4MAPPED hint flag on FreeBSD" (cjihrig) [iojs/io.js#1555](https://github.com/iojs/io.js/pull/1555) +* [[`1721968b22`](https://github.com/nodejs/node/commit/1721968b22)] - **doc**: document repl persistent history changes (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) +* [[`d12df7f159`](https://github.com/nodejs/node/commit/d12df7f159)] - **doc**: update v8 flags in man page (Michaël Zasso) [iojs/io.js#1701](https://github.com/iojs/io.js/pull/1701) +* [[`d168d01b04`](https://github.com/nodejs/node/commit/d168d01b04)] - **doc**: properly inheriting from EventEmitter (Sakthipriyan Vairamani) [#2168](https://github.com/nodejs/node/pull/2168) +* [[`500f2538cc`](https://github.com/nodejs/node/commit/500f2538cc)] - **doc**: a listener, not "an" listener (Sam Roberts) [#1025](https://github.com/nodejs/node/pull/1025) +* [[`54627a919d`](https://github.com/nodejs/node/commit/54627a919d)] - **doc**: server close event does not have an argument (Sam Roberts) [#1025](https://github.com/nodejs/node/pull/1025) +* [[`ed85c95a9c`](https://github.com/nodejs/node/commit/ed85c95a9c)] - **doc,test**: documents behaviour of non-existent file (Sakthipriyan Vairamani) [#2169](https://github.com/nodejs/node/pull/2169) +* [[`2965442308`](https://github.com/nodejs/node/commit/2965442308)] - **(SEMVER-MAJOR)** **http**: fix agent.getName() and add tests (Brendan Ashworth) [#1617](https://github.com/nodejs/node/pull/1617) +* [[`2d9456e3e6`](https://github.com/nodejs/node/commit/2d9456e3e6)] - **(SEMVER-MAJOR)** **http**: use official IANA Status Codes (jomo) [#1470](https://github.com/nodejs/node/pull/1470) +* [[`11e4249227`](https://github.com/nodejs/node/commit/11e4249227)] - **(SEMVER-MAJOR)** **http_server**: `prefinish` vs `finish` (Fedor Indutny) [#1411](https://github.com/nodejs/node/pull/1411) +* [[`9bc2e26720`](https://github.com/nodejs/node/commit/9bc2e26720)] - **net**: do not set V4MAPPED on FreeBSD (Julien Gilli) [iojs/io.js#1555](https://github.com/iojs/io.js/pull/1555) +* [[`ba9ccf227e`](https://github.com/nodejs/node/commit/ba9ccf227e)] - **node**: remove redundant --use-old-buffer (Rod Vagg) [#2275](https://github.com/nodejs/node/pull/2275) +* [[`ef65321083`](https://github.com/nodejs/node/commit/ef65321083)] - **(SEMVER-MAJOR)** **node**: do not override `message`/`stack` of error (Fedor Indutny) [#2108](https://github.com/nodejs/node/pull/2108) +* [[`9f727f5e03`](https://github.com/nodejs/node/commit/9f727f5e03)] - **node-gyp**: detect RC build with x.y.z-rc.n format (Rod Vagg) [#2171](https://github.com/nodejs/node/pull/2171) +* [[`e52f963632`](https://github.com/nodejs/node/commit/e52f963632)] - **node-gyp**: download header tarball for compile (Rod Vagg) [#2066](https://github.com/nodejs/node/pull/2066) +* [[`902c9ca51d`](https://github.com/nodejs/node/commit/902c9ca51d)] - **node-gyp**: make aware of nightly, next-nightly & rc (Rod Vagg) [#2066](https://github.com/nodejs/node/pull/2066) +* [[`4cffaa3f55`](https://github.com/nodejs/node/commit/4cffaa3f55)] - **(SEMVER-MINOR)** **readline**: allow tabs in input (Rich Trott) [#1761](https://github.com/nodejs/node/pull/1761) +* [[`ed6c249104`](https://github.com/nodejs/node/commit/ed6c249104)] - **(SEMVER-MAJOR)** **repl**: persist history in plain text (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) +* [[`f7d5e4c618`](https://github.com/nodejs/node/commit/f7d5e4c618)] - **(SEMVER-MINOR)** **repl**: default persistence to ~/.node_repl_history (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) +* [[`ea05e760cd`](https://github.com/nodejs/node/commit/ea05e760cd)] - **repl**: don't clobber RegExp.$ properties (Sakthipriyan Vairamani) [#2137](https://github.com/nodejs/node/pull/2137) +* [[`d20093246b`](https://github.com/nodejs/node/commit/d20093246b)] - **src**: disable vector ICs on arm (Michaël Zasso) [#2220](https://github.com/nodejs/node/pull/2220) +* [[`04fd4fad46`](https://github.com/nodejs/node/commit/04fd4fad46)] - **(SEMVER-MINOR)** **src**: introduce process.release object (Rod Vagg) [#2154](https://github.com/nodejs/node/pull/2154) +* [[`9d34bd1147`](https://github.com/nodejs/node/commit/9d34bd1147)] - **src**: increment NODE_MODULE_VERSION to 45 (Rod Vagg) [#2096](https://github.com/nodejs/node/pull/2096) +* [[`ceee8d2807`](https://github.com/nodejs/node/commit/ceee8d2807)] - **test**: add tests for persistent repl history (Jeremiah Senkpiel) [#2224](https://github.com/nodejs/node/pull/2224) +* [[`8e1a8ffe24`](https://github.com/nodejs/node/commit/8e1a8ffe24)] - **test**: remove two obsolete pummel tests (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) +* [[`ae731ec0fa`](https://github.com/nodejs/node/commit/ae731ec0fa)] - **test**: don't use arguments.callee (Ben Noordhuis) [#2022](https://github.com/nodejs/node/pull/2022) +* [[`21d31c08e7`](https://github.com/nodejs/node/commit/21d31c08e7)] - **test**: remove obsolete harmony flags (Chris Dickinson) +* [[`64cf71195c`](https://github.com/nodejs/node/commit/64cf71195c)] - **test**: change the hostname to an invalid name (Sakthipriyan Vairamani) [#2287](https://github.com/nodejs/node/pull/2287) +* [[`80a1cf7425`](https://github.com/nodejs/node/commit/80a1cf7425)] - **test**: fix messages and use return to skip tests (Sakthipriyan Vairamani) [#2290](https://github.com/nodejs/node/pull/2290) +* [[`d5ab92bcc1`](https://github.com/nodejs/node/commit/d5ab92bcc1)] - **test**: use common.isWindows consistently (Sakthipriyan Vairamani) [#2269](https://github.com/nodejs/node/pull/2269) +* [[`bc733f7065`](https://github.com/nodejs/node/commit/bc733f7065)] - **test**: fix fs.readFile('/dev/stdin') tests (Ben Noordhuis) [#2265](https://github.com/nodejs/node/pull/2265) +* [[`3cbb5870e5`](https://github.com/nodejs/node/commit/3cbb5870e5)] - **tools**: expose skip output to test runner (Johan Bergström) [#2130](https://github.com/nodejs/node/pull/2130) +* [[`3b021efe11`](https://github.com/nodejs/node/commit/3b021efe11)] - **vm**: fix symbol access (Domenic Denicola) [#1773](https://github.com/nodejs/node/pull/1773) +* [[`7b81e4ba36`](https://github.com/nodejs/node/commit/7b81e4ba36)] - **vm**: remove unnecessary access checks (Domenic Denicola) [#1773](https://github.com/nodejs/node/pull/1773) +* [[`659dadd410`](https://github.com/nodejs/node/commit/659dadd410)] - **vm**: fix property descriptors of sandbox properties (Domenic Denicola) [#1773](https://github.com/nodejs/node/pull/1773) +* [[`9bac1dbae9`](https://github.com/nodejs/node/commit/9bac1dbae9)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) + + +## 2015-07-28, Version 2.5.0, @cjihrig + +### Notable changes + +* **https**: TLS sessions in Agent are reused (Fedor Indutny) [#2228](https://github.com/nodejs/node/pull/2228) +* **src**: base64 decoding is now 50% faster (Ben Noordhuis) [#2193](https://github.com/nodejs/node/pull/2193) +* **npm**: Upgraded to v2.13.2, release notes can be found in (Kat Marchán) [#2241](https://github.com/nodejs/node/pull/2241). + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Using multiple REPL instances in parallel may cause some REPL history corruption or loss. [#1634](https://github.com/nodejs/node/issues/1634) +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`bf2cd225a8`](https://github.com/nodejs/node/commit/bf2cd225a8)] - **process**: resize stderr on SIGWINCH (Jeremiah Senkpiel) [#2231](https://github.com/nodejs/node/pull/2231) +* [[`99d9d7e716`](https://github.com/nodejs/node/commit/99d9d7e716)] - **benchmark**: add remaining path benchmarks & optimize (Nathan Woltman) [#2103](https://github.com/nodejs/node/pull/2103) +* [[`66fc8ca22b`](https://github.com/nodejs/node/commit/66fc8ca22b)] - **(SEMVER-MINOR)** **cluster**: emit 'message' event on cluster master (Sam Roberts) [#861](https://github.com/nodejs/node/pull/861) +* [[`eb35968de7`](https://github.com/nodejs/node/commit/eb35968de7)] - **crypto**: fix legacy SNICallback (Fedor Indutny) [#1720](https://github.com/nodejs/node/pull/1720) +* [[`fef190cea6`](https://github.com/nodejs/node/commit/fef190cea6)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`b73a7465c5`](https://github.com/nodejs/node/commit/b73a7465c5)] - **deps**: upgrade to npm 2.13.2 (Kat Marchán) [#2241](https://github.com/nodejs/node/pull/2241) +* [[`0a7bf81d2f`](https://github.com/nodejs/node/commit/0a7bf81d2f)] - **deps**: update V8 to 4.2.77.21 (Ali Ijaz Sheikh) [#2238](https://github.com/nodejs/node/issues/2238) +* [[`73cdcdd581`](https://github.com/nodejs/node/commit/73cdcdd581)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`04893a736d`](https://github.com/nodejs/node/commit/04893a736d)] - **deps**: upgrade to npm 2.13.1 (Kat Marchán) [#2210](https://github.com/nodejs/node/pull/2210) +* [[`a3c1b9720e`](https://github.com/nodejs/node/commit/a3c1b9720e)] - **doc**: add GPG fingerprint for cjihrig (cjihrig) [#2217](https://github.com/nodejs/node/pull/2217) +* [[`d9f857df3b`](https://github.com/nodejs/node/commit/d9f857df3b)] - **doc**: note about custom inspect functions (Sakthipriyan Vairamani) [#2142](https://github.com/nodejs/node/pull/2142) +* [[`4ef2b5fbfb`](https://github.com/nodejs/node/commit/4ef2b5fbfb)] - **doc**: Replace util.debug with console.error (Yosuke Furukawa) [#2214](https://github.com/nodejs/node/pull/2214) +* [[`b612f085ec`](https://github.com/nodejs/node/commit/b612f085ec)] - **doc**: add joaocgreis as a collaborator (João Reis) [#2208](https://github.com/nodejs/node/pull/2208) +* [[`6b85d5a4b3`](https://github.com/nodejs/node/commit/6b85d5a4b3)] - **doc**: add TSC meeting minutes 2015-07-15 (Rod Vagg) [#2191](https://github.com/nodejs/node/pull/2191) +* [[`c7d8b09162`](https://github.com/nodejs/node/commit/c7d8b09162)] - **doc**: recompile before testing core module changes (Phillip Johnsen) [#2051](https://github.com/nodejs/node/pull/2051) +* [[`9afee6785e`](https://github.com/nodejs/node/commit/9afee6785e)] - **http**: Check this.connection before using it (Sakthipriyan Vairamani) [#2172](https://github.com/nodejs/node/pull/2172) +* [[`2ca5a3db47`](https://github.com/nodejs/node/commit/2ca5a3db47)] - **https**: reuse TLS sessions in Agent (Fedor Indutny) [#2228](https://github.com/nodejs/node/pull/2228) +* [[`fef87fee1d`](https://github.com/nodejs/node/commit/fef87fee1d)] - **(SEMVER-MINOR)** **lib,test**: add freelist deprecation and test (Sakthipriyan Vairamani) [#2176](https://github.com/nodejs/node/pull/2176) +* [[`503b089dd8`](https://github.com/nodejs/node/commit/503b089dd8)] - **net**: don't throw on immediately destroyed socket (Evan Lucas) [#2251](https://github.com/nodejs/node/pull/2251) +* [[`93660c8b8e`](https://github.com/nodejs/node/commit/93660c8b8e)] - **node**: remove bad fn call and check (Trevor Norris) [#2157](https://github.com/nodejs/node/pull/2157) +* [[`afd7e37ee0`](https://github.com/nodejs/node/commit/afd7e37ee0)] - **repl**: better empty line handling (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) +* [[`81ea52aa01`](https://github.com/nodejs/node/commit/81ea52aa01)] - **repl**: improving line continuation handling (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) +* [[`30edb5aee9`](https://github.com/nodejs/node/commit/30edb5aee9)] - **repl**: preventing REPL crash with inherited properties (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) +* [[`77fa385e5d`](https://github.com/nodejs/node/commit/77fa385e5d)] - **repl**: fixing `undefined` in invalid REPL keyword error (Sakthipriyan Vairamani) [#2163](https://github.com/nodejs/node/pull/2163) +* [[`8fd3ce100e`](https://github.com/nodejs/node/commit/8fd3ce100e)] - **src**: make base64 decoding 50% faster (Ben Noordhuis) [#2193](https://github.com/nodejs/node/pull/2193) +* [[`c786d6341d`](https://github.com/nodejs/node/commit/c786d6341d)] - **test**: do not use public IPs for timeout testing (Rich Trott) [#2057](https://github.com/nodejs/node/pull/2057) +* [[`4e78cd71c0`](https://github.com/nodejs/node/commit/4e78cd71c0)] - **test**: skip IPv6 part before testing it (Sakthipriyan Vairamani) [#2226](https://github.com/nodejs/node/pull/2226) +* [[`ac70bc8240`](https://github.com/nodejs/node/commit/ac70bc8240)] - **test**: fix valgrind uninitialized memory warning (Ben Noordhuis) [#2193](https://github.com/nodejs/node/pull/2193) +* [[`ac7d3fa0d9`](https://github.com/nodejs/node/commit/ac7d3fa0d9)] - **test**: add -no_rand_screen to s_client opts on Win (Shigeki Ohtsu) [#2209](https://github.com/nodejs/node/pull/2209) +* [[`79c865a53f`](https://github.com/nodejs/node/commit/79c865a53f)] - **test**: changing process.exit to return while skipping tests (Sakthipriyan Vairamani) [#2109](https://github.com/nodejs/node/pull/2109) +* [[`69298d36cf`](https://github.com/nodejs/node/commit/69298d36cf)] - **test**: formatting skip messages for TAP parsing (Sakthipriyan Vairamani) [#2109](https://github.com/nodejs/node/pull/2109) +* [[`543dabb609`](https://github.com/nodejs/node/commit/543dabb609)] - **timers**: improve Timer.now() performance (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) +* [[`3663b124e6`](https://github.com/nodejs/node/commit/3663b124e6)] - **timers**: remove unused Timer.again() (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) +* [[`bcce5cf9bb`](https://github.com/nodejs/node/commit/bcce5cf9bb)] - **timers**: remove unused Timer.getRepeat() (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) +* [[`f2c83bd202`](https://github.com/nodejs/node/commit/f2c83bd202)] - **timers**: remove unused Timer.setRepeat() (Ben Noordhuis) [#2256](https://github.com/nodejs/node/pull/2256) +* [[`e11fc67225`](https://github.com/nodejs/node/commit/e11fc67225)] - **(SEMVER-MINOR)** **tls**: add `getTicketKeys()`/`setTicketKeys()` (Fedor Indutny) [#2227](https://github.com/nodejs/node/pull/2227) +* [[`68b06e94e3`](https://github.com/nodejs/node/commit/68b06e94e3)] - **tools**: use local or specified $NODE for test-npm (Jeremiah Senkpiel) [#1984](https://github.com/nodejs/node/pull/1984) +* [[`ab479659c7`](https://github.com/nodejs/node/commit/ab479659c7)] - **util**: delay creation of debug context (Ali Ijaz Sheikh) [#2248](https://github.com/nodejs/node/pull/2248) +* [[`6391f4d2fd`](https://github.com/nodejs/node/commit/6391f4d2fd)] - **util**: removing redundant checks in is* functions (Sakthipriyan Vairamani) [#2179](https://github.com/nodejs/node/pull/2179) +* [[`b148c0dff3`](https://github.com/nodejs/node/commit/b148c0dff3)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) +* [[`f90f1e75bb`](https://github.com/nodejs/node/commit/f90f1e75bb)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) + + +## 2015-07-17, Version 2.4.0, @Fishrock123 + +### Notable changes + +* **src**: Added a new `--track-heap-objects` flag to track heap object allocations for heap snapshots (Bradley Meck) [#2135](https://github.com/nodejs/node/pull/2135). +* **readline**: Fixed a freeze that affected the repl if the keypress event handler threw (Alex Kocharin) [#2107](https://github.com/nodejs/node/pull/2107). +* **npm**: Upgraded to v2.13.0, release notes can be found in (Forrest L Norvell) [#2152](https://github.com/nodejs/node/pull/2152). + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`f95f9ef6ea`](https://github.com/nodejs/node/commit/f95f9ef6ea)] - **build**: always use prefix=/ for tar-headers (Rod Vagg) [#2082](https://github.com/nodejs/node/pull/2082) +* [[`12bc397207`](https://github.com/nodejs/node/commit/12bc397207)] - **build**: run-ci makefile rule (Alexis Campailla) [#2134](https://github.com/nodejs/node/pull/2134) +* [[`84012c99e0`](https://github.com/nodejs/node/commit/84012c99e0)] - **build**: fix vcbuild merge issues (Alexis Campailla) [#2131](https://github.com/nodejs/node/pull/2131) +* [[`47e2c5c828`](https://github.com/nodejs/node/commit/47e2c5c828)] - **build**: bail early if clean is invoked (Johan Bergström) [#2127](https://github.com/nodejs/node/pull/2127) +* [[`5acad6b163`](https://github.com/nodejs/node/commit/5acad6b163)] - **child_process**: fix arguments comments (Roman Reiss) [#2161](https://github.com/nodejs/node/pull/2161) +* [[`3c4121c418`](https://github.com/nodejs/node/commit/3c4121c418)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`938cc757bb`](https://github.com/nodejs/node/commit/938cc757bb)] - **deps**: upgrade to npm 2.13.0 (Forrest L Norvell) [#2152](https://github.com/nodejs/node/pull/2152) +* [[`6f306e0ed2`](https://github.com/nodejs/node/commit/6f306e0ed2)] - **doc**: add targos as a collaborator (Michaël Zasso) [#2200](https://github.com/nodejs/node/pull/2200) +* [[`c019d9a239`](https://github.com/nodejs/node/commit/c019d9a239)] - **doc**: add thefourtheye as a collaborator (Sakthipriyan Vairamani) [#2199](https://github.com/nodejs/node/pull/2199) +* [[`4e92dbc26b`](https://github.com/nodejs/node/commit/4e92dbc26b)] - **doc**: add TSC members from the combined project (Jeremiah Senkpiel) [#2085](https://github.com/nodejs/node/pull/2085) +* [[`6c3aabf455`](https://github.com/nodejs/node/commit/6c3aabf455)] - **doc**: add TSC meeting minutes 2015-07-08 (Rod Vagg) [#2184](https://github.com/nodejs/node/pull/2184) +* [[`30a0d47d51`](https://github.com/nodejs/node/commit/30a0d47d51)] - **doc**: add TSC meeting minutes 2015-07-01 (Rod Vagg) [#2132](https://github.com/nodejs/node/pull/2132) +* [[`23efb05cc3`](https://github.com/nodejs/node/commit/23efb05cc3)] - **doc**: document fs.watchFile behaviour on ENOENT (Brendan Ashworth) [#2093](https://github.com/nodejs/node/pull/2093) +* [[`65963ec26f`](https://github.com/nodejs/node/commit/65963ec26f)] - **doc,test**: empty strings in path module (Sakthipriyan Vairamani) [#2106](https://github.com/nodejs/node/pull/2106) +* [[`0ab81e6f58`](https://github.com/nodejs/node/commit/0ab81e6f58)] - **docs**: link to more up-to-date v8 docs (Jeremiah Senkpiel) [#2196](https://github.com/nodejs/node/pull/2196) +* [[`1afc0c9e86`](https://github.com/nodejs/node/commit/1afc0c9e86)] - **fs**: fix error on bad listener type (Brendan Ashworth) [#2093](https://github.com/nodejs/node/pull/2093) +* [[`2ba84606a6`](https://github.com/nodejs/node/commit/2ba84606a6)] - **path**: assert path.join() arguments equally (Phillip Johnsen) [#2159](https://github.com/nodejs/node/pull/2159) +* [[`bd01603201`](https://github.com/nodejs/node/commit/bd01603201)] - **readline**: fix freeze if `keypress` event throws (Alex Kocharin) [#2107](https://github.com/nodejs/node/pull/2107) +* [[`59f6b5da2a`](https://github.com/nodejs/node/commit/59f6b5da2a)] - **repl**: Prevent crash when tab-completed with Proxy (Sakthipriyan Vairamani) [#2120](https://github.com/nodejs/node/pull/2120) +* [[`cf14a2427c`](https://github.com/nodejs/node/commit/cf14a2427c)] - **(SEMVER-MINOR)** **src**: add --track-heap-objects (Bradley Meck) [#2135](https://github.com/nodejs/node/pull/2135) +* [[`2b4b600660`](https://github.com/nodejs/node/commit/2b4b600660)] - **test**: fix test-debug-port-from-cmdline (João Reis) [#2186](https://github.com/nodejs/node/pull/2186) +* [[`d4ceb16da2`](https://github.com/nodejs/node/commit/d4ceb16da2)] - **test**: properly clean up temp directory (Roman Reiss) [#2164](https://github.com/nodejs/node/pull/2164) +* [[`842eb5b853`](https://github.com/nodejs/node/commit/842eb5b853)] - **test**: add test for dgram.setTTL (Evan Lucas) [#2121](https://github.com/nodejs/node/pull/2121) +* [[`cff7300a57`](https://github.com/nodejs/node/commit/cff7300a57)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) + + + +## 2015-07-09, Version 2.3.4, @Fishrock123 + +### Notable changes + +* **openssl**: Upgrade to 1.0.2d, fixes CVE-2015-1793 (Alternate Chains Certificate Forgery) (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141). +* **npm**: Upgraded to v2.12.1, release notes can be found in and (Kat Marchán) [#2112](https://github.com/nodejs/node/pull/2112). + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`0d15161c24`](https://github.com/nodejs/node/commit/0d15161c24)] - **benchmark**: Add some path benchmarks for #1778 (Nathan Woltman) [#1778](https://github.com/nodejs/node/pull/1778) +* [[`c70e68fa32`](https://github.com/nodejs/node/commit/c70e68fa32)] - **deps**: update deps/openssl/conf/arch/*/opensslconf.h (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) +* [[`ca93f7f2e6`](https://github.com/nodejs/node/commit/ca93f7f2e6)] - **deps**: upgrade openssl sources to 1.0.2d (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) +* [[`b18c841ec1`](https://github.com/nodejs/node/commit/b18c841ec1)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`863cdbdd08`](https://github.com/nodejs/node/commit/863cdbdd08)] - **deps**: upgrade to npm 2.12.1 (Kat Marchán) [#2112](https://github.com/nodejs/node/pull/2112) +* [[`84b3915764`](https://github.com/nodejs/node/commit/84b3915764)] - **doc**: document current release procedure (Rod Vagg) [#2099](https://github.com/nodejs/node/pull/2099) +* [[`46140334cd`](https://github.com/nodejs/node/commit/46140334cd)] - **doc**: update AUTHORS list (Rod Vagg) [#2100](https://github.com/nodejs/node/pull/2100) +* [[`bca53dce76`](https://github.com/nodejs/node/commit/bca53dce76)] - **path**: refactor for performance and consistency (Nathan Woltman) [#1778](https://github.com/nodejs/node/pull/1778) +* [[`6bef15afe7`](https://github.com/nodejs/node/commit/6bef15afe7)] - **src**: remove traceSyncIO property from process (Bradley Meck) [#2143](https://github.com/nodejs/node/pull/2143) +* [[`2ba1740ba1`](https://github.com/nodejs/node/commit/2ba1740ba1)] - **test**: add missing crypto checks (Johan Bergström) [#2129](https://github.com/nodejs/node/pull/2129) +* [[`180fd392ca`](https://github.com/nodejs/node/commit/180fd392ca)] - **test**: refactor test-repl-tab-complete (Sakthipriyan Vairamani) [#2122](https://github.com/nodejs/node/pull/2122) +* [[`fb05c8e27d`](https://github.com/nodejs/node/commit/fb05c8e27d)] - ***Revert*** "**test**: add test for missing `close`/`finish` event" (Fedor Indutny) +* [[`9436a860cb`](https://github.com/nodejs/node/commit/9436a860cb)] - **test**: add test for missing `close`/`finish` event (Mark Plomer) [iojs/io.js#1373](https://github.com/iojs/io.js/pull/1373) +* [[`ee3ce2ed88`](https://github.com/nodejs/node/commit/ee3ce2ed88)] - **tools**: install gdbinit from v8 to $PREFIX/share (Ali Ijaz Sheikh) [#2123](https://github.com/nodejs/node/pull/2123) +* [[`dd523c75da`](https://github.com/nodejs/node/commit/dd523c75da)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) + + + +## 2015-07-09, Version 1.8.4, @Fishrock123 + +**Maintenance release** + +### Notable changes + +* **openssl**: Upgrade to 1.0.2d, fixes CVE-2015-1793 (Alternate Chains Certificate Forgery) [#2141](https://github.com/nodejs/node/pull/2141). + +### Known issues + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). +* readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) + +### Commits + +* [[`52b1230628`](https://github.com/nodejs/node/commit/52b1230628)] - **deps**: update deps/openssl/conf/arch/*/opensslconf.h (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) +* [[`20ff1e2ecb`](https://github.com/nodejs/node/commit/20ff1e2ecb)] - **deps**: upgrade openssl sources to 1.0.2d (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) + + + +## 2015-07-04, Version 2.3.3, @Fishrock123 + +### Notable changes + +* **deps**: Fixed an out-of-band write in utf8 decoder. **This is an important security update** as it can be used to cause a denial of service attack. + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +## Commits + +* [[`030f8045c7`](https://github.com/nodejs/node/commit/030f8045c7)] - **deps**: fix out-of-band write in utf8 decoder (Fedor Indutny) +* [[`0f09b8db28`](https://github.com/nodejs/node/commit/0f09b8db28)] - **doc**: don't recommend domains for error handling (Benjamin Gruenbaum) [#2056](https://github.com/nodejs/node/pull/2056) +* [[`9cd44bb2b6`](https://github.com/nodejs/node/commit/9cd44bb2b6)] - **util**: prepend '(node) ' to deprecation messages (Sakthipriyan Vairamani) [#1892](https://github.com/nodejs/node/pull/1892) + + + +## 2015-07-04, Version 1.8.3, @rvagg + +**Maintenance release** + +## Notable changes + +* **v8**: Fixed an out-of-band write in utf8 decoder. **This is an important security update** as it can be used to cause a denial of service attack. +* **openssl**: Upgrade to 1.0.2b and 1.0.2c, introduces DHE man-in-the-middle protection (Logjam) and fixes malformed ECParameters causing infinite loop (CVE-2015-1788). See the [security advisory](https://www.openssl.org/news/secadv_20150611.txt) for full details. (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) [#1958](https://github.com/nodejs/node/pull/1958) +* **build**: + - Added support for compiling with Microsoft Visual C++ 2015 + - Started building and distributing headers-only tarballs along with binaries + +### Known issues + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). +* readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) + +### Commits + +* [[`d8f260d33b`](https://github.com/nodejs/node/commit/d8f260d33b)] - **build**: add tar-headers target for headers-only tar (Rod Vagg) [#1975](https://github.com/nodejs/node/pull/1975) +* [[`00ba429674`](https://github.com/nodejs/node/commit/00ba429674)] - **build**: update build targets for io.js (Rod Vagg) [#1938](https://github.com/nodejs/node/pull/1938) +* [[`39e2207ff1`](https://github.com/nodejs/node/commit/39e2207ff1)] - **build**: fix cherry-pick ooops, fix comment wording (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) +* [[`561919a67a`](https://github.com/nodejs/node/commit/561919a67a)] - **build**: add MSVS 2015 support (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) +* [[`8e1134c04c`](https://github.com/nodejs/node/commit/8e1134c04c)] - **build**: remove lint from test-ci on windows (Johan Bergström) [#2004](https://github.com/nodejs/node/pull/2004) +* [[`e52e99085e`](https://github.com/nodejs/node/commit/e52e99085e)] - **build**: don't run lint from test-ci (Johan Bergström) [#1965](https://github.com/nodejs/node/pull/1965) +* [[`c5d1ec7fea`](https://github.com/nodejs/node/commit/c5d1ec7fea)] - **build**: simplify execution of built binary (Johan Bergström) [#1955](https://github.com/nodejs/node/pull/1955) +* [[`2ce147551a`](https://github.com/nodejs/node/commit/2ce147551a)] - **build,win**: set env before generating projects (Alexis Campailla) [joyent/node#20109](https://github.com/joyent/node/pull/20109) +* [[`78de5f85f2`](https://github.com/nodejs/node/commit/78de5f85f2)] - **deps**: fix out-of-band write in utf8 decoder (Ben Noordhuis) +* [[`83ee07b6be`](https://github.com/nodejs/node/commit/83ee07b6be)] - **deps**: copy all openssl header files to include dir (Shigeki Ohtsu) [#2016](https://github.com/nodejs/node/pull/2016) +* [[`a97125520d`](https://github.com/nodejs/node/commit/a97125520d)] - **deps**: update UPGRADING.md doc to openssl-1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) +* [[`0e2d068e0b`](https://github.com/nodejs/node/commit/0e2d068e0b)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) +* [[`310b8d1120`](https://github.com/nodejs/node/commit/310b8d1120)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`a472946747`](https://github.com/nodejs/node/commit/a472946747)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) +* [[`b2467e3ebf`](https://github.com/nodejs/node/commit/b2467e3ebf)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) +* [[`e548abb800`](https://github.com/nodejs/node/commit/e548abb800)] - **deps**: upgrade openssl sources to 1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) +* [[`1feaa68e85`](https://github.com/nodejs/node/commit/1feaa68e85)] - **deps**: update asm files for openssl-1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) +* [[`151720fae7`](https://github.com/nodejs/node/commit/151720fae7)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) +* [[`139da6a02a`](https://github.com/nodejs/node/commit/139da6a02a)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`283642827a`](https://github.com/nodejs/node/commit/283642827a)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) +* [[`d593b552de`](https://github.com/nodejs/node/commit/d593b552de)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) +* [[`2a3367a4bd`](https://github.com/nodejs/node/commit/2a3367a4bd)] - **deps**: upgrade openssl sources to 1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) +* [[`5c29c0c519`](https://github.com/nodejs/node/commit/5c29c0c519)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) +* [[`2cd7f73d9f`](https://github.com/nodejs/node/commit/2cd7f73d9f)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) +* [[`c65484a74d`](https://github.com/nodejs/node/commit/c65484a74d)] - **tls**: make server not use DHE in less than 1024bits (Shigeki Ohtsu) [#1739](https://github.com/nodejs/node/pull/1739) +* [[`77f518403f`](https://github.com/nodejs/node/commit/77f518403f)] - **win,node-gyp**: make delay-load hook C89 compliant (Sharat M R) [TooTallNate/node-gyp#616](https://github.com/TooTallNa + + + +## 2015-07-01, Version 2.3.2, @rvagg + +### Notable changes + +* **build**: + - Added support for compiling with Microsoft Visual C++ 2015 + - Started building and distributing headers-only tarballs along with binaries + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +## Commits + +* [[`9180140231`](https://github.com/nodejs/node/commit/9180140231)] - **_stream_wrap**: prevent use after free in TLS (Fedor Indutny) [#1910](https://github.com/nodejs/node/pull/1910) +* [[`05a73c0f25`](https://github.com/nodejs/node/commit/05a73c0f25)] - **benchmark**: make concurrent requests configurable (Rich Trott) [#2068](https://github.com/nodejs/node/pull/2068) +* [[`f52d73352e`](https://github.com/nodejs/node/commit/f52d73352e)] - **benchmark**: fix typo in README (Rich Trott) [#2067](https://github.com/nodejs/node/pull/2067) +* [[`1cd9eeb556`](https://github.com/nodejs/node/commit/1cd9eeb556)] - **buffer**: prevent abort on bad proto (Trevor Norris) [#2012](https://github.com/nodejs/node/pull/2012) +* [[`8350f3a3a2`](https://github.com/nodejs/node/commit/8350f3a3a2)] - **buffer**: optimize Buffer#toString() (Ben Noordhuis) [#2027](https://github.com/nodejs/node/pull/2027) +* [[`628a3ab093`](https://github.com/nodejs/node/commit/628a3ab093)] - **build**: add tar-headers target for headers-only tar (Rod Vagg) [#1975](https://github.com/nodejs/node/pull/1975) +* [[`dcbb9e1da6`](https://github.com/nodejs/node/commit/dcbb9e1da6)] - **build**: update build targets for io.js (Rod Vagg) [#1938](https://github.com/nodejs/node/pull/1938) +* [[`c87c34c242`](https://github.com/nodejs/node/commit/c87c34c242)] - **build**: fix cherry-pick ooops, fix comment wording (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) +* [[`4208dc4fef`](https://github.com/nodejs/node/commit/4208dc4fef)] - **build**: add MSVS 2015 support (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) +* [[`834a365113`](https://github.com/nodejs/node/commit/834a365113)] - **build**: DTrace is enabled by default on darwin (Evan Lucas) [#2019](https://github.com/nodejs/node/pull/2019) +* [[`c0c0d73269`](https://github.com/nodejs/node/commit/c0c0d73269)] - **build,win**: set env before generating projects (Alexis Campailla) [joyent/node#20109](https://github.com/joyent/node/pull/20109) +* [[`9e890fe8b4`](https://github.com/nodejs/node/commit/9e890fe8b4)] - **crypto**: fix VerifyCallback in case of verify error (Shigeki Ohtsu) [#2064](https://github.com/nodejs/node/pull/2064) +* [[`1f371e3988`](https://github.com/nodejs/node/commit/1f371e3988)] - **deps**: copy all openssl header files to include dir (Shigeki Ohtsu) [#2016](https://github.com/nodejs/node/pull/2016) +* [[`c370bd3aea`](https://github.com/nodejs/node/commit/c370bd3aea)] - **doc**: make the abbreviation 1MM clear (Ivan Yan) [#2053](https://github.com/nodejs/node/pull/2053) +* [[`54d5437566`](https://github.com/nodejs/node/commit/54d5437566)] - **doc**: Added sample command to test iojs build (Jimmy Hsu) [#850](https://github.com/nodejs/node/pull/850) +* [[`f1f1b7e597`](https://github.com/nodejs/node/commit/f1f1b7e597)] - **doc**: add TSC meeting minutes 2015-06-17 (Rod Vagg) [#2048](https://github.com/nodejs/node/pull/2048) +* [[`dbd5dc932d`](https://github.com/nodejs/node/commit/dbd5dc932d)] - **doc**: clarify prerequisites in benchmark/README.md (Jeremiah Senkpiel) [#2034](https://github.com/nodejs/node/pull/2034) +* [[`50dbc8e143`](https://github.com/nodejs/node/commit/50dbc8e143)] - **doc**: add TSC meeting minutes 2015-05-27 (Rod Vagg) [#2037](https://github.com/nodejs/node/pull/2037) +* [[`941ad362a7`](https://github.com/nodejs/node/commit/941ad362a7)] - **doc**: archive io.js TC minutes (Rod Vagg) +* [[`644b2eaa89`](https://github.com/nodejs/node/commit/644b2eaa89)] - **doc**: rename tc-meetings to tsc-meetings (Rod Vagg) +* [[`1330ee3b27`](https://github.com/nodejs/node/commit/1330ee3b27)] - **doc**: add TC meeting 2015-05-13 minutes (Rod Vagg) [#1700](https://github.com/nodejs/node/pull/1700) +* [[`392e8fd64e`](https://github.com/nodejs/node/commit/392e8fd64e)] - **doc**: add @shigeki and @mscdex to TC (Rod Vagg) [#2008](https://github.com/nodejs/node/pull/2008) +* [[`af249fa8a1`](https://github.com/nodejs/node/commit/af249fa8a1)] - **net**: wrap connect in nextTick (Evan Lucas) [#2054](https://github.com/nodejs/node/pull/2054) +* [[`7f63449fde`](https://github.com/nodejs/node/commit/7f63449fde)] - **net**: fix debug for dnsopts (Evan Lucas) [#2059](https://github.com/nodejs/node/pull/2059) +* [[`eabed2f518`](https://github.com/nodejs/node/commit/eabed2f518)] - **repl**: remove obsolete TODO (Rich Trott) [#2081](https://github.com/nodejs/node/pull/2081) +* [[`a198c68b56`](https://github.com/nodejs/node/commit/a198c68b56)] - **repl**: make 'Unexpected token' errors recoverable (Julien Gilli) [#2052](https://github.com/nodejs/node/pull/2052) +* [[`d735b2c6ef`](https://github.com/nodejs/node/commit/d735b2c6ef)] - **repl**: fix tab completion for a non-global context (Sangmin Yoon) [#2052](https://github.com/nodejs/node/pull/2052) +* [[`8cee8f54fc`](https://github.com/nodejs/node/commit/8cee8f54fc)] - **src**: nix stdin _readableState.reading manipulation (Chris Dickinson) [#454](https://github.com/nodejs/node/pull/454) +* [[`856c11f8c8`](https://github.com/nodejs/node/commit/856c11f8c8)] - **test**: purge stale disabled tests (Rich Trott) [#2045](https://github.com/nodejs/node/pull/2045) +* [[`4d5089e181`](https://github.com/nodejs/node/commit/4d5089e181)] - **test**: do not swallow OpenSSL support error (Rich Trott) [#2042](https://github.com/nodejs/node/pull/2042) +* [[`06721fe005`](https://github.com/nodejs/node/commit/06721fe005)] - **test**: fix test-repl-tab-complete.js (cjihrig) [#2052](https://github.com/nodejs/node/pull/2052) +* [[`8e9089ac35`](https://github.com/nodejs/node/commit/8e9089ac35)] - **test**: check for error on Windows (Rich Trott) [#2035](https://github.com/nodejs/node/pull/2035) +* [[`776a65ebcd`](https://github.com/nodejs/node/commit/776a65ebcd)] - **test**: remove obsolete TODO comments (Rich Trott) [#2033](https://github.com/nodejs/node/pull/2033) +* [[`bdfeb798ad`](https://github.com/nodejs/node/commit/bdfeb798ad)] - **test**: remove obsolete TODO comments (Rich Trott) [#2032](https://github.com/nodejs/node/pull/2032) +* [[`58e914f9bc`](https://github.com/nodejs/node/commit/58e914f9bc)] - **tools**: fix gyp to work on MacOSX without XCode (Shigeki Ohtsu) [iojs/io.js#1325](https://github.com/iojs/io.js/pull/1325) +* [[`99cbbc0a13`](https://github.com/nodejs/node/commit/99cbbc0a13)] - **tools**: update gyp to 25ed9ac (Ben Noordhuis) [#2074](https://github.com/nodejs/node/pull/2074) +* [[`e3f9335c40`](https://github.com/nodejs/node/commit/e3f9335c40)] - **tools**: re-enable comma-spacing linter rule (Roman Reiss) [#2072](https://github.com/nodejs/node/pull/2072) +* [[`d91e10b3bd`](https://github.com/nodejs/node/commit/d91e10b3bd)] - **tools**: update eslint to 0.24.0 (Roman Reiss) [#2072](https://github.com/nodejs/node/pull/2072) +* [[`6c61ca5325`](https://github.com/nodejs/node/commit/6c61ca5325)] - **url**: fix typo in comment (Rich Trott) [#2071](https://github.com/nodejs/node/pull/2071) +* [[`1a51f0058c`](https://github.com/nodejs/node/commit/1a51f0058c)] - **v8**: cherry-pick JitCodeEvent patch from upstream (Ben Noordhuis) [#2075](https://github.com/nodejs/node/pull/2075) + + + +## 2015-06-23, Version 2.3.1, @rvagg + +### Notable changes + +* **module**: The number of syscalls made during a `require()` have been significantly reduced again (see [#1801](https://github.com/nodejs/node/pull/1801) from v2.2.0 for previous work), which should lead to a performance improvement (Pierre Inglebert) [#1920](https://github.com/nodejs/node/pull/1920). +* **npm**: + * Upgrade to [v2.11.2](https://github.com/npm/npm/releases/tag/v2.11.2) (Rebecca Turner) [#1956](https://github.com/nodejs/node/pull/1956). + * Upgrade to [v2.11.3](https://github.com/npm/npm/releases/tag/v2.11.3) (Forrest L Norvell) [#2018](https://github.com/nodejs/node/pull/2018). +* **zlib**: A bug was discovered where the process would abort if the final part of a zlib decompression results in a buffer that would exceed the maximum length of `0x3fffffff` bytes (~1GiB). This was likely to only occur during buffered decompression (rather than streaming). This is now fixed and will instead result in a thrown `RangeError` (Michaël Zasso) [#1811](https://github.com/nodejs/node/pull/1811). + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +## Commits + +* [[`e56758a5e0`](https://github.com/nodejs/node/commit/e56758a5e0)] - **async-wrap**: add provider id and object info cb (Trevor Norris) [#1896](https://github.com/nodejs/node/pull/1896) +* [[`d5637e67c9`](https://github.com/nodejs/node/commit/d5637e67c9)] - **buffer**: fix cyclic dependency with util (Brendan Ashworth) [#1988](https://github.com/nodejs/node/pull/1988) +* [[`c5353d7c62`](https://github.com/nodejs/node/commit/c5353d7c62)] - **build**: remove lint from test-ci on windows (Johan Bergström) [#2004](https://github.com/nodejs/node/pull/2004) +* [[`c207e8d223`](https://github.com/nodejs/node/commit/c207e8d223)] - **build**: fix pkg-config output parsing in configure (Ben Noordhuis) [#1986](https://github.com/nodejs/node/pull/1986) +* [[`8d8a26e8f7`](https://github.com/nodejs/node/commit/8d8a26e8f7)] - **build**: don't run lint from test-ci (Johan Bergström) [#1965](https://github.com/nodejs/node/pull/1965) +* [[`1ec53c044d`](https://github.com/nodejs/node/commit/1ec53c044d)] - **build**: simplify execution of built binary (Johan Bergström) [#1955](https://github.com/nodejs/node/pull/1955) +* [[`3beb880716`](https://github.com/nodejs/node/commit/3beb880716)] - **crypto**: add cert check to CNNIC Whitelist (Shigeki Ohtsu) [#1895](https://github.com/nodejs/node/pull/1895) +* [[`48c0fb8b1a`](https://github.com/nodejs/node/commit/48c0fb8b1a)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`6a359b1ce9`](https://github.com/nodejs/node/commit/6a359b1ce9)] - **deps**: upgrade to npm 2.11.3 (Forrest L Norvell) [#2018](https://github.com/nodejs/node/pull/2018) +* [[`6aab2f3b9a`](https://github.com/nodejs/node/commit/6aab2f3b9a)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`3e12561b55`](https://github.com/nodejs/node/commit/3e12561b55)] - **deps**: upgrade to npm 2.11.2 (Rebecca Turner) [#1956](https://github.com/nodejs/node/pull/1956) +* [[`8ac50819b6`](https://github.com/nodejs/node/commit/8ac50819b6)] - **doc**: add security section to README.md (Rod Vagg) [#1948](https://github.com/nodejs/node/pull/1948) +* [[`1f93b63b11`](https://github.com/nodejs/node/commit/1f93b63b11)] - **doc**: change the info to the same as in gitconfig (Christian Tellnes) [#2000](https://github.com/nodejs/node/pull/2000) +* [[`0cf94e6856`](https://github.com/nodejs/node/commit/0cf94e6856)] - **doc**: mention CI in Collaborator Guide (Rich Trott) [#1995](https://github.com/nodejs/node/pull/1995) +* [[`7a3006efe4`](https://github.com/nodejs/node/commit/7a3006efe4)] - **doc**: add TOC links to Collaborator Guide (Rich Trott) [#1994](https://github.com/nodejs/node/pull/1994) +* [[`30638b150f`](https://github.com/nodejs/node/commit/30638b150f)] - **doc**: add TSC meeting notes 2015-06-10 (Bert Belder) [#1943](https://github.com/nodejs/node/pull/1943) +* [[`c4ec04136b`](https://github.com/nodejs/node/commit/c4ec04136b)] - **doc**: reformat authors section (Johan Bergström) [#1966](https://github.com/nodejs/node/pull/1966) +* [[`96165f9be2`](https://github.com/nodejs/node/commit/96165f9be2)] - **doc**: minor clarification in the modules API doc. (Сковорода Никита Андреевич) [#1983](https://github.com/nodejs/node/pull/1983) +* [[`5c2707c1b2`](https://github.com/nodejs/node/commit/5c2707c1b2)] - **doc**: benchmark/README.md copyedit (Rich Trott) [#1970](https://github.com/nodejs/node/pull/1970) +* [[`74fdf732d0`](https://github.com/nodejs/node/commit/74fdf732d0)] - **doc**: copyedit COLLABORATOR_GUIDE.md (Rich Trott) [#1964](https://github.com/nodejs/node/pull/1964) +* [[`5fe6e83640`](https://github.com/nodejs/node/commit/5fe6e83640)] - **doc**: copyedit GOVERNANCE.md (Rich Trott) [#1963](https://github.com/nodejs/node/pull/1963) +* [[`428526544c`](https://github.com/nodejs/node/commit/428526544c)] - **doc**: add ChALkeR as collaborator (Сковорода Никита Андреевич) [#1927](https://github.com/nodejs/node/pull/1927) +* [[`5dfe0d5d61`](https://github.com/nodejs/node/commit/5dfe0d5d61)] - **doc**: remove irrelevant SEMVER-MINOR & MAJOR (Rod Vagg) +* [[`fb8811d95e`](https://github.com/nodejs/node/commit/fb8811d95e)] - **lib,test**: fix whitespace issues (Roman Reiss) [#1971](https://github.com/nodejs/node/pull/1971) +* [[`a4f4909f3d`](https://github.com/nodejs/node/commit/a4f4909f3d)] - **module**: fix stat with long paths on Windows (Michaël Zasso) [#2013](https://github.com/nodejs/node/pull/2013) +* [[`a71ee93afe`](https://github.com/nodejs/node/commit/a71ee93afe)] - **module**: reduce syscalls during require search (Pierre Inglebert) [#1920](https://github.com/nodejs/node/pull/1920) +* [[`671e64ac73`](https://github.com/nodejs/node/commit/671e64ac73)] - **module**: allow long paths for require on Windows (Michaël Zasso) +* [[`061342a500`](https://github.com/nodejs/node/commit/061342a500)] - **net**: Defer reading until listeners could be added (James Hartig) [#1496](https://github.com/nodejs/node/pull/1496) +* [[`5d2b846d11`](https://github.com/nodejs/node/commit/5d2b846d11)] - **test**: assert tmp and fixture dirs different (Rich Trott) [#2015](https://github.com/nodejs/node/pull/2015) +* [[`b0990ef45d`](https://github.com/nodejs/node/commit/b0990ef45d)] - **test**: confirm symlink (Rich Trott) [#2014](https://github.com/nodejs/node/pull/2014) +* [[`3ba4f71fc4`](https://github.com/nodejs/node/commit/3ba4f71fc4)] - **test**: check result as early as possible (Rich Trott) [#2007](https://github.com/nodejs/node/pull/2007) +* [[`0abcf44d6b`](https://github.com/nodejs/node/commit/0abcf44d6b)] - **test**: add Buffer slice UTF-8 test (Rich Trott) [#1989](https://github.com/nodejs/node/pull/1989) +* [[`88c1831ff4`](https://github.com/nodejs/node/commit/88c1831ff4)] - **test**: tmpdir creation failures should fail tests (Rich Trott) [#1976](https://github.com/nodejs/node/pull/1976) +* [[`52a822d944`](https://github.com/nodejs/node/commit/52a822d944)] - **test**: fix test-cluster-worker-disconnect (Santiago Gimeno) [#1919](https://github.com/nodejs/node/pull/1919) +* [[`7c79490bfb`](https://github.com/nodejs/node/commit/7c79490bfb)] - **test**: only refresh tmpDir for tests that need it (Rich Trott) [#1954](https://github.com/nodejs/node/pull/1954) +* [[`88d7904c0b`](https://github.com/nodejs/node/commit/88d7904c0b)] - **test**: remove test repetition (Rich Trott) [#1874](https://github.com/nodejs/node/pull/1874) +* [[`91dfb5e094`](https://github.com/nodejs/node/commit/91dfb5e094)] - **tools**: make test-npm work without global npm (Jeremiah Senkpiel) [#1926](https://github.com/nodejs/node/pull/1926) +* [[`3777f41562`](https://github.com/nodejs/node/commit/3777f41562)] - **tools**: enable whitespace related rules in eslint (Roman Reiss) [#1971](https://github.com/nodejs/node/pull/1971) +* [[`626432d843`](https://github.com/nodejs/node/commit/626432d843)] - **util**: dont repeat isBuffer (Brendan Ashworth) [#1988](https://github.com/nodejs/node/pull/1988) +* [[`1d79f572f1`](https://github.com/nodejs/node/commit/1d79f572f1)] - **util**: move deprecate() to internal module (Brendan Ashworth) [#1988](https://github.com/nodejs/node/pull/1988) +* [[`4b4b1760b5`](https://github.com/nodejs/node/commit/4b4b1760b5)] - **v8**: cherry-pick uclibc build patch from upstream (Ben Noordhuis) [#1974](https://github.com/nodejs/node/pull/1974) +* [[`5d0cee46bb`](https://github.com/nodejs/node/commit/5d0cee46bb)] - **vm**: remove unnecessary HandleScopes (Ben Noordhuis) [#2001](https://github.com/nodejs/node/pull/2001) +* [[`0ecf9457b5`](https://github.com/nodejs/node/commit/0ecf9457b5)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) +* [[`953b3e75e8`](https://github.com/nodejs/node/commit/953b3e75e8)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) +* [[`3806d875d3`](https://github.com/nodejs/node/commit/3806d875d3)] - **zlib**: prevent uncaught exception in zlibBuffer (Michaël Zasso) [#1811](https://github.com/nodejs/node/pull/1811) + + + +## 2015-06-13, Version 2.3.0, @rvagg + +### Notable changes + +* **libuv**: Upgraded to 1.6.0 and 1.6.1, see [full ChangeLog](https://github.com/libuv/libuv/blob/60e515d9e6f3d86c0eedad583805201f32ea3aed/ChangeLog#L1-L36) for details. (Saúl Ibarra Corretgé) [#1905](https://github.com/nodejs/node/pull/1905) [#1889](https://github.com/nodejs/node/pull/1889). Highlights include: + - Fix TTY becoming blocked on OS X + - Fix UDP send callbacks to not to be synchronous + - Add `uv_os_homedir()` (exposed as `os.homedir()`, see below) +* **npm**: See full [release notes](https://github.com/npm/npm/releases/tag/v2.11.1) for details. (Kat Marchán) [#1899](https://github.com/nodejs/node/pull/1899). Highlight: + - Use GIT_SSH_COMMAND (available as of Git 2.3) +* **openssl**: + - Upgrade to 1.0.2b and 1.0.2c, introduces DHE man-in-the-middle protection (Logjam) and fixes malformed ECParameters causing infinite loop (CVE-2015-1788). See the [security advisory](https://www.openssl.org/news/secadv_20150611.txt) for full details. (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) [#1958](https://github.com/nodejs/node/pull/1958) + - Support [FIPS](https://en.wikipedia.org/wiki/Federal_Information_Processing_Standards) mode of OpenSSL, see [README](https://github.com/nodejs/node#building-iojs-with-fips-compliant-openssl) for instructions. (Fedor Indutny) [#1890](https://github.com/nodejs/node/pull/1890) +* **os**: Add `os.homedir()` method. (Colin Ihrig) [#1791](https://github.com/nodejs/node/pull/1791) +* **smalloc**: Deprecate whole module. (Vladimir Kurchatkin) [#1822](https://github.com/nodejs/node/pull/1822) +* Add new collaborators: + - Alex Kocharin ([@rlidwka](https://github.com/rlidwka)) + - Christopher Monsanto ([@monsanto](https://github.com/monsanto)) + - Ali Ijaz Sheikh ([@ofrobots](https://github.com/ofrobots)) + - Oleg Elifantiev ([@Olegas](https://github.com/Olegas)) + - Domenic Denicola ([@domenic](https://github.com/domenic)) + - Rich Trott ([@Trott](https://github.com/Trott)) + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +## Commits + +* [[`9c0a1b8cfc`](https://github.com/nodejs/node/commit/9c0a1b8cfc)] - **cluster**: wait on servers closing before disconnect (Oleg Elifantiev) [#1400](https://github.com/nodejs/node/pull/1400) +* [[`0f68377f69`](https://github.com/nodejs/node/commit/0f68377f69)] - **crypto**: support FIPS mode of OpenSSL (Fedor Indutny) [#1890](https://github.com/nodejs/node/pull/1890) +* [[`38d1afc24d`](https://github.com/nodejs/node/commit/38d1afc24d)] - **(SEMVER-MINOR)** **crypto**: add getCurves() to get supported ECs (Brian White) [#1914](https://github.com/nodejs/node/pull/1914) +* [[`a4dbf45b59`](https://github.com/nodejs/node/commit/a4dbf45b59)] - **crypto**: update root certificates (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) +* [[`81029c639a`](https://github.com/nodejs/node/commit/81029c639a)] - **debugger**: improve ESRCH error message (Jackson Tian) [#1863](https://github.com/nodejs/node/pull/1863) +* [[`2a7fd0ad32`](https://github.com/nodejs/node/commit/2a7fd0ad32)] - **deps**: update UPGRADING.md doc to openssl-1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) +* [[`6b3df929e0`](https://github.com/nodejs/node/commit/6b3df929e0)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) +* [[`664a659696`](https://github.com/nodejs/node/commit/664a659696)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`42a8de2ac6`](https://github.com/nodejs/node/commit/42a8de2ac6)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) +* [[`c66c3d9fa3`](https://github.com/nodejs/node/commit/c66c3d9fa3)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) +* [[`86737cf0a0`](https://github.com/nodejs/node/commit/86737cf0a0)] - **deps**: upgrade openssl sources to 1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) +* [[`94804969b7`](https://github.com/nodejs/node/commit/94804969b7)] - **deps**: update asm files for openssl-1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) +* [[`38444915e0`](https://github.com/nodejs/node/commit/38444915e0)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) +* [[`f62b613252`](https://github.com/nodejs/node/commit/f62b613252)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`f624d0122c`](https://github.com/nodejs/node/commit/f624d0122c)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) +* [[`dcd67cc8d7`](https://github.com/nodejs/node/commit/dcd67cc8d7)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) +* [[`c21b24decf`](https://github.com/nodejs/node/commit/c21b24decf)] - **deps**: upgrade openssl sources to 1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) +* [[`2dc819b09a`](https://github.com/nodejs/node/commit/2dc819b09a)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`f41b7f12b5`](https://github.com/nodejs/node/commit/f41b7f12b5)] - **deps**: upgrade to npm 2.11.1 (Kat Marchán) [#1899](https://github.com/nodejs/node/pull/1899) +* [[`a5bd466440`](https://github.com/nodejs/node/commit/a5bd466440)] - **deps**: update libuv to version 1.6.1 (Saúl Ibarra Corretgé) [#1905](https://github.com/nodejs/node/pull/1905) +* [[`aa33db3238`](https://github.com/nodejs/node/commit/aa33db3238)] - **deps**: update libuv to version 1.6.0 (Saúl Ibarra Corretgé) [#1889](https://github.com/nodejs/node/pull/1889) +* [[`0ee497f0b4`](https://github.com/nodejs/node/commit/0ee497f0b4)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`b5cd2f0986`](https://github.com/nodejs/node/commit/b5cd2f0986)] - **dgram**: partially revert 18d457b (Saúl Ibarra Corretgé) [#1889](https://github.com/nodejs/node/pull/1889) +* [[`a3cc43d0a4`](https://github.com/nodejs/node/commit/a3cc43d0a4)] - **doc**: add Trott as collaborator (Rich Trott) [#1962](https://github.com/nodejs/node/pull/1962) +* [[`cf5020fc02`](https://github.com/nodejs/node/commit/cf5020fc02)] - **doc**: add domenic as collaborator (Domenic Denicola) [#1942](https://github.com/nodejs/node/pull/1942) +* [[`11ed5f31ab`](https://github.com/nodejs/node/commit/11ed5f31ab)] - **doc**: add Olegas as collaborator (Oleg Elifantiev) [#1930](https://github.com/nodejs/node/pull/1930) +* [[`f500e1833b`](https://github.com/nodejs/node/commit/f500e1833b)] - **doc**: add ofrobots as collaborator (Ali Ijaz Sheikh) +* [[`717724611a`](https://github.com/nodejs/node/commit/717724611a)] - **doc**: add monsanto as collaborator (Christopher Monsanto) [#1932](https://github.com/nodejs/node/pull/1932) +* [[`7192b6688c`](https://github.com/nodejs/node/commit/7192b6688c)] - **doc**: add rlidwka as collaborator (Alex Kocharin) [#1929](https://github.com/nodejs/node/pull/1929) +* [[`9f3a03f0d4`](https://github.com/nodejs/node/commit/9f3a03f0d4)] - **doc**: add references to crypto.getCurves() (Roman Reiss) [#1918](https://github.com/nodejs/node/pull/1918) +* [[`ff39ecb914`](https://github.com/nodejs/node/commit/ff39ecb914)] - **doc**: remove comma splice (Rich Trott) [#1900](https://github.com/nodejs/node/pull/1900) +* [[`deb8b87dc9`](https://github.com/nodejs/node/commit/deb8b87dc9)] - **doc**: add note about available ECC curves (Ryan Petschek) [#1913](https://github.com/nodejs/node/pull/1913) +* [[`89a5b9040e`](https://github.com/nodejs/node/commit/89a5b9040e)] - **doc**: fix http.IncomingMessage.socket documentation (Сковорода Никита Андреевич) [#1867](https://github.com/nodejs/node/pull/1867) +* [[`d29034b34b`](https://github.com/nodejs/node/commit/d29034b34b)] - **doc**: adjust changelog to clarify `client` revert (Rod Vagg) [#1859](https://github.com/nodejs/node/pull/1859) +* [[`a79dece8ad`](https://github.com/nodejs/node/commit/a79dece8ad)] - **docs**: add return value for sync fs functions (Tyler Anton) [#1770](https://github.com/nodejs/node/pull/1770) +* [[`1cb72c14c4`](https://github.com/nodejs/node/commit/1cb72c14c4)] - **docs**: delete unused/duplicate css files (Robert Kowalski) [#1770](https://github.com/nodejs/node/pull/1770) +* [[`53a4eb3198`](https://github.com/nodejs/node/commit/53a4eb3198)] - **fs**: make SyncWriteStream non-enumerable (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) +* [[`a011c3243f`](https://github.com/nodejs/node/commit/a011c3243f)] - **fs**: minor refactoring (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) +* [[`8841132f30`](https://github.com/nodejs/node/commit/8841132f30)] - **fs**: remove inStatWatchers and use Map for lookup (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) +* [[`67a11b9bcc`](https://github.com/nodejs/node/commit/67a11b9bcc)] - **fs**: removing unnecessary nullCheckCallNT (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) +* [[`09f2a67bd8`](https://github.com/nodejs/node/commit/09f2a67bd8)] - **fs**: improve error message descriptions (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) +* [[`2dcef83b5f`](https://github.com/nodejs/node/commit/2dcef83b5f)] - **fs**: use `kMaxLength` from binding (Vladimir Kurchatkin) [#1903](https://github.com/nodejs/node/pull/1903) +* [[`353e26e3c7`](https://github.com/nodejs/node/commit/353e26e3c7)] - **(SEMVER-MINOR)** **fs**: Add string encoding option for Stream method (Yosuke Furukawa) [#1845](https://github.com/nodejs/node/pull/1845) +* [[`8357c5084b`](https://github.com/nodejs/node/commit/8357c5084b)] - **fs**: set encoding on fs.createWriteStream (Yosuke Furukawa) [#1844](https://github.com/nodejs/node/pull/1844) +* [[`02c345020a`](https://github.com/nodejs/node/commit/02c345020a)] - **gitignore**: don't ignore the debug npm module (Kat Marchán) [#1908](https://github.com/nodejs/node/pull/1908) +* [[`b5b8ff117c`](https://github.com/nodejs/node/commit/b5b8ff117c)] - **lib**: don't use global Buffer (Roman Reiss) [#1794](https://github.com/nodejs/node/pull/1794) +* [[`a251657058`](https://github.com/nodejs/node/commit/a251657058)] - **node**: mark promises as handled as soon as possible (Vladimir Kurchatkin) [#1952](https://github.com/nodejs/node/pull/1952) +* [[`2eb170874a`](https://github.com/nodejs/node/commit/2eb170874a)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) +* [[`a130132c8f`](https://github.com/nodejs/node/commit/a130132c8f)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) +* [[`6e78e5feaa`](https://github.com/nodejs/node/commit/6e78e5feaa)] - **(SEMVER-MINOR)** **os**: add homedir() (cjihrig) [#1791](https://github.com/nodejs/node/pull/1791) +* [[`d9e250295b`](https://github.com/nodejs/node/commit/d9e250295b)] - ***Revert*** "**readline**: allow tabs in input" (Jeremiah Senkpiel) [#1961](https://github.com/nodejs/node/pull/1961) +* [[`4b3d493c4b`](https://github.com/nodejs/node/commit/4b3d493c4b)] - **readline**: allow tabs in input (Rich Trott) [#1761](https://github.com/nodejs/node/pull/1761) +* [[`6d95f4ff92`](https://github.com/nodejs/node/commit/6d95f4ff92)] - **(SEMVER-MINOR)** **smalloc**: deprecate whole module (Vladimir Kurchatkin) [#1822](https://github.com/nodejs/node/pull/1822) +* [[`8c71a9241d`](https://github.com/nodejs/node/commit/8c71a9241d)] - **src**: hide InitializeICUDirectory symbol (Ben Noordhuis) [#1815](https://github.com/nodejs/node/pull/1815) +* [[`5b6f575c1f`](https://github.com/nodejs/node/commit/5b6f575c1f)] - ***Revert*** "**src**: add getopt option parser" (Evan Lucas) [#1862](https://github.com/nodejs/node/pull/1862) +* [[`c0e7bf2d8c`](https://github.com/nodejs/node/commit/c0e7bf2d8c)] - **src**: add getopt option parser (Evan Lucas) [#1804](https://github.com/nodejs/node/pull/1804) +* [[`8ea6844d26`](https://github.com/nodejs/node/commit/8ea6844d26)] - **test**: add test for failed save in REPL (Rich Trott) [#1818](https://github.com/nodejs/node/pull/1818) +* [[`03ce84dfa1`](https://github.com/nodejs/node/commit/03ce84dfa1)] - **test**: fix cluster-worker-wait-server-close races (Sam Roberts) [#1953](https://github.com/nodejs/node/pull/1953) +* [[`a6b8ee19b8`](https://github.com/nodejs/node/commit/a6b8ee19b8)] - **test**: create temp dir in common.js (Rich Trott) [#1877](https://github.com/nodejs/node/pull/1877) +* [[`ff8202c6f4`](https://github.com/nodejs/node/commit/ff8202c6f4)] - **test**: fix undeclared variable access (Roman Reiss) [#1794](https://github.com/nodejs/node/pull/1794) +* [[`d9ddd7d345`](https://github.com/nodejs/node/commit/d9ddd7d345)] - **test**: remove TODO comment (Rich Trott) [#1820](https://github.com/nodejs/node/pull/1820) +* [[`6537fd4b55`](https://github.com/nodejs/node/commit/6537fd4b55)] - **test**: remove TODO (Rich Trott) [#1875](https://github.com/nodejs/node/pull/1875) +* [[`a804026c9b`](https://github.com/nodejs/node/commit/a804026c9b)] - **test**: fix broken FreeBSD test (Santiago Gimeno) [#1881](https://github.com/nodejs/node/pull/1881) +* [[`43a82f8a71`](https://github.com/nodejs/node/commit/43a82f8a71)] - **test**: fix test-sync-io-option (Evan Lucas) [#1840](https://github.com/nodejs/node/pull/1840) +* [[`4ed25f664d`](https://github.com/nodejs/node/commit/4ed25f664d)] - **test**: add -no_rand_screen for tls-server-verify (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`4cf323d23d`](https://github.com/nodejs/node/commit/4cf323d23d)] - **test**: kill child in tls-server-verify for speed up (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`e6ccdcc1fe`](https://github.com/nodejs/node/commit/e6ccdcc1fe)] - **test**: improve console output of tls-server-verify (João Reis) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`975e5956f0`](https://github.com/nodejs/node/commit/975e5956f0)] - **test**: run tls-server-verify servers in parallel (João Reis) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`b18604ba2c`](https://github.com/nodejs/node/commit/b18604ba2c)] - **test**: running tls-server-verify clients in parallel (João Reis) [#1836](https://github.com/nodejs/node/pull/1836) +* [[`f78c722df5`](https://github.com/nodejs/node/commit/f78c722df5)] - **test**: remove hardwired references to 'iojs' (Rod Vagg) [#1882](https://github.com/nodejs/node/pull/1882) +* [[`bd99e8de8e`](https://github.com/nodejs/node/commit/bd99e8de8e)] - **test**: more test coverage for maxConnections (Rich Trott) [#1855](https://github.com/nodejs/node/pull/1855) +* [[`b9267189a5`](https://github.com/nodejs/node/commit/b9267189a5)] - **test**: fix test-child-process-stdout-flush-exit (Santiago Gimeno) [#1868](https://github.com/nodejs/node/pull/1868) +* [[`d20f018dcf`](https://github.com/nodejs/node/commit/d20f018dcf)] - **test**: loosen condition to detect infinite loop (Yosuke Furukawa) [#1857](https://github.com/nodejs/node/pull/1857) +* [[`e0e96acc6f`](https://github.com/nodejs/node/commit/e0e96acc6f)] - **test**: remove smalloc add-on test (Ben Noordhuis) [#1835](https://github.com/nodejs/node/pull/1835) +* [[`8704c58fc4`](https://github.com/nodejs/node/commit/8704c58fc4)] - **test**: remove unneeded comment task (Rich Trott) [#1858](https://github.com/nodejs/node/pull/1858) +* [[`8732977536`](https://github.com/nodejs/node/commit/8732977536)] - **tls**: fix references to undefined `cb` (Fedor Indutny) [#1951](https://github.com/nodejs/node/pull/1951) +* [[`75930bb38c`](https://github.com/nodejs/node/commit/75930bb38c)] - **tls**: prevent use-after-free (Fedor Indutny) [#1702](https://github.com/nodejs/node/pull/1702) +* [[`5795e835a1`](https://github.com/nodejs/node/commit/5795e835a1)] - **tls**: emit errors on close whilst async action (Fedor Indutny) [#1702](https://github.com/nodejs/node/pull/1702) +* [[`59d9734e21`](https://github.com/nodejs/node/commit/59d9734e21)] - **tls_wrap**: invoke queued callbacks in DestroySSL (Fedor Indutny) [#1702](https://github.com/nodejs/node/pull/1702) +* [[`6e4d30286d`](https://github.com/nodejs/node/commit/6e4d30286d)] - **tools**: enable/add additional eslint rules (Roman Reiss) [#1794](https://github.com/nodejs/node/pull/1794) +* [[`098354a9f8`](https://github.com/nodejs/node/commit/098354a9f8)] - **tools**: update certdata.txt (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) +* [[`a2d921d6a0`](https://github.com/nodejs/node/commit/a2d921d6a0)] - **tools**: customize mk-ca-bundle.pl (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) +* [[`5be9efca40`](https://github.com/nodejs/node/commit/5be9efca40)] - **tools**: update mk-ca-bundle.pl to HEAD of upstream (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) +* [[`1baba0580d`](https://github.com/nodejs/node/commit/1baba0580d)] - **tools**: Fix copying contents of deps/npm (thefourtheye) [#1853](https://github.com/nodejs/node/pull/1853) +* [[`628845b816`](https://github.com/nodejs/node/commit/628845b816)] - **(SEMVER-MINOR)** **util**: introduce `printDeprecationMessage` function (Vladimir Kurchatkin) [#1822](https://github.com/nodejs/node/pull/1822) +* [[`91d0a8b19c`](https://github.com/nodejs/node/commit/91d0a8b19c)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) + + + +## 2015-06-01, Version 2.2.1, @rvagg + +### Notable changes + +* **http**: Reverts the move of the `client` property of `IncomingMessage` to its prototype. Although undocumented, this property was used and assumed to be an "own property" in the wild, most notably by [request](https://github.com/request/request) which is used by npm. (Michaël Zasso) [#1852](https://github.com/nodejs/node/pull/1852). + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`c5a1009903`](https://github.com/nodejs/node/commit/c5a1009903)] - **build**: avoid passing empty strings to build flags (Johan Bergström) [#1789](https://github.com/nodejs/node/pull/1789) +* [[`5d83401086`](https://github.com/nodejs/node/commit/5d83401086)] - **doc**: put SEMVER-MINOR on pre-load module fix 2.2.0 (Rod Vagg) +* [[`4d6b768e5d`](https://github.com/nodejs/node/commit/4d6b768e5d)] - **http**: revert deprecation of client property (Michaël Zasso) [#1852](https://github.com/nodejs/node/pull/1852) + + + +## 2015-05-31, Version 2.2.0, @rvagg + +### Notable changes + +* **node**: Speed-up `require()` by replacing usage of `fs.statSync()` and `fs.readFileSync()` with internal variants that are faster for this use-case and do not create as many objects for the garbage collector to clean up. The primary two benefits are: significant increase in application start-up time on typical applications and better start-up time for the debugger by eliminating almost all of the thousands of exception events. (Ben Noordhuis) [#1801](https://github.com/nodejs/node/pull/1801). +* **node**: Resolution of pre-load modules (`-r` or `--require`) now follows the standard `require()` rules rather than just resolving paths, so you can now pre-load modules in node_modules. (Ali Ijaz Sheikh) [#1812](https://github.com/nodejs/node/pull/1812). +* **npm**: Upgraded npm to v2.11.0. New hooks for `preversion`, `version`, and `postversion` lifecycle events, some SPDX-related license changes and license file inclusions. See the [release notes](https://github.com/npm/npm/releases/tag/v2.11.0) for full details. + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`a77c330c32`](https://github.com/nodejs/node/commit/a77c330c32)] - **(SEMVER-MINOR)** **child_process**: expose ChildProcess constructor (Evan Lucas) [#1760](https://github.com/nodejs/node/pull/1760) +* [[`3a1bc067d4`](https://github.com/nodejs/node/commit/3a1bc067d4)] - ***Revert*** "**core**: set PROVIDER type as Persistent class id" (Ben Noordhuis) [#1827](https://github.com/nodejs/node/pull/1827) +* [[`f9fd554500`](https://github.com/nodejs/node/commit/f9fd554500)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`c1afa53648`](https://github.com/nodejs/node/commit/c1afa53648)] - **deps**: upgrade npm to 2.11.0 (Forrest L Norvell) [iojs/io.js#1829](https://github.com/iojs/io.js/pull/1829) +* [[`ff794498e7`](https://github.com/nodejs/node/commit/ff794498e7)] - **doc**: `fs.*File()` also accept encoding strings (Rich Trott) [#1806](https://github.com/nodejs/node/pull/1806) +* [[`98649fd31a`](https://github.com/nodejs/node/commit/98649fd31a)] - **doc**: add documentation for AtExit hook (Steve Sharp) [#1014](https://github.com/nodejs/node/pull/1014) +* [[`eb1856dfd1`](https://github.com/nodejs/node/commit/eb1856dfd1)] - **doc**: clarify stability of fs.watch and relatives (Rich Trott) [#1775](https://github.com/nodejs/node/pull/1775) +* [[`a74c2c9458`](https://github.com/nodejs/node/commit/a74c2c9458)] - **doc**: state url decoding behavior (Josh Gummersall) [#1731](https://github.com/nodejs/node/pull/1731) +* [[`ba76a9d872`](https://github.com/nodejs/node/commit/ba76a9d872)] - **doc**: remove bad semver-major entry from CHANGELOG (Rod Vagg) [#1782](https://github.com/nodejs/node/pull/1782) +* [[`a6a3f8c78d`](https://github.com/nodejs/node/commit/a6a3f8c78d)] - **doc**: fix changelog s/2.0.3/2.1.0 (Rod Vagg) +* [[`2c686fd3ce`](https://github.com/nodejs/node/commit/2c686fd3ce)] - **http**: flush stored header (Vladimir Kurchatkin) [#1695](https://github.com/nodejs/node/pull/1695) +* [[`1eec5f091a`](https://github.com/nodejs/node/commit/1eec5f091a)] - **http**: simplify code and remove unused properties (Brian White) [#1572](https://github.com/nodejs/node/pull/1572) +* [[`1bbf8d0720`](https://github.com/nodejs/node/commit/1bbf8d0720)] - **lib**: speed up require(), phase 2 (Ben Noordhuis) [#1801](https://github.com/nodejs/node/pull/1801) +* [[`b14fd1a720`](https://github.com/nodejs/node/commit/b14fd1a720)] - **lib**: speed up require(), phase 1 (Ben Noordhuis) [#1801](https://github.com/nodejs/node/pull/1801) +* [[`5abd4ac079`](https://github.com/nodejs/node/commit/5abd4ac079)] - **lib**: simplify nextTick() usage (Brian White) [#1612](https://github.com/nodejs/node/pull/1612) +* [[`5759722cfa`](https://github.com/nodejs/node/commit/5759722cfa)] - **(SEMVER-MINOR)** **src**: fix module search path for preload modules (Ali Ijaz Sheikh) [#1812](https://github.com/nodejs/node/pull/1812) +* [[`a65762cab6`](https://github.com/nodejs/node/commit/a65762cab6)] - **src**: remove old code (Brendan Ashworth) [#1819](https://github.com/nodejs/node/pull/1819) +* [[`93a44d5228`](https://github.com/nodejs/node/commit/93a44d5228)] - **src**: fix deferred events not working with -e (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) +* [[`8059393934`](https://github.com/nodejs/node/commit/8059393934)] - **test**: check error type from net.Server.listen() (Rich Trott) [#1821](https://github.com/nodejs/node/pull/1821) +* [[`4e90c82cdb`](https://github.com/nodejs/node/commit/4e90c82cdb)] - **test**: add heap profiler add-on regression test (Ben Noordhuis) [#1828](https://github.com/nodejs/node/pull/1828) +* [[`6dfca71af0`](https://github.com/nodejs/node/commit/6dfca71af0)] - **test**: don't lint autogenerated test/addons/doc-*/ (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) +* [[`c2b8b30836`](https://github.com/nodejs/node/commit/c2b8b30836)] - **test**: remove stray copyright notices (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) +* [[`280fb01daf`](https://github.com/nodejs/node/commit/280fb01daf)] - **test**: fix deprecation warning in addons test (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) +* [[`8606793999`](https://github.com/nodejs/node/commit/8606793999)] - **tools**: pass constant to logger instead of string (Johan Bergström) [#1842](https://github.com/nodejs/node/pull/1842) +* [[`fbd2b59716`](https://github.com/nodejs/node/commit/fbd2b59716)] - **tools**: add objectLiteralShorthandProperties to .eslintrc (Evan Lucas) [#1760](https://github.com/nodejs/node/pull/1760) +* [[`53e98cc1b4`](https://github.com/nodejs/node/commit/53e98cc1b4)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1763](https://github.com/nodejs/node/pull/1763) + + +## 2015-05-24, Version 2.1.0, @rvagg + +### Notable changes + +* **crypto**: Diffie-Hellman key exchange (DHE) parameters (`'dhparams'`) must now be 1024 bits or longer or an error will be thrown. A warning will also be printed to the console if you supply less than 2048 bits. See https://weakdh.org/ for further context on this security concern. (Shigeki Ohtsu) [#1739](https://github.com/nodejs/node/pull/1739). +* **node**: A new `--trace-sync-io` command line flag will print a warning and a stack trace whenever a synchronous API is used. This can be used to track down synchronous calls that may be slowing down an application. (Trevor Norris) [#1707](https://github.com/nodejs/node/pull/1707). +* **node**: To allow for chaining of methods, the `setTimeout()`, `setKeepAlive()`, `setNoDelay()`, `ref()` and `unref()` methods used in `'net'`, `'dgram'`, `'http'`, `'https'` and `'tls'` now return the current instance instead of `undefined` (Roman Reiss & Evan Lucas) [#1699](https://github.com/nodejs/node/pull/1699) [#1768](https://github.com/nodejs/node/pull/1768) [#1779](https://github.com/nodejs/node/pull/1779). +* **npm**: Upgraded to v2.10.1, release notes can be found in and . +* **util**: A significant speed-up (in the order of 35%) for the common-case of a single string argument to `util.format()`, used by `console.log()` (Сковорода Никита Андреевич) [#1749](https://github.com/nodejs/node/pull/1749). + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`9da168b71f`](https://github.com/nodejs/node/commit/9da168b71f)] - **buffer**: optimize Buffer.byteLength (Brendan Ashworth) [#1713](https://github.com/nodejs/node/pull/1713) +* [[`2b1c01c2cc`](https://github.com/nodejs/node/commit/2b1c01c2cc)] - **build**: refactor pkg-config for shared libraries (Johan Bergström) [#1603](https://github.com/nodejs/node/pull/1603) +* [[`3c44100558`](https://github.com/nodejs/node/commit/3c44100558)] - **core**: set PROVIDER type as Persistent class id (Trevor Norris) [#1730](https://github.com/nodejs/node/pull/1730) +* [[`c1de6d249e`](https://github.com/nodejs/node/commit/c1de6d249e)] - **(SEMVER-MINOR)** **core**: implement runtime flag to trace sync io (Trevor Norris) [#1707](https://github.com/nodejs/node/pull/1707) +* [[`9e7099fa4e`](https://github.com/nodejs/node/commit/9e7099fa4e)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) +* [[`c54d057598`](https://github.com/nodejs/node/commit/c54d057598)] - **deps**: upgrade to npm 2.10.1 (Rebecca Turner) [#1763](https://github.com/nodejs/node/pull/1763) +* [[`367ffd167d`](https://github.com/nodejs/node/commit/367ffd167d)] - **doc**: update AUTHORS list (Rod Vagg) [#1776](https://github.com/nodejs/node/pull/1776) +* [[`2bb2f06b3e`](https://github.com/nodejs/node/commit/2bb2f06b3e)] - **doc**: fix typo in CONTRIBUTING.md (Rich Trott) [#1755](https://github.com/nodejs/node/pull/1755) +* [[`515afc6367`](https://github.com/nodejs/node/commit/515afc6367)] - **doc**: path is ignored in url.format (Maurice Butler) [#1753](https://github.com/nodejs/node/pull/1753) +* [[`f0a8bc3f84`](https://github.com/nodejs/node/commit/f0a8bc3f84)] - **doc**: fix spelling in CHANGELOG (Felipe Batista) +* [[`86dd244d9b`](https://github.com/nodejs/node/commit/86dd244d9b)] - **doc**: add notes to child_process.fork() and .exec() (Rich Trott) [#1718](https://github.com/nodejs/node/pull/1718) +* [[`066274794c`](https://github.com/nodejs/node/commit/066274794c)] - **doc**: update links from iojs/io.js to nodejs/io.js (Frederic Hemberger) [#1715](https://github.com/nodejs/node/pull/1715) +* [[`cb381fe3e0`](https://github.com/nodejs/node/commit/cb381fe3e0)] - **(SEMVER-MINOR)** **net**: return this from setNoDelay and setKeepAlive (Roman Reiss) [#1779](https://github.com/nodejs/node/pull/1779) +* [[`85d9983009`](https://github.com/nodejs/node/commit/85d9983009)] - **net**: persist net.Socket options before connect (Evan Lucas) [#1518](https://github.com/nodejs/node/pull/1518) +* [[`39dde3222e`](https://github.com/nodejs/node/commit/39dde3222e)] - **(SEMVER-MINOR)** **net,dgram**: return this from ref and unref methods (Roman Reiss) [#1768](https://github.com/nodejs/node/pull/1768) +* [[`5773438913`](https://github.com/nodejs/node/commit/5773438913)] - **test**: fix jslint error (Michaël Zasso) [#1743](https://github.com/nodejs/node/pull/1743) +* [[`867631986f`](https://github.com/nodejs/node/commit/867631986f)] - **test**: fix test-sync-io-option (Santiago Gimeno) [#1734](https://github.com/nodejs/node/pull/1734) +* [[`f29762f4dd`](https://github.com/nodejs/node/commit/f29762f4dd)] - **test**: enable linting for tests (Roman Reiss) [#1721](https://github.com/nodejs/node/pull/1721) +* [[`2a71f02988`](https://github.com/nodejs/node/commit/2a71f02988)] - **tls**: emit errors happening before handshake finish (Malte-Thorben Bruns) [#1769](https://github.com/nodejs/node/pull/1769) +* [[`80342f649d`](https://github.com/nodejs/node/commit/80342f649d)] - **tls**: use `.destroy(err)` instead of destroy+emit (Fedor Indutny) [#1711](https://github.com/nodejs/node/pull/1711) +* [[`9b35be5810`](https://github.com/nodejs/node/commit/9b35be5810)] - **tls**: make server not use DHE in less than 1024bits (Shigeki Ohtsu) [#1739](https://github.com/nodejs/node/pull/1739) +* [[`214d02040e`](https://github.com/nodejs/node/commit/214d02040e)] - **util**: speed up common case of formatting string (Сковорода Никита Андреевич) [#1749](https://github.com/nodejs/node/pull/1749) +* [[`d144e96fbf`](https://github.com/nodejs/node/commit/d144e96fbf)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1763](https://github.com/nodejs/node/pull/1763) +* [[`0d6d3dda95`](https://github.com/nodejs/node/commit/0d6d3dda95)] - **win,node-gyp**: make delay-load hook C89 compliant (Sharat M R) [TooTallNate/node-gyp#616](https://github.com/TooTallNate/node-gyp/pull/616) + + +## 2015-05-17, Version 1.8.2, @rvagg + +**Maintenance release** + +## Notable changes + +* **crypto**: significantly reduced memory usage for TLS (Fedor Indutny & Сковорода Никита Андреевич) [#1529](https://github.com/nodejs/node/pull/1529) +* **npm**: Upgrade npm to 2.9.0. See the [v2.8.4](https://github.com/npm/npm/releases/tag/v2.8.4) and [v2.9.0](https://github.com/npm/npm/releases/tag/v2.9.0) release notes for details. Summary: + - Add support for default author field to make `npm init -y` work without user-input (@othiym23) [npm/npm/d8eee6cf9d](https://github.com/npm/npm/commit/d8eee6cf9d2ff7aca68dfaed2de76824a3e0d9 + - Include local modules in `npm outdated` and `npm update` (@ArnaudRinquin) [npm/npm#7426](https://github.com/npm/npm/issues/7426) + - The prefix used before the version number on `npm version` is now configurable via `tag-version-prefix` (@kkragenbrink) [npm/npm#8014](https://github.com/npm/npm/issues/8014) + +### Known issues + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). +* readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) + +### Commits + +* [[`5404cbc745`](https://github.com/nodejs/node/commit/5404cbc745)] - **buffer**: fix copy() segfault with zero arguments (Trevor Norris) [nodejs/node#1520](https://github.com/nodejs/node/pull/1520) +* [[`65dd10e9c0`](https://github.com/nodejs/node/commit/65dd10e9c0)] - **build**: remove -J from test-ci (Rod Vagg) [nodejs/node#1544](https://github.com/nodejs/node/pull/1544) +* [[`74060bb60e`](https://github.com/nodejs/node/commit/74060bb60e)] - **crypto**: track external memory for SSL structures (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) +* [[`f10f379240`](https://github.com/nodejs/node/commit/f10f379240)] - **deps**: make node-gyp work with io.js (cjihrig) [nodejs/node#990](https://github.com/nodejs/node/pull/990) +* [[`ba0e744c2c`](https://github.com/nodejs/node/commit/ba0e744c2c)] - **deps**: upgrade npm to 2.9.0 (Forrest L Norvell) [nodejs/node#1583](https://github.com/nodejs/node/pull/1583) +* [[`b3a7da1091`](https://github.com/nodejs/node/commit/b3a7da1091)] - **deps**: update http_parser to 2.5.0 (Fedor Indutny) [nodejs/node#1517](https://github.com/nodejs/node/pull/1517) +* [[`4030545af6`](https://github.com/nodejs/node/commit/4030545af6)] - **fs**: validate fd on fs.write (Julian Duque) [#1553](https://github.com/nodejs/node/pull/1553) +* [[`898d423820`](https://github.com/nodejs/node/commit/898d423820)] - **string_decoder**: don't cache Buffer.isEncoding (Brian White) [nodejs/node#1548](https://github.com/nodejs/node/pull/1548) +* [[`32a6dbcf23`](https://github.com/nodejs/node/commit/32a6dbcf23)] - **test**: extend timeouts for ARMv6 (Rod Vagg) [nodejs/node#1554](https://github.com/nodejs/node/pull/1554) +* [[`5896fe5cd3`](https://github.com/nodejs/node/commit/5896fe5cd3)] - **test**: adjust Makefile/test-ci, add to vcbuild.bat (Rod Vagg) [nodejs/node#1530](https://github.com/nodejs/node/pull/1530) +* [[`b72e4bc596`](https://github.com/nodejs/node/commit/b72e4bc596)] - **tls**: destroy singleUse context immediately (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) +* [[`1cfc455dc5`](https://github.com/nodejs/node/commit/1cfc455dc5)] - **tls**: zero SSL_CTX freelist for a singleUse socket (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) +* [[`7ada680519`](https://github.com/nodejs/node/commit/7ada680519)] - **tls**: destroy SSL once it is out of use (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) +* [[`71274b0263`](https://github.com/nodejs/node/commit/71274b0263)] - **tls_wrap**: use localhost if options.host is empty (Guilherme Souza) [nodejs/node#1493](https://github.com/nodejs/node/pull/1493) +* [[`0eb74a8b6c`](https://github.com/nodejs/node/commit/0eb74a8b6c)] - **win,node-gyp**: optionally allow node.exe/iojs.exe to be renamed (Bert Belder) [nodejs/node#1266](https://github.com/nodejs/node/pull/1266) + + +## 2015-05-15, Version 2.0.2, @Fishrock123 + +### Notable changes + +* **win,node-gyp**: the delay-load hook for windows addons has now been correctly enabled by default, it had wrongly defaulted to off in the release version of 2.0.0 (Bert Belder) [#1433](https://github.com/nodejs/node/pull/1433) +* **os**: `tmpdir()`'s trailing slash stripping has been refined to fix an issue when the temp directory is at '/'. Also considers which slash is used by the operating system. (cjihrig) [#1673](https://github.com/nodejs/node/pull/1673) +* **tls**: default ciphers have been updated to use gcm and aes128 (Mike MacCana) [#1660](https://github.com/nodejs/node/pull/1660) +* **build**: v8 snapshots have been re-enabled by default as suggested by the v8 team, since prior security issues have been resolved. This should give some perf improvements to both startup and vm context creation. (Trevor Norris) [#1663](https://github.com/nodejs/node/pull/1663) +* **src**: fixed preload modules not working when other flags were used before `--require` (Yosuke Furukawa) [#1694](https://github.com/nodejs/node/pull/1694) +* **dgram**: fixed `send()`'s callback not being asynchronous (Yosuke Furukawa) [#1313](https://github.com/nodejs/node/pull/1313) +* **readline**: emitKeys now keeps buffering data until it has enough to parse. This fixes an issue with parsing split escapes. (Alex Kocharin) [#1601](https://github.com/nodejs/node/pull/1601) +* **cluster**: works now properly emit 'disconnect' to `cluser.worker` (Oleg Elifantiev) [#1386](https://github.com/nodejs/node/pull/1386) +* **events**: uncaught errors now provide some context (Evan Lucas) [#1654](https://github.com/nodejs/node/pull/1654) + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). + +### Commits + +* [[`8a0e5295b4`](https://github.com/nodejs/node/commit/8a0e5295b4)] - **build**: use backslashes for paths on windows (Johan Bergström) [#1698](https://github.com/nodejs/node/pull/1698) +* [[`20c9a52227`](https://github.com/nodejs/node/commit/20c9a52227)] - **build**: move --with-intl to intl optgroup (Johan Bergström) [#1680](https://github.com/nodejs/node/pull/1680) +* [[`36cdc7c8ac`](https://github.com/nodejs/node/commit/36cdc7c8ac)] - **build**: re-enable V8 snapshots (Trevor Norris) [#1663](https://github.com/nodejs/node/pull/1663) +* [[`5883a59b21`](https://github.com/nodejs/node/commit/5883a59b21)] - **cluster**: disconnect event not emitted correctly (Oleg Elifantiev) [#1386](https://github.com/nodejs/node/pull/1386) +* [[`0f850f7ae7`](https://github.com/nodejs/node/commit/0f850f7ae7)] - **deps**: provide TXT chunk info in c-ares (Fedor Indutny) +* [[`7e1c0e75ed`](https://github.com/nodejs/node/commit/7e1c0e75ed)] - **deps**: sync with upstream bagder/c-ares@bba4dc5 (Ben Noordhuis) [#1678](https://github.com/nodejs/node/pull/1678) +* [[`18d457bd34`](https://github.com/nodejs/node/commit/18d457bd34)] - **dgram**: call send callback asynchronously (Yosuke Furukawa) [#1313](https://github.com/nodejs/node/pull/1313) +* [[`8b9a1537ad`](https://github.com/nodejs/node/commit/8b9a1537ad)] - **events**: provide better error message for unhandled error (Evan Lucas) [#1654](https://github.com/nodejs/node/pull/1654) +* [[`19ffb5cf1c`](https://github.com/nodejs/node/commit/19ffb5cf1c)] - **lib**: fix eslint styles (Yosuke Furukawa) [#1539](https://github.com/nodejs/node/pull/1539) +* [[`76937051f8`](https://github.com/nodejs/node/commit/76937051f8)] - **os**: refine tmpdir() trailing slash stripping (cjihrig) [#1673](https://github.com/nodejs/node/pull/1673) +* [[`aed6bce906`](https://github.com/nodejs/node/commit/aed6bce906)] - **readline**: turn emitKeys into a streaming parser (Alex Kocharin) [#1601](https://github.com/nodejs/node/pull/1601) +* [[`0a461e5360`](https://github.com/nodejs/node/commit/0a461e5360)] - **src**: fix preload when used with prior flags (Yosuke Furukawa) [#1694](https://github.com/nodejs/node/pull/1694) +* [[`931a0d4634`](https://github.com/nodejs/node/commit/931a0d4634)] - **src**: add type check to v8.setFlagsFromString() (Roman Klauke) [#1652](https://github.com/nodejs/node/pull/1652) +* [[`08d08668c9`](https://github.com/nodejs/node/commit/08d08668c9)] - **src,deps**: replace LoadLibrary by LoadLibraryW (Cheng Zhao) [#226](https://github.com/nodejs/node/pull/226) +* [[`4e2f999a62`](https://github.com/nodejs/node/commit/4e2f999a62)] - **test**: fix infinite loop detection (Yosuke Furukawa) [#1681](https://github.com/nodejs/node/pull/1681) +* [[`5755fc099f`](https://github.com/nodejs/node/commit/5755fc099f)] - **tls**: update default ciphers to use gcm and aes128 (Mike MacCana) [#1660](https://github.com/nodejs/node/pull/1660) +* [[`966acb9916`](https://github.com/nodejs/node/commit/966acb9916)] - **tools**: remove closure_linter to eslint on windows (Yosuke Furukawa) [#1685](https://github.com/nodejs/node/pull/1685) +* [[`c58264e58b`](https://github.com/nodejs/node/commit/c58264e58b)] - **tools**: make eslint work on subdirectories (Roman Reiss) [#1686](https://github.com/nodejs/node/pull/1686) +* [[`0b21ab13b7`](https://github.com/nodejs/node/commit/0b21ab13b7)] - **tools**: refactor `make test-npm` into test-npm.sh (Jeremiah Senkpiel) [#1662](https://github.com/nodejs/node/pull/1662) +* [[`f07b3b600b`](https://github.com/nodejs/node/commit/f07b3b600b)] - **tools**: set eslint comma-spacing to 'warn' (Roman Reiss) [#1672](https://github.com/nodejs/node/pull/1672) +* [[`f9dd34d301`](https://github.com/nodejs/node/commit/f9dd34d301)] - **tools**: replace closure-linter with eslint (Yosuke Furukawa) [#1539](https://github.com/nodejs/node/pull/1539) +* [[`64d3210c98`](https://github.com/nodejs/node/commit/64d3210c98)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1667](https://github.com/nodejs/node/issues/1667) + + +## 2015-05-07, Version 2.0.1, @rvagg + +### Notable changes + +* **async_wrap**: (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) + - it is now possible to filter by providers + - bit flags have been removed and replaced with method calls on the binding object + - _note that this is an unstable API so feature additions and breaking changes won't change io.js semver_ +* **libuv**: resolves numerous io.js issues: + - [#862](https://github.com/nodejs/node/issues/862) prevent spawning child processes with invalid stdio file descriptors + - [#1397](https://github.com/nodejs/node/issues/1397) fix EPERM error with fs.access(W_OK) on Windows + - [#1621](https://github.com/nodejs/node/issues/1621) build errors associated with the bundled libuv + - [#1512](https://github.com/nodejs/node/issues/1512) should properly fix Windows termination errors +* **addons**: the `NODE_DEPRECATED` macro was causing problems when compiling addons with older compilers, this should now be resolved (Ben Noordhuis) [#1626](https://github.com/nodejs/node/pull/1626) +* **V8**: upgrade V8 from 4.2.77.18 to 4.2.77.20 with minor fixes, including a bug preventing builds on FreeBSD + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). +* readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) + +### Commits + +* [[`7dde95a8bd`](https://github.com/nodejs/node/commit/7dde95a8bd)] - **async-wrap**: remove before/after calls in init (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) +* [[`bd42ba056a`](https://github.com/nodejs/node/commit/bd42ba056a)] - **async-wrap**: set flags using functions (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) +* [[`4b2c786449`](https://github.com/nodejs/node/commit/4b2c786449)] - **async-wrap**: pass PROVIDER as first arg to init (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) +* [[`84bf609fd2`](https://github.com/nodejs/node/commit/84bf609fd2)] - **async-wrap**: don't call init callback unnecessarily (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) +* [[`04cc03b029`](https://github.com/nodejs/node/commit/04cc03b029)] - **deps**: update libuv to 1.5.0 (Saúl Ibarra Corretgé) [#1646](https://github.com/nodejs/node/pull/1646) +* [[`b16d9c28e8`](https://github.com/nodejs/node/commit/b16d9c28e8)] - **deps**: upgrade v8 to 4.2.77.20 (Ben Noordhuis) [#1639](https://github.com/nodejs/node/pull/1639) +* [[`9ec3109272`](https://github.com/nodejs/node/commit/9ec3109272)] - **doc**: add TC meeting 2015-04-29 minutes (Rod Vagg) [#1585](https://github.com/nodejs/node/pull/1585) +* [[`2c7206254c`](https://github.com/nodejs/node/commit/2c7206254c)] - **doc**: fix typo in readme.md (AQNOUCH Mohammed) [#1643](https://github.com/nodejs/node/pull/1643) +* [[`71dc7152ee`](https://github.com/nodejs/node/commit/71dc7152ee)] - **doc**: fix PR link in CHANGELOG (Brian White) [#1624](https://github.com/nodejs/node/pull/1624) +* [[`b97b96d05a`](https://github.com/nodejs/node/commit/b97b96d05a)] - **install**: fix NameError (thefourtheye) [#1628](https://github.com/nodejs/node/pull/1628) +* [[`6ccbe75384`](https://github.com/nodejs/node/commit/6ccbe75384)] - **js_stream**: fix buffer index in DoWrite (Shigeki Ohtsu) [#1635](https://github.com/nodejs/node/pull/1635) +* [[`c43855c49c`](https://github.com/nodejs/node/commit/c43855c49c)] - **src**: export the ParseEncoding function on Windows (Ivan Kozik) [#1596](https://github.com/nodejs/node/pull/1596) +* [[`8315b22390`](https://github.com/nodejs/node/commit/8315b22390)] - **src**: fix pedantic cpplint whitespace warnings (Ben Noordhuis) [#1640](https://github.com/nodejs/node/pull/1640) +* [[`b712af79a7`](https://github.com/nodejs/node/commit/b712af79a7)] - **src**: fix NODE_DEPRECATED macro with old compilers (Ben Noordhuis) [#1626](https://github.com/nodejs/node/pull/1626) +* [[`2ed10f1349`](https://github.com/nodejs/node/commit/2ed10f1349)] - **src**: fix minor inefficiency in Buffer::New() call (Ben Noordhuis) [#1577](https://github.com/nodejs/node/pull/1577) +* [[`f696c9efab`](https://github.com/nodejs/node/commit/f696c9efab)] - **src**: fix deprecated use of Buffer::New() (Ben Noordhuis) [#1577](https://github.com/nodejs/node/pull/1577) +* [[`0c8f13df8f`](https://github.com/nodejs/node/commit/0c8f13df8f)] - **tools**: remove unused GuessWordSize function (thefourtheye) [#1638](https://github.com/nodejs/node/pull/1638) + + +## 2015-05-04, Version 2.0.0, @rvagg + +### Breaking changes + +Full details at https://github.com/nodejs/node/wiki/Breaking-Changes#200-from-1x + +* V8 upgrade to 4.2, minor changes to C++ API +* `os.tmpdir()` is now cross-platform consistent and no longer returns a path with a trailing slash on any platform +* While not a *breaking change* the 'smalloc' module has been deprecated in anticipation of it becoming unsupportable with a future upgrade to V8 4.4. See [#1451](https://github.com/nodejs/node/issues/1451) for further information. + +_Note: a new version of the 'url' module was reverted prior to release as it was decided the potential for breakage across the npm ecosystem was too great and that more compatibility work needed to be done before releasing it. See [#1602](https://github.com/nodejs/node/pull/1602) for further information._ + +### Notable changes + +* **crypto**: significantly reduced memory usage for TLS (Fedor Indutny & Сковорода Никита Андреевич) [#1529](https://github.com/nodejs/node/pull/1529) +* **net**: `socket.connect()` now accepts a `'lookup'` option for a custom DNS resolution mechanism, defaults to `dns.lookup()` (Evan Lucas) [#1505](https://github.com/nodejs/node/pull/1505) +* **npm**: Upgrade npm to 2.9.0. See the [v2.8.4](https://github.com/npm/npm/releases/tag/v2.8.4) and [v2.9.0](https://github.com/npm/npm/releases/tag/v2.9.0) release notes for details. Notable items: + - Add support for default author field to make `npm init -y` work without user-input (@othiym23) [npm/npm/d8eee6cf9d](https://github.com/npm/npm/commit/d8eee6cf9d2ff7aca68dfaed2de76824a3e0d9af) + - Include local modules in `npm outdated` and `npm update` (@ArnaudRinquin) [npm/npm#7426](https://github.com/npm/npm/issues/7426) + - The prefix used before the version number on `npm version` is now configurable via `tag-version-prefix` (@kkragenbrink) [npm/npm#8014](https://github.com/npm/npm/issues/8014) +* **os**: `os.tmpdir()` is now cross-platform consistent and will no longer returns a path with a trailing slash on any platform (Christian Tellnes) [#747](https://github.com/nodejs/node/pull/747) +* **process**: + - `process.nextTick()` performance has been improved by between 2-42% across the benchmark suite, notable because this is heavily used across core (Brian White) [#1571](https://github.com/nodejs/node/pull/1571) + - New `process.geteuid()`, `process.seteuid(id)`, `process.getegid()` and `process.setegid(id)` methods allow you to get and set effective UID and GID of the process (Evan Lucas) [#1536](https://github.com/nodejs/node/pull/1536) +* **repl**: + - REPL history can be persisted across sessions if the `NODE_REPL_HISTORY_FILE` environment variable is set to a user accessible file, `NODE_REPL_HISTORY_SIZE` can set the maximum history size and defaults to `1000` (Chris Dickinson) [#1513](https://github.com/nodejs/node/pull/1513) + - The REPL can be placed in to one of three modes using the `NODE_REPL_MODE` environment variable: `sloppy`, `strict` or `magic` (default); the new `magic` mode will automatically run "strict mode only" statements in strict mode (Chris Dickinson) [#1513](https://github.com/nodejs/node/pull/1513) +* **smalloc**: the 'smalloc' module has been deprecated due to changes coming in V8 4.4 that will render it unusable +* **util**: add Promise, Map and Set inspection support (Christopher Monsanto) [#1471](https://github.com/nodejs/node/pull/1471) +* **V8**: upgrade to 4.2.77.18, see the [ChangeLog](https://chromium.googlesource.com/v8/v8/+/refs/heads/4.2.77/ChangeLog) for full details. Notable items: + - Classes have moved out of staging; the `class` keyword is now usable in strict mode without flags + - Object literal enhancements have moved out of staging; shorthand method and property syntax is now usable (`{ method() { }, property }`) + - Rest parameters (`function(...args) {}`) are implemented in staging behind the `--harmony-rest-parameters` flag + - Computed property names (`{['foo'+'bar']:'bam'}`) are implemented in staging behind the `--harmony-computed-property-names` flag + - Unicode escapes (`'\u{xxxx}'`) are implemented in staging behind the `--harmony_unicode` flag and the `--harmony_unicode_regexps` flag for use in regular expressions +* **Windows**: + - Random process termination on Windows fixed (Fedor Indutny) [#1512](https://github.com/nodejs/node/issues/1512) / [#1563](https://github.com/nodejs/node/pull/1563) + - The delay-load hook introduced to fix issues with process naming (iojs.exe / node.exe) has been made opt-out for native add-ons. Native add-ons should include `'win_delay_load_hook': 'false'` in their binding.gyp to disable this feature if they experience problems . (Bert Belder) [#1433](https://github.com/nodejs/node/pull/1433) +* **Governance**: + - Rod Vagg (@rvagg) was added to the Technical Committee (TC) + - Jeremiah Senkpiel (@Fishrock123) was added to the Technical Committee (TC) + +### Known issues + +See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). +* readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) + +### Commits - * [[`52b1230628`](https://github.com/nodejs/node/commit/52b1230628)] - **deps**: update deps/openssl/conf/arch/*/opensslconf.h (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) - * [[`20ff1e2ecb`](https://github.com/nodejs/node/commit/20ff1e2ecb)] - **deps**: upgrade openssl sources to 1.0.2d (Shigeki Ohtsu) [#2141](https://github.com/nodejs/node/pull/2141) +* [[`5404cbc745`](https://github.com/nodejs/node/commit/5404cbc745)] - **buffer**: fix copy() segfault with zero arguments (Trevor Norris) [#1520](https://github.com/nodejs/node/pull/1520) +* [[`3d3083b91f`](https://github.com/nodejs/node/commit/3d3083b91f)] - **buffer**: little improve for Buffer.concat method (Jackson Tian) [#1437](https://github.com/nodejs/node/pull/1437) +* [[`e67542ae17`](https://github.com/nodejs/node/commit/e67542ae17)] - **build**: disable -Og when building with clang (Ben Noordhuis) [#1609](https://github.com/nodejs/node/pull/1609) +* [[`78f4b038f8`](https://github.com/nodejs/node/commit/78f4b038f8)] - **build**: turn on debug-safe optimizations with -Og (Ben Noordhuis) [#1569](https://github.com/nodejs/node/pull/1569) +* [[`a5dcff827a`](https://github.com/nodejs/node/commit/a5dcff827a)] - **build**: Use option groups in configure output (Johan Bergström) [#1533](https://github.com/nodejs/node/pull/1533) +* [[`2a3c8c187e`](https://github.com/nodejs/node/commit/2a3c8c187e)] - **build**: remove -J from test-ci (Rod Vagg) [#1544](https://github.com/nodejs/node/pull/1544) +* [[`e6874dd0f9`](https://github.com/nodejs/node/commit/e6874dd0f9)] - **crypto**: track external memory for SSL structures (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) +* [[`935c9d3fa7`](https://github.com/nodejs/node/commit/935c9d3fa7)] - **deps**: make node-gyp work with io.js (cjihrig) [#990](https://github.com/nodejs/node/pull/990) +* [[`56e4255382`](https://github.com/nodejs/node/commit/56e4255382)] - **deps**: upgrade npm to 2.9.0 (Forrest L Norvell) [#1573](https://github.com/nodejs/node/pull/1573) +* [[`509b59ea7c`](https://github.com/nodejs/node/commit/509b59ea7c)] - **deps**: enable v8 postmortem debugging again (Ben Noordhuis) [#1232](https://github.com/nodejs/node/pull/1232) +* [[`01652c7709`](https://github.com/nodejs/node/commit/01652c7709)] - **deps**: upgrade v8 to 4.2.77.18 (Chris Dickinson) [#1506](https://github.com/nodejs/node/pull/1506) +* [[`01e6632d70`](https://github.com/nodejs/node/commit/01e6632d70)] - **deps**: upgrade v8 to 4.2.77.15 (Ben Noordhuis) [#1399](https://github.com/nodejs/node/pull/1399) +* [[`db4ded5903`](https://github.com/nodejs/node/commit/db4ded5903)] - **deps**: enable v8 postmortem debugging again (Ben Noordhuis) [#1232](https://github.com/nodejs/node/pull/1232) +* [[`36cd5fb9d2`](https://github.com/nodejs/node/commit/36cd5fb9d2)] - **(SEMVER-MAJOR)** **deps**: upgrade v8 to 4.2.77.13 (Ben Noordhuis) [#1232](https://github.com/nodejs/node/pull/1232) +* [[`b3a7da1091`](https://github.com/nodejs/node/commit/b3a7da1091)] - **deps**: update http_parser to 2.5.0 (Fedor Indutny) [#1517](https://github.com/nodejs/node/pull/1517) +* [[`ac1fb39ce8`](https://github.com/nodejs/node/commit/ac1fb39ce8)] - **doc**: add rvagg to the TC (Rod Vagg) [#1613](https://github.com/nodejs/node/pull/1613) +* [[`dacc1fa35c`](https://github.com/nodejs/node/commit/dacc1fa35c)] - **doc**: update AUTHORS list (Rod Vagg) [#1586](https://github.com/nodejs/node/pull/1586) +* [[`2a3a1909ab`](https://github.com/nodejs/node/commit/2a3a1909ab)] - **doc**: add require() lines to child.stdio example (Nick Raienko) [#1504](https://github.com/nodejs/node/pull/1504) +* [[`02388dbf40`](https://github.com/nodejs/node/commit/02388dbf40)] - **doc**: fix some cross-references (Alexander Gromnitsky) [#1584](https://github.com/nodejs/node/pull/1584) +* [[`57c4cc26e2`](https://github.com/nodejs/node/commit/57c4cc26e2)] - **doc**: add TC meeting 2015-04-22 minutes (Rod Vagg) [#1556](https://github.com/nodejs/node/pull/1556) +* [[`b4ad5d7050`](https://github.com/nodejs/node/commit/b4ad5d7050)] - **doc**: improve http.request and https.request opts (Roman Reiss) [#1551](https://github.com/nodejs/node/pull/1551) +* [[`7dc8eec0a6`](https://github.com/nodejs/node/commit/7dc8eec0a6)] - **doc**: deprecate smalloc module (Ben Noordhuis) [#1566](https://github.com/nodejs/node/pull/1566) +* [[`1bcdf46ca7`](https://github.com/nodejs/node/commit/1bcdf46ca7)] - **doc**: add TC meeting 2015-04-15 minutes (Rod Vagg) [#1498](https://github.com/nodejs/node/pull/1498) +* [[`391cae3595`](https://github.com/nodejs/node/commit/391cae3595)] - **doc**: Add Known issues to v1.7.0/1.7.1 CHANGELOG (Yosuke Furukawa) [#1473](https://github.com/nodejs/node/pull/1473) +* [[`e55fdc47a7`](https://github.com/nodejs/node/commit/e55fdc47a7)] - **doc**: fix util.deprecate example (Nick Raienko) [#1535](https://github.com/nodejs/node/pull/1535) +* [[`5178f93bc0`](https://github.com/nodejs/node/commit/5178f93bc0)] - **doc**: Add Addon API (NAN) to working group list (Julian Duque) [#1523](https://github.com/nodejs/node/pull/1523) +* [[`f3cc50f811`](https://github.com/nodejs/node/commit/f3cc50f811)] - **doc**: add TC meeting 2015-04-08 minutes (Rod Vagg) [#1497](https://github.com/nodejs/node/pull/1497) +* [[`bb254b533b`](https://github.com/nodejs/node/commit/bb254b533b)] - **doc**: update branch to master (Roman Reiss) [#1511](https://github.com/nodejs/node/pull/1511) +* [[`22aafa5597`](https://github.com/nodejs/node/commit/22aafa5597)] - **doc**: add Fishrock123 to the TC (Jeremiah Senkpiel) [#1507](https://github.com/nodejs/node/pull/1507) +* [[`b16a328ede`](https://github.com/nodejs/node/commit/b16a328ede)] - **doc**: add spaces to child.kill example (Nick Raienko) [#1503](https://github.com/nodejs/node/pull/1503) +* [[`26327757f8`](https://github.com/nodejs/node/commit/26327757f8)] - **doc**: update AUTHORS list (Rod Vagg) [#1476](https://github.com/nodejs/node/pull/1476) +* [[`f9c681cf62`](https://github.com/nodejs/node/commit/f9c681cf62)] - **fs**: validate fd on fs.write (Julian Duque) [#1553](https://github.com/nodejs/node/pull/1553) +* [[`801b47acc5`](https://github.com/nodejs/node/commit/801b47acc5)] - **gitignore**: ignore xcode workspaces and projects (Roman Klauke) [#1562](https://github.com/nodejs/node/pull/1562) +* [[`d5ce47e433`](https://github.com/nodejs/node/commit/d5ce47e433)] - **(SEMVER-MINOR)** **lib**: deprecate the smalloc module (Ben Noordhuis) [#1564](https://github.com/nodejs/node/pull/1564) +* [[`7384ca83f9`](https://github.com/nodejs/node/commit/7384ca83f9)] - **module**: remove '' from Module.globalPaths (Chris Yip) [#1488](https://github.com/nodejs/node/pull/1488) +* [[`b4f5898395`](https://github.com/nodejs/node/commit/b4f5898395)] - **net**: ensure Write/ShutdownWrap references handle (Fedor Indutny) [#1590](https://github.com/nodejs/node/pull/1590) +* [[`4abe2fa1cf`](https://github.com/nodejs/node/commit/4abe2fa1cf)] - **(SEMVER-MINOR)** **net**: add lookup option to Socket.prototype.connect (Evan Lucas) [#1505](https://github.com/nodejs/node/pull/1505) +* [[`1bef717476`](https://github.com/nodejs/node/commit/1bef717476)] - **(SEMVER-MINOR)** **net**: cleanup connect logic (Evan Lucas) [#1505](https://github.com/nodejs/node/pull/1505) +* [[`c7782c0af8`](https://github.com/nodejs/node/commit/c7782c0af8)] - **node**: improve nextTick performance (Brian White) [#1571](https://github.com/nodejs/node/pull/1571) +* [[`b57cc51d8d`](https://github.com/nodejs/node/commit/b57cc51d8d)] - **(SEMVER-MAJOR)** **os**: remove trailing slash from os.tmpdir() (Christian Tellnes) [#747](https://github.com/nodejs/node/pull/747) +* [[`ca219b00d1`](https://github.com/nodejs/node/commit/ca219b00d1)] - **repl**: fix for a+ fd clearing the file on read (Chris Dickinson) [#1605](https://github.com/nodejs/node/pull/1605) +* [[`051d482b15`](https://github.com/nodejs/node/commit/051d482b15)] - **repl**: fix \_debugger by properly proxying repl (Chris Dickinson) [#1605](https://github.com/nodejs/node/pull/1605) +* [[`2e2fce0502`](https://github.com/nodejs/node/commit/2e2fce0502)] - **repl**: fix persistent history and env variable name (Roman Reiss) [#1593](https://github.com/nodejs/node/pull/1593) +* [[`ea5195ccaf`](https://github.com/nodejs/node/commit/ea5195ccaf)] - **repl**: do not save history for non-terminal repl (Fedor Indutny) [#1575](https://github.com/nodejs/node/pull/1575) +* [[`0450ce7db2`](https://github.com/nodejs/node/commit/0450ce7db2)] - **repl**: add mode detection, cli persistent history (Chris Dickinson) [#1513](https://github.com/nodejs/node/pull/1513) +* [[`af9fe3bbc7`](https://github.com/nodejs/node/commit/af9fe3bbc7)] - **(SEMVER-MAJOR)** **src**: bump NODE_MODULE_VERSION due to V8 API (Rod Vagg) [#1532](https://github.com/nodejs/node/pull/1532) +* [[`279f6116aa`](https://github.com/nodejs/node/commit/279f6116aa)] - **src**: fix -Wmissing-field-initializers warning (Ben Noordhuis) [#1606](https://github.com/nodejs/node/pull/1606) +* [[`73062521a4`](https://github.com/nodejs/node/commit/73062521a4)] - **src**: deprecate smalloc public functions (Ben Noordhuis) [#1565](https://github.com/nodejs/node/pull/1565) +* [[`ccb199af17`](https://github.com/nodejs/node/commit/ccb199af17)] - **src**: fix deprecation warnings (Ben Noordhuis) [#1565](https://github.com/nodejs/node/pull/1565) +* [[`609fa0de03`](https://github.com/nodejs/node/commit/609fa0de03)] - **src**: fix NODE_DEPRECATED macro (Ben Noordhuis) [#1565](https://github.com/nodejs/node/pull/1565) +* [[`3c92ca2b5c`](https://github.com/nodejs/node/commit/3c92ca2b5c)] - **(SEMVER-MINOR)** **src**: add ability to get/set effective uid/gid (Evan Lucas) [#1536](https://github.com/nodejs/node/pull/1536) +* [[`30b7349176`](https://github.com/nodejs/node/commit/30b7349176)] - **stream_base**: dispatch reqs in the stream impl (Fedor Indutny) [#1563](https://github.com/nodejs/node/pull/1563) +* [[`0fa6c4a6fc`](https://github.com/nodejs/node/commit/0fa6c4a6fc)] - **string_decoder**: don't cache Buffer.isEncoding (Brian White) [#1548](https://github.com/nodejs/node/pull/1548) +* [[`f9b226c1c1`](https://github.com/nodejs/node/commit/f9b226c1c1)] - **test**: extend timeouts for ARMv6 (Rod Vagg) [#1554](https://github.com/nodejs/node/pull/1554) +* [[`bfae8236b1`](https://github.com/nodejs/node/commit/bfae8236b1)] - **test**: fix test-net-dns-custom-lookup test assertion (Evan Lucas) [#1531](https://github.com/nodejs/node/pull/1531) +* [[`547213913b`](https://github.com/nodejs/node/commit/547213913b)] - **test**: adjust Makefile/test-ci, add to vcbuild.bat (Rod Vagg) [#1530](https://github.com/nodejs/node/pull/1530) +* [[`550c2638c0`](https://github.com/nodejs/node/commit/550c2638c0)] - **tls**: use `SSL_set_cert_cb` for async SNI/OCSP (Fedor Indutny) [#1464](https://github.com/nodejs/node/pull/1464) +* [[`1787416376`](https://github.com/nodejs/node/commit/1787416376)] - **tls**: destroy singleUse context immediately (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) +* [[`2684c902c4`](https://github.com/nodejs/node/commit/2684c902c4)] - **tls**: zero SSL_CTX freelist for a singleUse socket (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) +* [[`2d241b3b82`](https://github.com/nodejs/node/commit/2d241b3b82)] - **tls**: destroy SSL once it is out of use (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) +* [[`f7620fb96d`](https://github.com/nodejs/node/commit/f7620fb96d)] - **tls_wrap**: Unlink TLSWrap and SecureContext objects (Сковорода Никита Андреевич) [#1580](https://github.com/nodejs/node/pull/1580) +* [[`a7d74633f2`](https://github.com/nodejs/node/commit/a7d74633f2)] - **tls_wrap**: use localhost if options.host is empty (Guilherme Souza) [#1493](https://github.com/nodejs/node/pull/1493) +* [[`702997c1f0`](https://github.com/nodejs/node/commit/702997c1f0)] - ***Revert*** "**url**: significantly improve the performance of the url module" (Rod Vagg) [#1602](https://github.com/nodejs/node/pull/1602) +* [[`0daed24883`](https://github.com/nodejs/node/commit/0daed24883)] - ***Revert*** "**url**: delete href cache on all setter code paths" (Rod Vagg) [#1602](https://github.com/nodejs/node/pull/1602) +* [[`0f39ef4ca1`](https://github.com/nodejs/node/commit/0f39ef4ca1)] - ***Revert*** "**url**: fix treatment of some values as non-empty" (Rod Vagg) [#1602](https://github.com/nodejs/node/pull/1602) +* [[`66877216bd`](https://github.com/nodejs/node/commit/66877216bd)] - **url**: fix treatment of some values as non-empty (Petka Antonov) [#1589](https://github.com/nodejs/node/pull/1589) +* [[`dbdd81a91b`](https://github.com/nodejs/node/commit/dbdd81a91b)] - **url**: delete href cache on all setter code paths (Petka Antonov) [#1589](https://github.com/nodejs/node/pull/1589) +* [[`3fd7fc429c`](https://github.com/nodejs/node/commit/3fd7fc429c)] - **url**: significantly improve the performance of the url module (Petka Antonov) [#1561](https://github.com/nodejs/node/pull/1561) +* [[`bf7ac08dd0`](https://github.com/nodejs/node/commit/bf7ac08dd0)] - **util**: add Map and Set inspection support (Christopher Monsanto) [#1471](https://github.com/nodejs/node/pull/1471) +* [[`30e83d2e84`](https://github.com/nodejs/node/commit/30e83d2e84)] - **win,node-gyp**: optionally allow node.exe/iojs.exe to be renamed (Bert Belder) [#1266](https://github.com/nodejs/node/pull/1266) +* [[`3bda6cbfa4`](https://github.com/nodejs/node/commit/3bda6cbfa4)] - **(SEMVER-MAJOR)** **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1433](https://github.com/nodejs/node/pull/1433) + + + +## 2015-04-20, Version 1.8.1, @chrisdickinson +### Notable changes + +* **NOTICE**: Skipped v1.8.0 due to problems with release tooling. + See [#1436](https://github.com/nodejs/node/issues/1436) for details. +* **build**: Support for building io.js as a static library (Marat Abdullin) [#1341](https://github.com/nodejs/node/pull/1341) +* **deps**: Upgrade openssl to 1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) + * Users should see performance improvements when using the crypto API. + See [here](https://github.com/nodejs/node/wiki/Crypto-Performance-Notes-for-OpenSSL-1.0.2a-on-iojs-v1.8.0) + for details. +* **npm**: Upgrade npm to 2.8.3. See the [release notes](https://github.com/npm/npm/releases/tag/v2.8.3) for details. Includes improved git support. Summary: + * [`387f889`](https://github.com/npm/npm/commit/387f889c0e8fb617d9cc9a42ed0a3ec49424ab5d) + [#7961](https://github.com/npm/npm/issues/7961) Ensure that hosted git SSH + URLs always have a valid protocol when stored in `resolved` fields in + `npm-shrinkwrap.json`. ([@othiym23](https://github.com/othiym23)) + * [`394c2f5`](https://github.com/npm/npm/commit/394c2f5a1227232c0baf42fbba1402aafe0d6ffb) + Switch the order in which hosted Git providers are checked to `git:`, + `git+https:`, then `git+ssh:` (from `git:`, `git+ssh:`, then `git+https:`) in + an effort to go from most to least likely to succeed, to make for less + confusing error message. ([@othiym23](https://github.com/othiym23)) + * [`431c3bf`](https://github.com/npm/npm/commit/431c3bf6cdec50f9f0c735f478cb2f3f337d3313) + [#7699](https://github.com/npm/npm/issues/7699) `npm-registry-client@6.3.2`: + Don't send body with HTTP GET requests when logging in. + ([@smikes](https://github.com/smikes)) + * [`15efe12`](https://github.com/npm/npm/commit/15efe124753257728a0ddc64074fa5a4b9c2eb30) + [#7872](https://github.com/npm/npm/issues/7872) Use the new version of + `hosted-git-info` to pass along credentials embedded in git URLs. Test it. + Test it a lot. ([@othiym23](https://github.com/othiym23)) + * [`b027319`](https://github.com/npm/npm/commit/b0273190c71eba14395ddfdd1d9f7ba625297523) + [#7920](https://github.com/npm/npm/issues/7920) Scoped packages with + `peerDependencies` were installing the `peerDependencies` into the wrong + directory. ([@ewie](https://github.com/ewie)) + * [`6b0f588`](https://github.com/npm/npm/commit/6b0f58877f37df9904490ffbaaad33862bd36dce) + [#7867](https://github.com/npm/npm/issues/7867) Use git shorthand and git + URLs as presented by user. Support new `hosted-git-info` shortcut syntax. + Save shorthand in `package.json`. Try cloning via `git:`, `git+ssh:`, and + `git+https:`, in that order, when supported by the underlying hosting + provider. ([@othiym23](https://github.com/othiym23)) +* **src**: Allow multiple arguments to be passed to process.nextTick (Trevor Norris) [#1077](https://github.com/nodejs/node/pull/1077) +* **module**: The interaction of `require('.')` with `NODE_PATH` has been restored and deprecated. This functionality +will be removed at a later point. (Roman Reiss) [#1363](https://github.com/nodejs/node/pull/1363) + +### Known issues + +* Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). +* Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) +* `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) +* Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) +* `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). +* readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) + +### Commits - - ## 2015-07-04, Version 2.3.3, @Fishrock123 - - ### Notable changes - - * **deps**: Fixed an out-of-band write in utf8 decoder. **This is an important security update** as it can be used to cause a denial of service attack. - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal. [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760). - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion. [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ## Commits - - * [[`030f8045c7`](https://github.com/nodejs/node/commit/030f8045c7)] - **deps**: fix out-of-band write in utf8 decoder (Fedor Indutny) - * [[`0f09b8db28`](https://github.com/nodejs/node/commit/0f09b8db28)] - **doc**: don't recommend domains for error handling (Benjamin Gruenbaum) [#2056](https://github.com/nodejs/node/pull/2056) - * [[`9cd44bb2b6`](https://github.com/nodejs/node/commit/9cd44bb2b6)] - **util**: prepend '(node) ' to deprecation messages (Sakthipriyan Vairamani) [#1892](https://github.com/nodejs/node/pull/1892) - - - - ## 2015-07-04, Version 1.8.3, @rvagg - - **Maintenance release** - - ## Notable changes - - * **v8**: Fixed an out-of-band write in utf8 decoder. **This is an important security update** as it can be used to cause a denial of service attack. - * **openssl**: Upgrade to 1.0.2b and 1.0.2c, introduces DHE man-in-the-middle protection (Logjam) and fixes malformed ECParameters causing infinite loop (CVE-2015-1788). See the [security advisory](https://www.openssl.org/news/secadv_20150611.txt) for full details. (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) [#1958](https://github.com/nodejs/node/pull/1958) - * **build**: - - Added support for compiling with Microsoft Visual C++ 2015 - - Started building and distributing headers-only tarballs along with binaries - - ### Known issues - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - * readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) - - ### Commits - - * [[`d8f260d33b`](https://github.com/nodejs/node/commit/d8f260d33b)] - **build**: add tar-headers target for headers-only tar (Rod Vagg) [#1975](https://github.com/nodejs/node/pull/1975) - * [[`00ba429674`](https://github.com/nodejs/node/commit/00ba429674)] - **build**: update build targets for io.js (Rod Vagg) [#1938](https://github.com/nodejs/node/pull/1938) - * [[`39e2207ff1`](https://github.com/nodejs/node/commit/39e2207ff1)] - **build**: fix cherry-pick ooops, fix comment wording (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) - * [[`561919a67a`](https://github.com/nodejs/node/commit/561919a67a)] - **build**: add MSVS 2015 support (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) - * [[`8e1134c04c`](https://github.com/nodejs/node/commit/8e1134c04c)] - **build**: remove lint from test-ci on windows (Johan Bergström) [#2004](https://github.com/nodejs/node/pull/2004) - * [[`e52e99085e`](https://github.com/nodejs/node/commit/e52e99085e)] - **build**: don't run lint from test-ci (Johan Bergström) [#1965](https://github.com/nodejs/node/pull/1965) - * [[`c5d1ec7fea`](https://github.com/nodejs/node/commit/c5d1ec7fea)] - **build**: simplify execution of built binary (Johan Bergström) [#1955](https://github.com/nodejs/node/pull/1955) - * [[`2ce147551a`](https://github.com/nodejs/node/commit/2ce147551a)] - **build,win**: set env before generating projects (Alexis Campailla) [joyent/node#20109](https://github.com/joyent/node/pull/20109) - * [[`78de5f85f2`](https://github.com/nodejs/node/commit/78de5f85f2)] - **deps**: fix out-of-band write in utf8 decoder (Ben Noordhuis) - * [[`83ee07b6be`](https://github.com/nodejs/node/commit/83ee07b6be)] - **deps**: copy all openssl header files to include dir (Shigeki Ohtsu) [#2016](https://github.com/nodejs/node/pull/2016) - * [[`a97125520d`](https://github.com/nodejs/node/commit/a97125520d)] - **deps**: update UPGRADING.md doc to openssl-1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) - * [[`0e2d068e0b`](https://github.com/nodejs/node/commit/0e2d068e0b)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) - * [[`310b8d1120`](https://github.com/nodejs/node/commit/310b8d1120)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`a472946747`](https://github.com/nodejs/node/commit/a472946747)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) - * [[`b2467e3ebf`](https://github.com/nodejs/node/commit/b2467e3ebf)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) - * [[`e548abb800`](https://github.com/nodejs/node/commit/e548abb800)] - **deps**: upgrade openssl sources to 1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) - * [[`1feaa68e85`](https://github.com/nodejs/node/commit/1feaa68e85)] - **deps**: update asm files for openssl-1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) - * [[`151720fae7`](https://github.com/nodejs/node/commit/151720fae7)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) - * [[`139da6a02a`](https://github.com/nodejs/node/commit/139da6a02a)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`283642827a`](https://github.com/nodejs/node/commit/283642827a)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) - * [[`d593b552de`](https://github.com/nodejs/node/commit/d593b552de)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) - * [[`2a3367a4bd`](https://github.com/nodejs/node/commit/2a3367a4bd)] - **deps**: upgrade openssl sources to 1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) - * [[`5c29c0c519`](https://github.com/nodejs/node/commit/5c29c0c519)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) - * [[`2cd7f73d9f`](https://github.com/nodejs/node/commit/2cd7f73d9f)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [nodejs/node#1389](https://github.com/nodejs/node/pull/1389) - * [[`c65484a74d`](https://github.com/nodejs/node/commit/c65484a74d)] - **tls**: make server not use DHE in less than 1024bits (Shigeki Ohtsu) [#1739](https://github.com/nodejs/node/pull/1739) - * [[`77f518403f`](https://github.com/nodejs/node/commit/77f518403f)] - **win,node-gyp**: make delay-load hook C89 compliant (Sharat M R) [TooTallNate/node-gyp#616](https://github.com/TooTallNa - - - - ## 2015-07-01, Version 2.3.2, @rvagg - - ### Notable changes - - * **build**: - - Added support for compiling with Microsoft Visual C++ 2015 - - Started building and distributing headers-only tarballs along with binaries - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ## Commits - - * [[`9180140231`](https://github.com/nodejs/node/commit/9180140231)] - **_stream_wrap**: prevent use after free in TLS (Fedor Indutny) [#1910](https://github.com/nodejs/node/pull/1910) - * [[`05a73c0f25`](https://github.com/nodejs/node/commit/05a73c0f25)] - **benchmark**: make concurrent requests configurable (Rich Trott) [#2068](https://github.com/nodejs/node/pull/2068) - * [[`f52d73352e`](https://github.com/nodejs/node/commit/f52d73352e)] - **benchmark**: fix typo in README (Rich Trott) [#2067](https://github.com/nodejs/node/pull/2067) - * [[`1cd9eeb556`](https://github.com/nodejs/node/commit/1cd9eeb556)] - **buffer**: prevent abort on bad proto (Trevor Norris) [#2012](https://github.com/nodejs/node/pull/2012) - * [[`8350f3a3a2`](https://github.com/nodejs/node/commit/8350f3a3a2)] - **buffer**: optimize Buffer#toString() (Ben Noordhuis) [#2027](https://github.com/nodejs/node/pull/2027) - * [[`628a3ab093`](https://github.com/nodejs/node/commit/628a3ab093)] - **build**: add tar-headers target for headers-only tar (Rod Vagg) [#1975](https://github.com/nodejs/node/pull/1975) - * [[`dcbb9e1da6`](https://github.com/nodejs/node/commit/dcbb9e1da6)] - **build**: update build targets for io.js (Rod Vagg) [#1938](https://github.com/nodejs/node/pull/1938) - * [[`c87c34c242`](https://github.com/nodejs/node/commit/c87c34c242)] - **build**: fix cherry-pick ooops, fix comment wording (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) - * [[`4208dc4fef`](https://github.com/nodejs/node/commit/4208dc4fef)] - **build**: add MSVS 2015 support (Rod Vagg) [#2036](https://github.com/nodejs/node/pull/2036) - * [[`834a365113`](https://github.com/nodejs/node/commit/834a365113)] - **build**: DTrace is enabled by default on darwin (Evan Lucas) [#2019](https://github.com/nodejs/node/pull/2019) - * [[`c0c0d73269`](https://github.com/nodejs/node/commit/c0c0d73269)] - **build,win**: set env before generating projects (Alexis Campailla) [joyent/node#20109](https://github.com/joyent/node/pull/20109) - * [[`9e890fe8b4`](https://github.com/nodejs/node/commit/9e890fe8b4)] - **crypto**: fix VerifyCallback in case of verify error (Shigeki Ohtsu) [#2064](https://github.com/nodejs/node/pull/2064) - * [[`1f371e3988`](https://github.com/nodejs/node/commit/1f371e3988)] - **deps**: copy all openssl header files to include dir (Shigeki Ohtsu) [#2016](https://github.com/nodejs/node/pull/2016) - * [[`c370bd3aea`](https://github.com/nodejs/node/commit/c370bd3aea)] - **doc**: make the abbreviation 1MM clear (Ivan Yan) [#2053](https://github.com/nodejs/node/pull/2053) - * [[`54d5437566`](https://github.com/nodejs/node/commit/54d5437566)] - **doc**: Added sample command to test iojs build (Jimmy Hsu) [#850](https://github.com/nodejs/node/pull/850) - * [[`f1f1b7e597`](https://github.com/nodejs/node/commit/f1f1b7e597)] - **doc**: add TSC meeting minutes 2015-06-17 (Rod Vagg) [#2048](https://github.com/nodejs/node/pull/2048) - * [[`dbd5dc932d`](https://github.com/nodejs/node/commit/dbd5dc932d)] - **doc**: clarify prerequisites in benchmark/README.md (Jeremiah Senkpiel) [#2034](https://github.com/nodejs/node/pull/2034) - * [[`50dbc8e143`](https://github.com/nodejs/node/commit/50dbc8e143)] - **doc**: add TSC meeting minutes 2015-05-27 (Rod Vagg) [#2037](https://github.com/nodejs/node/pull/2037) - * [[`941ad362a7`](https://github.com/nodejs/node/commit/941ad362a7)] - **doc**: archive io.js TC minutes (Rod Vagg) - * [[`644b2eaa89`](https://github.com/nodejs/node/commit/644b2eaa89)] - **doc**: rename tc-meetings to tsc-meetings (Rod Vagg) - * [[`1330ee3b27`](https://github.com/nodejs/node/commit/1330ee3b27)] - **doc**: add TC meeting 2015-05-13 minutes (Rod Vagg) [#1700](https://github.com/nodejs/node/pull/1700) - * [[`392e8fd64e`](https://github.com/nodejs/node/commit/392e8fd64e)] - **doc**: add @shigeki and @mscdex to TC (Rod Vagg) [#2008](https://github.com/nodejs/node/pull/2008) - * [[`af249fa8a1`](https://github.com/nodejs/node/commit/af249fa8a1)] - **net**: wrap connect in nextTick (Evan Lucas) [#2054](https://github.com/nodejs/node/pull/2054) - * [[`7f63449fde`](https://github.com/nodejs/node/commit/7f63449fde)] - **net**: fix debug for dnsopts (Evan Lucas) [#2059](https://github.com/nodejs/node/pull/2059) - * [[`eabed2f518`](https://github.com/nodejs/node/commit/eabed2f518)] - **repl**: remove obsolete TODO (Rich Trott) [#2081](https://github.com/nodejs/node/pull/2081) - * [[`a198c68b56`](https://github.com/nodejs/node/commit/a198c68b56)] - **repl**: make 'Unexpected token' errors recoverable (Julien Gilli) [#2052](https://github.com/nodejs/node/pull/2052) - * [[`d735b2c6ef`](https://github.com/nodejs/node/commit/d735b2c6ef)] - **repl**: fix tab completion for a non-global context (Sangmin Yoon) [#2052](https://github.com/nodejs/node/pull/2052) - * [[`8cee8f54fc`](https://github.com/nodejs/node/commit/8cee8f54fc)] - **src**: nix stdin _readableState.reading manipulation (Chris Dickinson) [#454](https://github.com/nodejs/node/pull/454) - * [[`856c11f8c8`](https://github.com/nodejs/node/commit/856c11f8c8)] - **test**: purge stale disabled tests (Rich Trott) [#2045](https://github.com/nodejs/node/pull/2045) - * [[`4d5089e181`](https://github.com/nodejs/node/commit/4d5089e181)] - **test**: do not swallow OpenSSL support error (Rich Trott) [#2042](https://github.com/nodejs/node/pull/2042) - * [[`06721fe005`](https://github.com/nodejs/node/commit/06721fe005)] - **test**: fix test-repl-tab-complete.js (cjihrig) [#2052](https://github.com/nodejs/node/pull/2052) - * [[`8e9089ac35`](https://github.com/nodejs/node/commit/8e9089ac35)] - **test**: check for error on Windows (Rich Trott) [#2035](https://github.com/nodejs/node/pull/2035) - * [[`776a65ebcd`](https://github.com/nodejs/node/commit/776a65ebcd)] - **test**: remove obsolete TODO comments (Rich Trott) [#2033](https://github.com/nodejs/node/pull/2033) - * [[`bdfeb798ad`](https://github.com/nodejs/node/commit/bdfeb798ad)] - **test**: remove obsolete TODO comments (Rich Trott) [#2032](https://github.com/nodejs/node/pull/2032) - * [[`58e914f9bc`](https://github.com/nodejs/node/commit/58e914f9bc)] - **tools**: fix gyp to work on MacOSX without XCode (Shigeki Ohtsu) [iojs/io.js#1325](https://github.com/iojs/io.js/pull/1325) - * [[`99cbbc0a13`](https://github.com/nodejs/node/commit/99cbbc0a13)] - **tools**: update gyp to 25ed9ac (Ben Noordhuis) [#2074](https://github.com/nodejs/node/pull/2074) - * [[`e3f9335c40`](https://github.com/nodejs/node/commit/e3f9335c40)] - **tools**: re-enable comma-spacing linter rule (Roman Reiss) [#2072](https://github.com/nodejs/node/pull/2072) - * [[`d91e10b3bd`](https://github.com/nodejs/node/commit/d91e10b3bd)] - **tools**: update eslint to 0.24.0 (Roman Reiss) [#2072](https://github.com/nodejs/node/pull/2072) - * [[`6c61ca5325`](https://github.com/nodejs/node/commit/6c61ca5325)] - **url**: fix typo in comment (Rich Trott) [#2071](https://github.com/nodejs/node/pull/2071) - * [[`1a51f0058c`](https://github.com/nodejs/node/commit/1a51f0058c)] - **v8**: cherry-pick JitCodeEvent patch from upstream (Ben Noordhuis) [#2075](https://github.com/nodejs/node/pull/2075) - - - - ## 2015-06-23, Version 2.3.1, @rvagg - - ### Notable changes - - * **module**: The number of syscalls made during a `require()` have been significantly reduced again (see [#1801](https://github.com/nodejs/node/pull/1801) from v2.2.0 for previous work), which should lead to a performance improvement (Pierre Inglebert) [#1920](https://github.com/nodejs/node/pull/1920). - * **npm**: - * Upgrade to [v2.11.2](https://github.com/npm/npm/releases/tag/v2.11.2) (Rebecca Turner) [#1956](https://github.com/nodejs/node/pull/1956). - * Upgrade to [v2.11.3](https://github.com/npm/npm/releases/tag/v2.11.3) (Forrest L Norvell) [#2018](https://github.com/nodejs/node/pull/2018). - * **zlib**: A bug was discovered where the process would abort if the final part of a zlib decompression results in a buffer that would exceed the maximum length of `0x3fffffff` bytes (~1GiB). This was likely to only occur during buffered decompression (rather than streaming). This is now fixed and will instead result in a thrown `RangeError` (Michaël Zasso) [#1811](https://github.com/nodejs/node/pull/1811). - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ## Commits - - * [[`e56758a5e0`](https://github.com/nodejs/node/commit/e56758a5e0)] - **async-wrap**: add provider id and object info cb (Trevor Norris) [#1896](https://github.com/nodejs/node/pull/1896) - * [[`d5637e67c9`](https://github.com/nodejs/node/commit/d5637e67c9)] - **buffer**: fix cyclic dependency with util (Brendan Ashworth) [#1988](https://github.com/nodejs/node/pull/1988) - * [[`c5353d7c62`](https://github.com/nodejs/node/commit/c5353d7c62)] - **build**: remove lint from test-ci on windows (Johan Bergström) [#2004](https://github.com/nodejs/node/pull/2004) - * [[`c207e8d223`](https://github.com/nodejs/node/commit/c207e8d223)] - **build**: fix pkg-config output parsing in configure (Ben Noordhuis) [#1986](https://github.com/nodejs/node/pull/1986) - * [[`8d8a26e8f7`](https://github.com/nodejs/node/commit/8d8a26e8f7)] - **build**: don't run lint from test-ci (Johan Bergström) [#1965](https://github.com/nodejs/node/pull/1965) - * [[`1ec53c044d`](https://github.com/nodejs/node/commit/1ec53c044d)] - **build**: simplify execution of built binary (Johan Bergström) [#1955](https://github.com/nodejs/node/pull/1955) - * [[`3beb880716`](https://github.com/nodejs/node/commit/3beb880716)] - **crypto**: add cert check to CNNIC Whitelist (Shigeki Ohtsu) [#1895](https://github.com/nodejs/node/pull/1895) - * [[`48c0fb8b1a`](https://github.com/nodejs/node/commit/48c0fb8b1a)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`6a359b1ce9`](https://github.com/nodejs/node/commit/6a359b1ce9)] - **deps**: upgrade to npm 2.11.3 (Forrest L Norvell) [#2018](https://github.com/nodejs/node/pull/2018) - * [[`6aab2f3b9a`](https://github.com/nodejs/node/commit/6aab2f3b9a)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`3e12561b55`](https://github.com/nodejs/node/commit/3e12561b55)] - **deps**: upgrade to npm 2.11.2 (Rebecca Turner) [#1956](https://github.com/nodejs/node/pull/1956) - * [[`8ac50819b6`](https://github.com/nodejs/node/commit/8ac50819b6)] - **doc**: add security section to README.md (Rod Vagg) [#1948](https://github.com/nodejs/node/pull/1948) - * [[`1f93b63b11`](https://github.com/nodejs/node/commit/1f93b63b11)] - **doc**: change the info to the same as in gitconfig (Christian Tellnes) [#2000](https://github.com/nodejs/node/pull/2000) - * [[`0cf94e6856`](https://github.com/nodejs/node/commit/0cf94e6856)] - **doc**: mention CI in Collaborator Guide (Rich Trott) [#1995](https://github.com/nodejs/node/pull/1995) - * [[`7a3006efe4`](https://github.com/nodejs/node/commit/7a3006efe4)] - **doc**: add TOC links to Collaborator Guide (Rich Trott) [#1994](https://github.com/nodejs/node/pull/1994) - * [[`30638b150f`](https://github.com/nodejs/node/commit/30638b150f)] - **doc**: add TSC meeting notes 2015-06-10 (Bert Belder) [#1943](https://github.com/nodejs/node/pull/1943) - * [[`c4ec04136b`](https://github.com/nodejs/node/commit/c4ec04136b)] - **doc**: reformat authors section (Johan Bergström) [#1966](https://github.com/nodejs/node/pull/1966) - * [[`96165f9be2`](https://github.com/nodejs/node/commit/96165f9be2)] - **doc**: minor clarification in the modules API doc. (Сковорода Никита Андреевич) [#1983](https://github.com/nodejs/node/pull/1983) - * [[`5c2707c1b2`](https://github.com/nodejs/node/commit/5c2707c1b2)] - **doc**: benchmark/README.md copyedit (Rich Trott) [#1970](https://github.com/nodejs/node/pull/1970) - * [[`74fdf732d0`](https://github.com/nodejs/node/commit/74fdf732d0)] - **doc**: copyedit COLLABORATOR_GUIDE.md (Rich Trott) [#1964](https://github.com/nodejs/node/pull/1964) - * [[`5fe6e83640`](https://github.com/nodejs/node/commit/5fe6e83640)] - **doc**: copyedit GOVERNANCE.md (Rich Trott) [#1963](https://github.com/nodejs/node/pull/1963) - * [[`428526544c`](https://github.com/nodejs/node/commit/428526544c)] - **doc**: add ChALkeR as collaborator (Сковорода Никита Андреевич) [#1927](https://github.com/nodejs/node/pull/1927) - * [[`5dfe0d5d61`](https://github.com/nodejs/node/commit/5dfe0d5d61)] - **doc**: remove irrelevant SEMVER-MINOR & MAJOR (Rod Vagg) - * [[`fb8811d95e`](https://github.com/nodejs/node/commit/fb8811d95e)] - **lib,test**: fix whitespace issues (Roman Reiss) [#1971](https://github.com/nodejs/node/pull/1971) - * [[`a4f4909f3d`](https://github.com/nodejs/node/commit/a4f4909f3d)] - **module**: fix stat with long paths on Windows (Michaël Zasso) [#2013](https://github.com/nodejs/node/pull/2013) - * [[`a71ee93afe`](https://github.com/nodejs/node/commit/a71ee93afe)] - **module**: reduce syscalls during require search (Pierre Inglebert) [#1920](https://github.com/nodejs/node/pull/1920) - * [[`671e64ac73`](https://github.com/nodejs/node/commit/671e64ac73)] - **module**: allow long paths for require on Windows (Michaël Zasso) - * [[`061342a500`](https://github.com/nodejs/node/commit/061342a500)] - **net**: Defer reading until listeners could be added (James Hartig) [#1496](https://github.com/nodejs/node/pull/1496) - * [[`5d2b846d11`](https://github.com/nodejs/node/commit/5d2b846d11)] - **test**: assert tmp and fixture dirs different (Rich Trott) [#2015](https://github.com/nodejs/node/pull/2015) - * [[`b0990ef45d`](https://github.com/nodejs/node/commit/b0990ef45d)] - **test**: confirm symlink (Rich Trott) [#2014](https://github.com/nodejs/node/pull/2014) - * [[`3ba4f71fc4`](https://github.com/nodejs/node/commit/3ba4f71fc4)] - **test**: check result as early as possible (Rich Trott) [#2007](https://github.com/nodejs/node/pull/2007) - * [[`0abcf44d6b`](https://github.com/nodejs/node/commit/0abcf44d6b)] - **test**: add Buffer slice UTF-8 test (Rich Trott) [#1989](https://github.com/nodejs/node/pull/1989) - * [[`88c1831ff4`](https://github.com/nodejs/node/commit/88c1831ff4)] - **test**: tmpdir creation failures should fail tests (Rich Trott) [#1976](https://github.com/nodejs/node/pull/1976) - * [[`52a822d944`](https://github.com/nodejs/node/commit/52a822d944)] - **test**: fix test-cluster-worker-disconnect (Santiago Gimeno) [#1919](https://github.com/nodejs/node/pull/1919) - * [[`7c79490bfb`](https://github.com/nodejs/node/commit/7c79490bfb)] - **test**: only refresh tmpDir for tests that need it (Rich Trott) [#1954](https://github.com/nodejs/node/pull/1954) - * [[`88d7904c0b`](https://github.com/nodejs/node/commit/88d7904c0b)] - **test**: remove test repetition (Rich Trott) [#1874](https://github.com/nodejs/node/pull/1874) - * [[`91dfb5e094`](https://github.com/nodejs/node/commit/91dfb5e094)] - **tools**: make test-npm work without global npm (Jeremiah Senkpiel) [#1926](https://github.com/nodejs/node/pull/1926) - * [[`3777f41562`](https://github.com/nodejs/node/commit/3777f41562)] - **tools**: enable whitespace related rules in eslint (Roman Reiss) [#1971](https://github.com/nodejs/node/pull/1971) - * [[`626432d843`](https://github.com/nodejs/node/commit/626432d843)] - **util**: dont repeat isBuffer (Brendan Ashworth) [#1988](https://github.com/nodejs/node/pull/1988) - * [[`1d79f572f1`](https://github.com/nodejs/node/commit/1d79f572f1)] - **util**: move deprecate() to internal module (Brendan Ashworth) [#1988](https://github.com/nodejs/node/pull/1988) - * [[`4b4b1760b5`](https://github.com/nodejs/node/commit/4b4b1760b5)] - **v8**: cherry-pick uclibc build patch from upstream (Ben Noordhuis) [#1974](https://github.com/nodejs/node/pull/1974) - * [[`5d0cee46bb`](https://github.com/nodejs/node/commit/5d0cee46bb)] - **vm**: remove unnecessary HandleScopes (Ben Noordhuis) [#2001](https://github.com/nodejs/node/pull/2001) - * [[`0ecf9457b5`](https://github.com/nodejs/node/commit/0ecf9457b5)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - * [[`953b3e75e8`](https://github.com/nodejs/node/commit/953b3e75e8)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - * [[`3806d875d3`](https://github.com/nodejs/node/commit/3806d875d3)] - **zlib**: prevent uncaught exception in zlibBuffer (Michaël Zasso) [#1811](https://github.com/nodejs/node/pull/1811) - - - - ## 2015-06-13, Version 2.3.0, @rvagg - - ### Notable changes - - * **libuv**: Upgraded to 1.6.0 and 1.6.1, see [full ChangeLog](https://github.com/libuv/libuv/blob/60e515d9e6f3d86c0eedad583805201f32ea3aed/ChangeLog#L1-L36) for details. (Saúl Ibarra Corretgé) [#1905](https://github.com/nodejs/node/pull/1905) [#1889](https://github.com/nodejs/node/pull/1889). Highlights include: - - Fix TTY becoming blocked on OS X - - Fix UDP send callbacks to not to be synchronous - - Add `uv_os_homedir()` (exposed as `os.homedir()`, see below) - * **npm**: See full [release notes](https://github.com/npm/npm/releases/tag/v2.11.1) for details. (Kat Marchán) [#1899](https://github.com/nodejs/node/pull/1899). Highlight: - - Use GIT_SSH_COMMAND (available as of Git 2.3) - * **openssl**: - - Upgrade to 1.0.2b and 1.0.2c, introduces DHE man-in-the-middle protection (Logjam) and fixes malformed ECParameters causing infinite loop (CVE-2015-1788). See the [security advisory](https://www.openssl.org/news/secadv_20150611.txt) for full details. (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) [#1958](https://github.com/nodejs/node/pull/1958) - - Support [FIPS](https://en.wikipedia.org/wiki/Federal_Information_Processing_Standards) mode of OpenSSL, see [README](https://github.com/nodejs/node#building-iojs-with-fips-compliant-openssl) for instructions. (Fedor Indutny) [#1890](https://github.com/nodejs/node/pull/1890) - * **os**: Add `os.homedir()` method. (Colin Ihrig) [#1791](https://github.com/nodejs/node/pull/1791) - * **smalloc**: Deprecate whole module. (Vladimir Kurchatkin) [#1822](https://github.com/nodejs/node/pull/1822) - * Add new collaborators: - - Alex Kocharin ([@rlidwka](https://github.com/rlidwka)) - - Christopher Monsanto ([@monsanto](https://github.com/monsanto)) - - Ali Ijaz Sheikh ([@ofrobots](https://github.com/ofrobots)) - - Oleg Elifantiev ([@Olegas](https://github.com/Olegas)) - - Domenic Denicola ([@domenic](https://github.com/domenic)) - - Rich Trott ([@Trott](https://github.com/Trott)) - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ## Commits - - * [[`9c0a1b8cfc`](https://github.com/nodejs/node/commit/9c0a1b8cfc)] - **cluster**: wait on servers closing before disconnect (Oleg Elifantiev) [#1400](https://github.com/nodejs/node/pull/1400) - * [[`0f68377f69`](https://github.com/nodejs/node/commit/0f68377f69)] - **crypto**: support FIPS mode of OpenSSL (Fedor Indutny) [#1890](https://github.com/nodejs/node/pull/1890) - * [[`38d1afc24d`](https://github.com/nodejs/node/commit/38d1afc24d)] - **(SEMVER-MINOR)** **crypto**: add getCurves() to get supported ECs (Brian White) [#1914](https://github.com/nodejs/node/pull/1914) - * [[`a4dbf45b59`](https://github.com/nodejs/node/commit/a4dbf45b59)] - **crypto**: update root certificates (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) - * [[`81029c639a`](https://github.com/nodejs/node/commit/81029c639a)] - **debugger**: improve ESRCH error message (Jackson Tian) [#1863](https://github.com/nodejs/node/pull/1863) - * [[`2a7fd0ad32`](https://github.com/nodejs/node/commit/2a7fd0ad32)] - **deps**: update UPGRADING.md doc to openssl-1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) - * [[`6b3df929e0`](https://github.com/nodejs/node/commit/6b3df929e0)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) - * [[`664a659696`](https://github.com/nodejs/node/commit/664a659696)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`42a8de2ac6`](https://github.com/nodejs/node/commit/42a8de2ac6)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) - * [[`c66c3d9fa3`](https://github.com/nodejs/node/commit/c66c3d9fa3)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) - * [[`86737cf0a0`](https://github.com/nodejs/node/commit/86737cf0a0)] - **deps**: upgrade openssl sources to 1.0.2c (Shigeki Ohtsu) [#1958](https://github.com/nodejs/node/pull/1958) - * [[`94804969b7`](https://github.com/nodejs/node/commit/94804969b7)] - **deps**: update asm files for openssl-1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) - * [[`38444915e0`](https://github.com/nodejs/node/commit/38444915e0)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) - * [[`f62b613252`](https://github.com/nodejs/node/commit/f62b613252)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`f624d0122c`](https://github.com/nodejs/node/commit/f624d0122c)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) - * [[`dcd67cc8d7`](https://github.com/nodejs/node/commit/dcd67cc8d7)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) - * [[`c21b24decf`](https://github.com/nodejs/node/commit/c21b24decf)] - **deps**: upgrade openssl sources to 1.0.2b (Shigeki Ohtsu) [#1950](https://github.com/nodejs/node/pull/1950) - * [[`2dc819b09a`](https://github.com/nodejs/node/commit/2dc819b09a)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`f41b7f12b5`](https://github.com/nodejs/node/commit/f41b7f12b5)] - **deps**: upgrade to npm 2.11.1 (Kat Marchán) [#1899](https://github.com/nodejs/node/pull/1899) - * [[`a5bd466440`](https://github.com/nodejs/node/commit/a5bd466440)] - **deps**: update libuv to version 1.6.1 (Saúl Ibarra Corretgé) [#1905](https://github.com/nodejs/node/pull/1905) - * [[`aa33db3238`](https://github.com/nodejs/node/commit/aa33db3238)] - **deps**: update libuv to version 1.6.0 (Saúl Ibarra Corretgé) [#1889](https://github.com/nodejs/node/pull/1889) - * [[`0ee497f0b4`](https://github.com/nodejs/node/commit/0ee497f0b4)] - **deps**: add -no_rand_screen to openssl s_client (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`b5cd2f0986`](https://github.com/nodejs/node/commit/b5cd2f0986)] - **dgram**: partially revert 18d457b (Saúl Ibarra Corretgé) [#1889](https://github.com/nodejs/node/pull/1889) - * [[`a3cc43d0a4`](https://github.com/nodejs/node/commit/a3cc43d0a4)] - **doc**: add Trott as collaborator (Rich Trott) [#1962](https://github.com/nodejs/node/pull/1962) - * [[`cf5020fc02`](https://github.com/nodejs/node/commit/cf5020fc02)] - **doc**: add domenic as collaborator (Domenic Denicola) [#1942](https://github.com/nodejs/node/pull/1942) - * [[`11ed5f31ab`](https://github.com/nodejs/node/commit/11ed5f31ab)] - **doc**: add Olegas as collaborator (Oleg Elifantiev) [#1930](https://github.com/nodejs/node/pull/1930) - * [[`f500e1833b`](https://github.com/nodejs/node/commit/f500e1833b)] - **doc**: add ofrobots as collaborator (Ali Ijaz Sheikh) - * [[`717724611a`](https://github.com/nodejs/node/commit/717724611a)] - **doc**: add monsanto as collaborator (Christopher Monsanto) [#1932](https://github.com/nodejs/node/pull/1932) - * [[`7192b6688c`](https://github.com/nodejs/node/commit/7192b6688c)] - **doc**: add rlidwka as collaborator (Alex Kocharin) [#1929](https://github.com/nodejs/node/pull/1929) - * [[`9f3a03f0d4`](https://github.com/nodejs/node/commit/9f3a03f0d4)] - **doc**: add references to crypto.getCurves() (Roman Reiss) [#1918](https://github.com/nodejs/node/pull/1918) - * [[`ff39ecb914`](https://github.com/nodejs/node/commit/ff39ecb914)] - **doc**: remove comma splice (Rich Trott) [#1900](https://github.com/nodejs/node/pull/1900) - * [[`deb8b87dc9`](https://github.com/nodejs/node/commit/deb8b87dc9)] - **doc**: add note about available ECC curves (Ryan Petschek) [#1913](https://github.com/nodejs/node/pull/1913) - * [[`89a5b9040e`](https://github.com/nodejs/node/commit/89a5b9040e)] - **doc**: fix http.IncomingMessage.socket documentation (Сковорода Никита Андреевич) [#1867](https://github.com/nodejs/node/pull/1867) - * [[`d29034b34b`](https://github.com/nodejs/node/commit/d29034b34b)] - **doc**: adjust changelog to clarify `client` revert (Rod Vagg) [#1859](https://github.com/nodejs/node/pull/1859) - * [[`a79dece8ad`](https://github.com/nodejs/node/commit/a79dece8ad)] - **docs**: add return value for sync fs functions (Tyler Anton) [#1770](https://github.com/nodejs/node/pull/1770) - * [[`1cb72c14c4`](https://github.com/nodejs/node/commit/1cb72c14c4)] - **docs**: delete unused/duplicate css files (Robert Kowalski) [#1770](https://github.com/nodejs/node/pull/1770) - * [[`53a4eb3198`](https://github.com/nodejs/node/commit/53a4eb3198)] - **fs**: make SyncWriteStream non-enumerable (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) - * [[`a011c3243f`](https://github.com/nodejs/node/commit/a011c3243f)] - **fs**: minor refactoring (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) - * [[`8841132f30`](https://github.com/nodejs/node/commit/8841132f30)] - **fs**: remove inStatWatchers and use Map for lookup (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) - * [[`67a11b9bcc`](https://github.com/nodejs/node/commit/67a11b9bcc)] - **fs**: removing unnecessary nullCheckCallNT (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) - * [[`09f2a67bd8`](https://github.com/nodejs/node/commit/09f2a67bd8)] - **fs**: improve error message descriptions (Sakthipriyan Vairamani) [#1870](https://github.com/nodejs/node/pull/1870) - * [[`2dcef83b5f`](https://github.com/nodejs/node/commit/2dcef83b5f)] - **fs**: use `kMaxLength` from binding (Vladimir Kurchatkin) [#1903](https://github.com/nodejs/node/pull/1903) - * [[`353e26e3c7`](https://github.com/nodejs/node/commit/353e26e3c7)] - **(SEMVER-MINOR)** **fs**: Add string encoding option for Stream method (Yosuke Furukawa) [#1845](https://github.com/nodejs/node/pull/1845) - * [[`8357c5084b`](https://github.com/nodejs/node/commit/8357c5084b)] - **fs**: set encoding on fs.createWriteStream (Yosuke Furukawa) [#1844](https://github.com/nodejs/node/pull/1844) - * [[`02c345020a`](https://github.com/nodejs/node/commit/02c345020a)] - **gitignore**: don't ignore the debug npm module (Kat Marchán) [#1908](https://github.com/nodejs/node/pull/1908) - * [[`b5b8ff117c`](https://github.com/nodejs/node/commit/b5b8ff117c)] - **lib**: don't use global Buffer (Roman Reiss) [#1794](https://github.com/nodejs/node/pull/1794) - * [[`a251657058`](https://github.com/nodejs/node/commit/a251657058)] - **node**: mark promises as handled as soon as possible (Vladimir Kurchatkin) [#1952](https://github.com/nodejs/node/pull/1952) - * [[`2eb170874a`](https://github.com/nodejs/node/commit/2eb170874a)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) - * [[`a130132c8f`](https://github.com/nodejs/node/commit/a130132c8f)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [iojs/io.js#1389](https://github.com/iojs/io.js/pull/1389) - * [[`6e78e5feaa`](https://github.com/nodejs/node/commit/6e78e5feaa)] - **(SEMVER-MINOR)** **os**: add homedir() (cjihrig) [#1791](https://github.com/nodejs/node/pull/1791) - * [[`d9e250295b`](https://github.com/nodejs/node/commit/d9e250295b)] - ***Revert*** "**readline**: allow tabs in input" (Jeremiah Senkpiel) [#1961](https://github.com/nodejs/node/pull/1961) - * [[`4b3d493c4b`](https://github.com/nodejs/node/commit/4b3d493c4b)] - **readline**: allow tabs in input (Rich Trott) [#1761](https://github.com/nodejs/node/pull/1761) - * [[`6d95f4ff92`](https://github.com/nodejs/node/commit/6d95f4ff92)] - **(SEMVER-MINOR)** **smalloc**: deprecate whole module (Vladimir Kurchatkin) [#1822](https://github.com/nodejs/node/pull/1822) - * [[`8c71a9241d`](https://github.com/nodejs/node/commit/8c71a9241d)] - **src**: hide InitializeICUDirectory symbol (Ben Noordhuis) [#1815](https://github.com/nodejs/node/pull/1815) - * [[`5b6f575c1f`](https://github.com/nodejs/node/commit/5b6f575c1f)] - ***Revert*** "**src**: add getopt option parser" (Evan Lucas) [#1862](https://github.com/nodejs/node/pull/1862) - * [[`c0e7bf2d8c`](https://github.com/nodejs/node/commit/c0e7bf2d8c)] - **src**: add getopt option parser (Evan Lucas) [#1804](https://github.com/nodejs/node/pull/1804) - * [[`8ea6844d26`](https://github.com/nodejs/node/commit/8ea6844d26)] - **test**: add test for failed save in REPL (Rich Trott) [#1818](https://github.com/nodejs/node/pull/1818) - * [[`03ce84dfa1`](https://github.com/nodejs/node/commit/03ce84dfa1)] - **test**: fix cluster-worker-wait-server-close races (Sam Roberts) [#1953](https://github.com/nodejs/node/pull/1953) - * [[`a6b8ee19b8`](https://github.com/nodejs/node/commit/a6b8ee19b8)] - **test**: create temp dir in common.js (Rich Trott) [#1877](https://github.com/nodejs/node/pull/1877) - * [[`ff8202c6f4`](https://github.com/nodejs/node/commit/ff8202c6f4)] - **test**: fix undeclared variable access (Roman Reiss) [#1794](https://github.com/nodejs/node/pull/1794) - * [[`d9ddd7d345`](https://github.com/nodejs/node/commit/d9ddd7d345)] - **test**: remove TODO comment (Rich Trott) [#1820](https://github.com/nodejs/node/pull/1820) - * [[`6537fd4b55`](https://github.com/nodejs/node/commit/6537fd4b55)] - **test**: remove TODO (Rich Trott) [#1875](https://github.com/nodejs/node/pull/1875) - * [[`a804026c9b`](https://github.com/nodejs/node/commit/a804026c9b)] - **test**: fix broken FreeBSD test (Santiago Gimeno) [#1881](https://github.com/nodejs/node/pull/1881) - * [[`43a82f8a71`](https://github.com/nodejs/node/commit/43a82f8a71)] - **test**: fix test-sync-io-option (Evan Lucas) [#1840](https://github.com/nodejs/node/pull/1840) - * [[`4ed25f664d`](https://github.com/nodejs/node/commit/4ed25f664d)] - **test**: add -no_rand_screen for tls-server-verify (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`4cf323d23d`](https://github.com/nodejs/node/commit/4cf323d23d)] - **test**: kill child in tls-server-verify for speed up (Shigeki Ohtsu) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`e6ccdcc1fe`](https://github.com/nodejs/node/commit/e6ccdcc1fe)] - **test**: improve console output of tls-server-verify (João Reis) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`975e5956f0`](https://github.com/nodejs/node/commit/975e5956f0)] - **test**: run tls-server-verify servers in parallel (João Reis) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`b18604ba2c`](https://github.com/nodejs/node/commit/b18604ba2c)] - **test**: running tls-server-verify clients in parallel (João Reis) [#1836](https://github.com/nodejs/node/pull/1836) - * [[`f78c722df5`](https://github.com/nodejs/node/commit/f78c722df5)] - **test**: remove hardwired references to 'iojs' (Rod Vagg) [#1882](https://github.com/nodejs/node/pull/1882) - * [[`bd99e8de8e`](https://github.com/nodejs/node/commit/bd99e8de8e)] - **test**: more test coverage for maxConnections (Rich Trott) [#1855](https://github.com/nodejs/node/pull/1855) - * [[`b9267189a5`](https://github.com/nodejs/node/commit/b9267189a5)] - **test**: fix test-child-process-stdout-flush-exit (Santiago Gimeno) [#1868](https://github.com/nodejs/node/pull/1868) - * [[`d20f018dcf`](https://github.com/nodejs/node/commit/d20f018dcf)] - **test**: loosen condition to detect infinite loop (Yosuke Furukawa) [#1857](https://github.com/nodejs/node/pull/1857) - * [[`e0e96acc6f`](https://github.com/nodejs/node/commit/e0e96acc6f)] - **test**: remove smalloc add-on test (Ben Noordhuis) [#1835](https://github.com/nodejs/node/pull/1835) - * [[`8704c58fc4`](https://github.com/nodejs/node/commit/8704c58fc4)] - **test**: remove unneeded comment task (Rich Trott) [#1858](https://github.com/nodejs/node/pull/1858) - * [[`8732977536`](https://github.com/nodejs/node/commit/8732977536)] - **tls**: fix references to undefined `cb` (Fedor Indutny) [#1951](https://github.com/nodejs/node/pull/1951) - * [[`75930bb38c`](https://github.com/nodejs/node/commit/75930bb38c)] - **tls**: prevent use-after-free (Fedor Indutny) [#1702](https://github.com/nodejs/node/pull/1702) - * [[`5795e835a1`](https://github.com/nodejs/node/commit/5795e835a1)] - **tls**: emit errors on close whilst async action (Fedor Indutny) [#1702](https://github.com/nodejs/node/pull/1702) - * [[`59d9734e21`](https://github.com/nodejs/node/commit/59d9734e21)] - **tls_wrap**: invoke queued callbacks in DestroySSL (Fedor Indutny) [#1702](https://github.com/nodejs/node/pull/1702) - * [[`6e4d30286d`](https://github.com/nodejs/node/commit/6e4d30286d)] - **tools**: enable/add additional eslint rules (Roman Reiss) [#1794](https://github.com/nodejs/node/pull/1794) - * [[`098354a9f8`](https://github.com/nodejs/node/commit/098354a9f8)] - **tools**: update certdata.txt (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) - * [[`a2d921d6a0`](https://github.com/nodejs/node/commit/a2d921d6a0)] - **tools**: customize mk-ca-bundle.pl (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) - * [[`5be9efca40`](https://github.com/nodejs/node/commit/5be9efca40)] - **tools**: update mk-ca-bundle.pl to HEAD of upstream (Ben Noordhuis) [#1833](https://github.com/nodejs/node/pull/1833) - * [[`1baba0580d`](https://github.com/nodejs/node/commit/1baba0580d)] - **tools**: Fix copying contents of deps/npm (thefourtheye) [#1853](https://github.com/nodejs/node/pull/1853) - * [[`628845b816`](https://github.com/nodejs/node/commit/628845b816)] - **(SEMVER-MINOR)** **util**: introduce `printDeprecationMessage` function (Vladimir Kurchatkin) [#1822](https://github.com/nodejs/node/pull/1822) - * [[`91d0a8b19c`](https://github.com/nodejs/node/commit/91d0a8b19c)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [iojs/io.js#1433](https://github.com/iojs/io.js/pull/1433) - - - - ## 2015-06-01, Version 2.2.1, @rvagg - - ### Notable changes - - * **http**: Reverts the move of the `client` property of `IncomingMessage` to its prototype. Although undocumented, this property was used and assumed to be an "own property" in the wild, most notably by [request](https://github.com/request/request) which is used by npm. (Michaël Zasso) [#1852](https://github.com/nodejs/node/pull/1852). - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`c5a1009903`](https://github.com/nodejs/node/commit/c5a1009903)] - **build**: avoid passing empty strings to build flags (Johan Bergström) [#1789](https://github.com/nodejs/node/pull/1789) - * [[`5d83401086`](https://github.com/nodejs/node/commit/5d83401086)] - **doc**: put SEMVER-MINOR on pre-load module fix 2.2.0 (Rod Vagg) - * [[`4d6b768e5d`](https://github.com/nodejs/node/commit/4d6b768e5d)] - **http**: revert deprecation of client property (Michaël Zasso) [#1852](https://github.com/nodejs/node/pull/1852) - - - - ## 2015-05-31, Version 2.2.0, @rvagg - - ### Notable changes - - * **node**: Speed-up `require()` by replacing usage of `fs.statSync()` and `fs.readFileSync()` with internal variants that are faster for this use-case and do not create as many objects for the garbage collector to clean up. The primary two benefits are: significant increase in application start-up time on typical applications and better start-up time for the debugger by eliminating almost all of the thousands of exception events. (Ben Noordhuis) [#1801](https://github.com/nodejs/node/pull/1801). - * **node**: Resolution of pre-load modules (`-r` or `--require`) now follows the standard `require()` rules rather than just resolving paths, so you can now pre-load modules in node_modules. (Ali Ijaz Sheikh) [#1812](https://github.com/nodejs/node/pull/1812). - * **npm**: Upgraded npm to v2.11.0. New hooks for `preversion`, `version`, and `postversion` lifecycle events, some SPDX-related license changes and license file inclusions. See the [release notes](https://github.com/npm/npm/releases/tag/v2.11.0) for full details. - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`a77c330c32`](https://github.com/nodejs/node/commit/a77c330c32)] - **(SEMVER-MINOR)** **child_process**: expose ChildProcess constructor (Evan Lucas) [#1760](https://github.com/nodejs/node/pull/1760) - * [[`3a1bc067d4`](https://github.com/nodejs/node/commit/3a1bc067d4)] - ***Revert*** "**core**: set PROVIDER type as Persistent class id" (Ben Noordhuis) [#1827](https://github.com/nodejs/node/pull/1827) - * [[`f9fd554500`](https://github.com/nodejs/node/commit/f9fd554500)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`c1afa53648`](https://github.com/nodejs/node/commit/c1afa53648)] - **deps**: upgrade npm to 2.11.0 (Forrest L Norvell) [iojs/io.js#1829](https://github.com/iojs/io.js/pull/1829) - * [[`ff794498e7`](https://github.com/nodejs/node/commit/ff794498e7)] - **doc**: `fs.*File()` also accept encoding strings (Rich Trott) [#1806](https://github.com/nodejs/node/pull/1806) - * [[`98649fd31a`](https://github.com/nodejs/node/commit/98649fd31a)] - **doc**: add documentation for AtExit hook (Steve Sharp) [#1014](https://github.com/nodejs/node/pull/1014) - * [[`eb1856dfd1`](https://github.com/nodejs/node/commit/eb1856dfd1)] - **doc**: clarify stability of fs.watch and relatives (Rich Trott) [#1775](https://github.com/nodejs/node/pull/1775) - * [[`a74c2c9458`](https://github.com/nodejs/node/commit/a74c2c9458)] - **doc**: state url decoding behavior (Josh Gummersall) [#1731](https://github.com/nodejs/node/pull/1731) - * [[`ba76a9d872`](https://github.com/nodejs/node/commit/ba76a9d872)] - **doc**: remove bad semver-major entry from CHANGELOG (Rod Vagg) [#1782](https://github.com/nodejs/node/pull/1782) - * [[`a6a3f8c78d`](https://github.com/nodejs/node/commit/a6a3f8c78d)] - **doc**: fix changelog s/2.0.3/2.1.0 (Rod Vagg) - * [[`2c686fd3ce`](https://github.com/nodejs/node/commit/2c686fd3ce)] - **http**: flush stored header (Vladimir Kurchatkin) [#1695](https://github.com/nodejs/node/pull/1695) - * [[`1eec5f091a`](https://github.com/nodejs/node/commit/1eec5f091a)] - **http**: simplify code and remove unused properties (Brian White) [#1572](https://github.com/nodejs/node/pull/1572) - * [[`1bbf8d0720`](https://github.com/nodejs/node/commit/1bbf8d0720)] - **lib**: speed up require(), phase 2 (Ben Noordhuis) [#1801](https://github.com/nodejs/node/pull/1801) - * [[`b14fd1a720`](https://github.com/nodejs/node/commit/b14fd1a720)] - **lib**: speed up require(), phase 1 (Ben Noordhuis) [#1801](https://github.com/nodejs/node/pull/1801) - * [[`5abd4ac079`](https://github.com/nodejs/node/commit/5abd4ac079)] - **lib**: simplify nextTick() usage (Brian White) [#1612](https://github.com/nodejs/node/pull/1612) - * [[`5759722cfa`](https://github.com/nodejs/node/commit/5759722cfa)] - **(SEMVER-MINOR)** **src**: fix module search path for preload modules (Ali Ijaz Sheikh) [#1812](https://github.com/nodejs/node/pull/1812) - * [[`a65762cab6`](https://github.com/nodejs/node/commit/a65762cab6)] - **src**: remove old code (Brendan Ashworth) [#1819](https://github.com/nodejs/node/pull/1819) - * [[`93a44d5228`](https://github.com/nodejs/node/commit/93a44d5228)] - **src**: fix deferred events not working with -e (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) - * [[`8059393934`](https://github.com/nodejs/node/commit/8059393934)] - **test**: check error type from net.Server.listen() (Rich Trott) [#1821](https://github.com/nodejs/node/pull/1821) - * [[`4e90c82cdb`](https://github.com/nodejs/node/commit/4e90c82cdb)] - **test**: add heap profiler add-on regression test (Ben Noordhuis) [#1828](https://github.com/nodejs/node/pull/1828) - * [[`6dfca71af0`](https://github.com/nodejs/node/commit/6dfca71af0)] - **test**: don't lint autogenerated test/addons/doc-*/ (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) - * [[`c2b8b30836`](https://github.com/nodejs/node/commit/c2b8b30836)] - **test**: remove stray copyright notices (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) - * [[`280fb01daf`](https://github.com/nodejs/node/commit/280fb01daf)] - **test**: fix deprecation warning in addons test (Ben Noordhuis) [#1793](https://github.com/nodejs/node/pull/1793) - * [[`8606793999`](https://github.com/nodejs/node/commit/8606793999)] - **tools**: pass constant to logger instead of string (Johan Bergström) [#1842](https://github.com/nodejs/node/pull/1842) - * [[`fbd2b59716`](https://github.com/nodejs/node/commit/fbd2b59716)] - **tools**: add objectLiteralShorthandProperties to .eslintrc (Evan Lucas) [#1760](https://github.com/nodejs/node/pull/1760) - * [[`53e98cc1b4`](https://github.com/nodejs/node/commit/53e98cc1b4)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1763](https://github.com/nodejs/node/pull/1763) - - - ## 2015-05-24, Version 2.1.0, @rvagg - - ### Notable changes - - * **crypto**: Diffie-Hellman key exchange (DHE) parameters (`'dhparams'`) must now be 1024 bits or longer or an error will be thrown. A warning will also be printed to the console if you supply less than 2048 bits. See https://weakdh.org/ for further context on this security concern. (Shigeki Ohtsu) [#1739](https://github.com/nodejs/node/pull/1739). - * **node**: A new `--trace-sync-io` command line flag will print a warning and a stack trace whenever a synchronous API is used. This can be used to track down synchronous calls that may be slowing down an application. (Trevor Norris) [#1707](https://github.com/nodejs/node/pull/1707). - * **node**: To allow for chaining of methods, the `setTimeout()`, `setKeepAlive()`, `setNoDelay()`, `ref()` and `unref()` methods used in `'net'`, `'dgram'`, `'http'`, `'https'` and `'tls'` now return the current instance instead of `undefined` (Roman Reiss & Evan Lucas) [#1699](https://github.com/nodejs/node/pull/1699) [#1768](https://github.com/nodejs/node/pull/1768) [#1779](https://github.com/nodejs/node/pull/1779). - * **npm**: Upgraded to v2.10.1, release notes can be found in and . - * **util**: A significant speed-up (in the order of 35%) for the common-case of a single string argument to `util.format()`, used by `console.log()` (Сковорода Никита Андреевич) [#1749](https://github.com/nodejs/node/pull/1749). - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`9da168b71f`](https://github.com/nodejs/node/commit/9da168b71f)] - **buffer**: optimize Buffer.byteLength (Brendan Ashworth) [#1713](https://github.com/nodejs/node/pull/1713) - * [[`2b1c01c2cc`](https://github.com/nodejs/node/commit/2b1c01c2cc)] - **build**: refactor pkg-config for shared libraries (Johan Bergström) [#1603](https://github.com/nodejs/node/pull/1603) - * [[`3c44100558`](https://github.com/nodejs/node/commit/3c44100558)] - **core**: set PROVIDER type as Persistent class id (Trevor Norris) [#1730](https://github.com/nodejs/node/pull/1730) - * [[`c1de6d249e`](https://github.com/nodejs/node/commit/c1de6d249e)] - **(SEMVER-MINOR)** **core**: implement runtime flag to trace sync io (Trevor Norris) [#1707](https://github.com/nodejs/node/pull/1707) - * [[`9e7099fa4e`](https://github.com/nodejs/node/commit/9e7099fa4e)] - **deps**: make node-gyp work with io.js (cjihrig) [iojs/io.js#990](https://github.com/iojs/io.js/pull/990) - * [[`c54d057598`](https://github.com/nodejs/node/commit/c54d057598)] - **deps**: upgrade to npm 2.10.1 (Rebecca Turner) [#1763](https://github.com/nodejs/node/pull/1763) - * [[`367ffd167d`](https://github.com/nodejs/node/commit/367ffd167d)] - **doc**: update AUTHORS list (Rod Vagg) [#1776](https://github.com/nodejs/node/pull/1776) - * [[`2bb2f06b3e`](https://github.com/nodejs/node/commit/2bb2f06b3e)] - **doc**: fix typo in CONTRIBUTING.md (Rich Trott) [#1755](https://github.com/nodejs/node/pull/1755) - * [[`515afc6367`](https://github.com/nodejs/node/commit/515afc6367)] - **doc**: path is ignored in url.format (Maurice Butler) [#1753](https://github.com/nodejs/node/pull/1753) - * [[`f0a8bc3f84`](https://github.com/nodejs/node/commit/f0a8bc3f84)] - **doc**: fix spelling in CHANGELOG (Felipe Batista) - * [[`86dd244d9b`](https://github.com/nodejs/node/commit/86dd244d9b)] - **doc**: add notes to child_process.fork() and .exec() (Rich Trott) [#1718](https://github.com/nodejs/node/pull/1718) - * [[`066274794c`](https://github.com/nodejs/node/commit/066274794c)] - **doc**: update links from iojs/io.js to nodejs/io.js (Frederic Hemberger) [#1715](https://github.com/nodejs/node/pull/1715) - * [[`cb381fe3e0`](https://github.com/nodejs/node/commit/cb381fe3e0)] - **(SEMVER-MINOR)** **net**: return this from setNoDelay and setKeepAlive (Roman Reiss) [#1779](https://github.com/nodejs/node/pull/1779) - * [[`85d9983009`](https://github.com/nodejs/node/commit/85d9983009)] - **net**: persist net.Socket options before connect (Evan Lucas) [#1518](https://github.com/nodejs/node/pull/1518) - * [[`39dde3222e`](https://github.com/nodejs/node/commit/39dde3222e)] - **(SEMVER-MINOR)** **net,dgram**: return this from ref and unref methods (Roman Reiss) [#1768](https://github.com/nodejs/node/pull/1768) - * [[`5773438913`](https://github.com/nodejs/node/commit/5773438913)] - **test**: fix jslint error (Michaël Zasso) [#1743](https://github.com/nodejs/node/pull/1743) - * [[`867631986f`](https://github.com/nodejs/node/commit/867631986f)] - **test**: fix test-sync-io-option (Santiago Gimeno) [#1734](https://github.com/nodejs/node/pull/1734) - * [[`f29762f4dd`](https://github.com/nodejs/node/commit/f29762f4dd)] - **test**: enable linting for tests (Roman Reiss) [#1721](https://github.com/nodejs/node/pull/1721) - * [[`2a71f02988`](https://github.com/nodejs/node/commit/2a71f02988)] - **tls**: emit errors happening before handshake finish (Malte-Thorben Bruns) [#1769](https://github.com/nodejs/node/pull/1769) - * [[`80342f649d`](https://github.com/nodejs/node/commit/80342f649d)] - **tls**: use `.destroy(err)` instead of destroy+emit (Fedor Indutny) [#1711](https://github.com/nodejs/node/pull/1711) - * [[`9b35be5810`](https://github.com/nodejs/node/commit/9b35be5810)] - **tls**: make server not use DHE in less than 1024bits (Shigeki Ohtsu) [#1739](https://github.com/nodejs/node/pull/1739) - * [[`214d02040e`](https://github.com/nodejs/node/commit/214d02040e)] - **util**: speed up common case of formatting string (Сковорода Никита Андреевич) [#1749](https://github.com/nodejs/node/pull/1749) - * [[`d144e96fbf`](https://github.com/nodejs/node/commit/d144e96fbf)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1763](https://github.com/nodejs/node/pull/1763) - * [[`0d6d3dda95`](https://github.com/nodejs/node/commit/0d6d3dda95)] - **win,node-gyp**: make delay-load hook C89 compliant (Sharat M R) [TooTallNate/node-gyp#616](https://github.com/TooTallNate/node-gyp/pull/616) - - - ## 2015-05-17, Version 1.8.2, @rvagg - - **Maintenance release** - - ## Notable changes - - * **crypto**: significantly reduced memory usage for TLS (Fedor Indutny & Сковорода Никита Андреевич) [#1529](https://github.com/nodejs/node/pull/1529) - * **npm**: Upgrade npm to 2.9.0. See the [v2.8.4](https://github.com/npm/npm/releases/tag/v2.8.4) and [v2.9.0](https://github.com/npm/npm/releases/tag/v2.9.0) release notes for details. Summary: - - Add support for default author field to make `npm init -y` work without user-input (@othiym23) [npm/npm/d8eee6cf9d](https://github.com/npm/npm/commit/d8eee6cf9d2ff7aca68dfaed2de76824a3e0d9 - - Include local modules in `npm outdated` and `npm update` (@ArnaudRinquin) [npm/npm#7426](https://github.com/npm/npm/issues/7426) - - The prefix used before the version number on `npm version` is now configurable via `tag-version-prefix` (@kkragenbrink) [npm/npm#8014](https://github.com/npm/npm/issues/8014) - - ### Known issues - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - * readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) - - ### Commits - - * [[`5404cbc745`](https://github.com/nodejs/node/commit/5404cbc745)] - **buffer**: fix copy() segfault with zero arguments (Trevor Norris) [nodejs/node#1520](https://github.com/nodejs/node/pull/1520) - * [[`65dd10e9c0`](https://github.com/nodejs/node/commit/65dd10e9c0)] - **build**: remove -J from test-ci (Rod Vagg) [nodejs/node#1544](https://github.com/nodejs/node/pull/1544) - * [[`74060bb60e`](https://github.com/nodejs/node/commit/74060bb60e)] - **crypto**: track external memory for SSL structures (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) - * [[`f10f379240`](https://github.com/nodejs/node/commit/f10f379240)] - **deps**: make node-gyp work with io.js (cjihrig) [nodejs/node#990](https://github.com/nodejs/node/pull/990) - * [[`ba0e744c2c`](https://github.com/nodejs/node/commit/ba0e744c2c)] - **deps**: upgrade npm to 2.9.0 (Forrest L Norvell) [nodejs/node#1583](https://github.com/nodejs/node/pull/1583) - * [[`b3a7da1091`](https://github.com/nodejs/node/commit/b3a7da1091)] - **deps**: update http_parser to 2.5.0 (Fedor Indutny) [nodejs/node#1517](https://github.com/nodejs/node/pull/1517) - * [[`4030545af6`](https://github.com/nodejs/node/commit/4030545af6)] - **fs**: validate fd on fs.write (Julian Duque) [#1553](https://github.com/nodejs/node/pull/1553) - * [[`898d423820`](https://github.com/nodejs/node/commit/898d423820)] - **string_decoder**: don't cache Buffer.isEncoding (Brian White) [nodejs/node#1548](https://github.com/nodejs/node/pull/1548) - * [[`32a6dbcf23`](https://github.com/nodejs/node/commit/32a6dbcf23)] - **test**: extend timeouts for ARMv6 (Rod Vagg) [nodejs/node#1554](https://github.com/nodejs/node/pull/1554) - * [[`5896fe5cd3`](https://github.com/nodejs/node/commit/5896fe5cd3)] - **test**: adjust Makefile/test-ci, add to vcbuild.bat (Rod Vagg) [nodejs/node#1530](https://github.com/nodejs/node/pull/1530) - * [[`b72e4bc596`](https://github.com/nodejs/node/commit/b72e4bc596)] - **tls**: destroy singleUse context immediately (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) - * [[`1cfc455dc5`](https://github.com/nodejs/node/commit/1cfc455dc5)] - **tls**: zero SSL_CTX freelist for a singleUse socket (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) - * [[`7ada680519`](https://github.com/nodejs/node/commit/7ada680519)] - **tls**: destroy SSL once it is out of use (Fedor Indutny) [nodejs/node#1529](https://github.com/nodejs/node/pull/1529) - * [[`71274b0263`](https://github.com/nodejs/node/commit/71274b0263)] - **tls_wrap**: use localhost if options.host is empty (Guilherme Souza) [nodejs/node#1493](https://github.com/nodejs/node/pull/1493) - * [[`0eb74a8b6c`](https://github.com/nodejs/node/commit/0eb74a8b6c)] - **win,node-gyp**: optionally allow node.exe/iojs.exe to be renamed (Bert Belder) [nodejs/node#1266](https://github.com/nodejs/node/pull/1266) - - - ## 2015-05-15, Version 2.0.2, @Fishrock123 - - ### Notable changes - - * **win,node-gyp**: the delay-load hook for windows addons has now been correctly enabled by default, it had wrongly defaulted to off in the release version of 2.0.0 (Bert Belder) [#1433](https://github.com/nodejs/node/pull/1433) - * **os**: `tmpdir()`'s trailing slash stripping has been refined to fix an issue when the temp directory is at '/'. Also considers which slash is used by the operating system. (cjihrig) [#1673](https://github.com/nodejs/node/pull/1673) - * **tls**: default ciphers have been updated to use gcm and aes128 (Mike MacCana) [#1660](https://github.com/nodejs/node/pull/1660) - * **build**: v8 snapshots have been re-enabled by default as suggested by the v8 team, since prior security issues have been resolved. This should give some perf improvements to both startup and vm context creation. (Trevor Norris) [#1663](https://github.com/nodejs/node/pull/1663) - * **src**: fixed preload modules not working when other flags were used before `--require` (Yosuke Furukawa) [#1694](https://github.com/nodejs/node/pull/1694) - * **dgram**: fixed `send()`'s callback not being asynchronous (Yosuke Furukawa) [#1313](https://github.com/nodejs/node/pull/1313) - * **readline**: emitKeys now keeps buffering data until it has enough to parse. This fixes an issue with parsing split escapes. (Alex Kocharin) [#1601](https://github.com/nodejs/node/pull/1601) - * **cluster**: works now properly emit 'disconnect' to `cluser.worker` (Oleg Elifantiev) [#1386](https://github.com/nodejs/node/pull/1386) - * **events**: uncaught errors now provide some context (Evan Lucas) [#1654](https://github.com/nodejs/node/pull/1654) - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - - ### Commits - - * [[`8a0e5295b4`](https://github.com/nodejs/node/commit/8a0e5295b4)] - **build**: use backslashes for paths on windows (Johan Bergström) [#1698](https://github.com/nodejs/node/pull/1698) - * [[`20c9a52227`](https://github.com/nodejs/node/commit/20c9a52227)] - **build**: move --with-intl to intl optgroup (Johan Bergström) [#1680](https://github.com/nodejs/node/pull/1680) - * [[`36cdc7c8ac`](https://github.com/nodejs/node/commit/36cdc7c8ac)] - **build**: re-enable V8 snapshots (Trevor Norris) [#1663](https://github.com/nodejs/node/pull/1663) - * [[`5883a59b21`](https://github.com/nodejs/node/commit/5883a59b21)] - **cluster**: disconnect event not emitted correctly (Oleg Elifantiev) [#1386](https://github.com/nodejs/node/pull/1386) - * [[`0f850f7ae7`](https://github.com/nodejs/node/commit/0f850f7ae7)] - **deps**: provide TXT chunk info in c-ares (Fedor Indutny) - * [[`7e1c0e75ed`](https://github.com/nodejs/node/commit/7e1c0e75ed)] - **deps**: sync with upstream bagder/c-ares@bba4dc5 (Ben Noordhuis) [#1678](https://github.com/nodejs/node/pull/1678) - * [[`18d457bd34`](https://github.com/nodejs/node/commit/18d457bd34)] - **dgram**: call send callback asynchronously (Yosuke Furukawa) [#1313](https://github.com/nodejs/node/pull/1313) - * [[`8b9a1537ad`](https://github.com/nodejs/node/commit/8b9a1537ad)] - **events**: provide better error message for unhandled error (Evan Lucas) [#1654](https://github.com/nodejs/node/pull/1654) - * [[`19ffb5cf1c`](https://github.com/nodejs/node/commit/19ffb5cf1c)] - **lib**: fix eslint styles (Yosuke Furukawa) [#1539](https://github.com/nodejs/node/pull/1539) - * [[`76937051f8`](https://github.com/nodejs/node/commit/76937051f8)] - **os**: refine tmpdir() trailing slash stripping (cjihrig) [#1673](https://github.com/nodejs/node/pull/1673) - * [[`aed6bce906`](https://github.com/nodejs/node/commit/aed6bce906)] - **readline**: turn emitKeys into a streaming parser (Alex Kocharin) [#1601](https://github.com/nodejs/node/pull/1601) - * [[`0a461e5360`](https://github.com/nodejs/node/commit/0a461e5360)] - **src**: fix preload when used with prior flags (Yosuke Furukawa) [#1694](https://github.com/nodejs/node/pull/1694) - * [[`931a0d4634`](https://github.com/nodejs/node/commit/931a0d4634)] - **src**: add type check to v8.setFlagsFromString() (Roman Klauke) [#1652](https://github.com/nodejs/node/pull/1652) - * [[`08d08668c9`](https://github.com/nodejs/node/commit/08d08668c9)] - **src,deps**: replace LoadLibrary by LoadLibraryW (Cheng Zhao) [#226](https://github.com/nodejs/node/pull/226) - * [[`4e2f999a62`](https://github.com/nodejs/node/commit/4e2f999a62)] - **test**: fix infinite loop detection (Yosuke Furukawa) [#1681](https://github.com/nodejs/node/pull/1681) - * [[`5755fc099f`](https://github.com/nodejs/node/commit/5755fc099f)] - **tls**: update default ciphers to use gcm and aes128 (Mike MacCana) [#1660](https://github.com/nodejs/node/pull/1660) - * [[`966acb9916`](https://github.com/nodejs/node/commit/966acb9916)] - **tools**: remove closure_linter to eslint on windows (Yosuke Furukawa) [#1685](https://github.com/nodejs/node/pull/1685) - * [[`c58264e58b`](https://github.com/nodejs/node/commit/c58264e58b)] - **tools**: make eslint work on subdirectories (Roman Reiss) [#1686](https://github.com/nodejs/node/pull/1686) - * [[`0b21ab13b7`](https://github.com/nodejs/node/commit/0b21ab13b7)] - **tools**: refactor `make test-npm` into test-npm.sh (Jeremiah Senkpiel) [#1662](https://github.com/nodejs/node/pull/1662) - * [[`f07b3b600b`](https://github.com/nodejs/node/commit/f07b3b600b)] - **tools**: set eslint comma-spacing to 'warn' (Roman Reiss) [#1672](https://github.com/nodejs/node/pull/1672) - * [[`f9dd34d301`](https://github.com/nodejs/node/commit/f9dd34d301)] - **tools**: replace closure-linter with eslint (Yosuke Furukawa) [#1539](https://github.com/nodejs/node/pull/1539) - * [[`64d3210c98`](https://github.com/nodejs/node/commit/64d3210c98)] - **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1667](https://github.com/nodejs/node/issues/1667) - - - ## 2015-05-07, Version 2.0.1, @rvagg - - ### Notable changes - - * **async_wrap**: (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) - - it is now possible to filter by providers - - bit flags have been removed and replaced with method calls on the binding object - - _note that this is an unstable API so feature additions and breaking changes won't change io.js semver_ - * **libuv**: resolves numerous io.js issues: - - [#862](https://github.com/nodejs/node/issues/862) prevent spawning child processes with invalid stdio file descriptors - - [#1397](https://github.com/nodejs/node/issues/1397) fix EPERM error with fs.access(W_OK) on Windows - - [#1621](https://github.com/nodejs/node/issues/1621) build errors associated with the bundled libuv - - [#1512](https://github.com/nodejs/node/issues/1512) should properly fix Windows termination errors - * **addons**: the `NODE_DEPRECATED` macro was causing problems when compiling addons with older compilers, this should now be resolved (Ben Noordhuis) [#1626](https://github.com/nodejs/node/pull/1626) - * **V8**: upgrade V8 from 4.2.77.18 to 4.2.77.20 with minor fixes, including a bug preventing builds on FreeBSD - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - * readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) - - ### Commits - - * [[`7dde95a8bd`](https://github.com/nodejs/node/commit/7dde95a8bd)] - **async-wrap**: remove before/after calls in init (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) - * [[`bd42ba056a`](https://github.com/nodejs/node/commit/bd42ba056a)] - **async-wrap**: set flags using functions (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) - * [[`4b2c786449`](https://github.com/nodejs/node/commit/4b2c786449)] - **async-wrap**: pass PROVIDER as first arg to init (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) - * [[`84bf609fd2`](https://github.com/nodejs/node/commit/84bf609fd2)] - **async-wrap**: don't call init callback unnecessarily (Trevor Norris) [#1614](https://github.com/nodejs/node/pull/1614) - * [[`04cc03b029`](https://github.com/nodejs/node/commit/04cc03b029)] - **deps**: update libuv to 1.5.0 (Saúl Ibarra Corretgé) [#1646](https://github.com/nodejs/node/pull/1646) - * [[`b16d9c28e8`](https://github.com/nodejs/node/commit/b16d9c28e8)] - **deps**: upgrade v8 to 4.2.77.20 (Ben Noordhuis) [#1639](https://github.com/nodejs/node/pull/1639) - * [[`9ec3109272`](https://github.com/nodejs/node/commit/9ec3109272)] - **doc**: add TC meeting 2015-04-29 minutes (Rod Vagg) [#1585](https://github.com/nodejs/node/pull/1585) - * [[`2c7206254c`](https://github.com/nodejs/node/commit/2c7206254c)] - **doc**: fix typo in readme.md (AQNOUCH Mohammed) [#1643](https://github.com/nodejs/node/pull/1643) - * [[`71dc7152ee`](https://github.com/nodejs/node/commit/71dc7152ee)] - **doc**: fix PR link in CHANGELOG (Brian White) [#1624](https://github.com/nodejs/node/pull/1624) - * [[`b97b96d05a`](https://github.com/nodejs/node/commit/b97b96d05a)] - **install**: fix NameError (thefourtheye) [#1628](https://github.com/nodejs/node/pull/1628) - * [[`6ccbe75384`](https://github.com/nodejs/node/commit/6ccbe75384)] - **js_stream**: fix buffer index in DoWrite (Shigeki Ohtsu) [#1635](https://github.com/nodejs/node/pull/1635) - * [[`c43855c49c`](https://github.com/nodejs/node/commit/c43855c49c)] - **src**: export the ParseEncoding function on Windows (Ivan Kozik) [#1596](https://github.com/nodejs/node/pull/1596) - * [[`8315b22390`](https://github.com/nodejs/node/commit/8315b22390)] - **src**: fix pedantic cpplint whitespace warnings (Ben Noordhuis) [#1640](https://github.com/nodejs/node/pull/1640) - * [[`b712af79a7`](https://github.com/nodejs/node/commit/b712af79a7)] - **src**: fix NODE_DEPRECATED macro with old compilers (Ben Noordhuis) [#1626](https://github.com/nodejs/node/pull/1626) - * [[`2ed10f1349`](https://github.com/nodejs/node/commit/2ed10f1349)] - **src**: fix minor inefficiency in Buffer::New() call (Ben Noordhuis) [#1577](https://github.com/nodejs/node/pull/1577) - * [[`f696c9efab`](https://github.com/nodejs/node/commit/f696c9efab)] - **src**: fix deprecated use of Buffer::New() (Ben Noordhuis) [#1577](https://github.com/nodejs/node/pull/1577) - * [[`0c8f13df8f`](https://github.com/nodejs/node/commit/0c8f13df8f)] - **tools**: remove unused GuessWordSize function (thefourtheye) [#1638](https://github.com/nodejs/node/pull/1638) - - - ## 2015-05-04, Version 2.0.0, @rvagg - - ### Breaking changes - - Full details at https://github.com/nodejs/node/wiki/Breaking-Changes#200-from-1x - - * V8 upgrade to 4.2, minor changes to C++ API - * `os.tmpdir()` is now cross-platform consistent and no longer returns a path with a trailing slash on any platform - * While not a *breaking change* the 'smalloc' module has been deprecated in anticipation of it becoming unsupportable with a future upgrade to V8 4.4. See [#1451](https://github.com/nodejs/node/issues/1451) for further information. - - _Note: a new version of the 'url' module was reverted prior to release as it was decided the potential for breakage across the npm ecosystem was too great and that more compatibility work needed to be done before releasing it. See [#1602](https://github.com/nodejs/node/pull/1602) for further information._ - - ### Notable changes - - * **crypto**: significantly reduced memory usage for TLS (Fedor Indutny & Сковорода Никита Андреевич) [#1529](https://github.com/nodejs/node/pull/1529) - * **net**: `socket.connect()` now accepts a `'lookup'` option for a custom DNS resolution mechanism, defaults to `dns.lookup()` (Evan Lucas) [#1505](https://github.com/nodejs/node/pull/1505) - * **npm**: Upgrade npm to 2.9.0. See the [v2.8.4](https://github.com/npm/npm/releases/tag/v2.8.4) and [v2.9.0](https://github.com/npm/npm/releases/tag/v2.9.0) release notes for details. Notable items: - - Add support for default author field to make `npm init -y` work without user-input (@othiym23) [npm/npm/d8eee6cf9d](https://github.com/npm/npm/commit/d8eee6cf9d2ff7aca68dfaed2de76824a3e0d9af) - - Include local modules in `npm outdated` and `npm update` (@ArnaudRinquin) [npm/npm#7426](https://github.com/npm/npm/issues/7426) - - The prefix used before the version number on `npm version` is now configurable via `tag-version-prefix` (@kkragenbrink) [npm/npm#8014](https://github.com/npm/npm/issues/8014) - * **os**: `os.tmpdir()` is now cross-platform consistent and will no longer returns a path with a trailing slash on any platform (Christian Tellnes) [#747](https://github.com/nodejs/node/pull/747) - * **process**: - - `process.nextTick()` performance has been improved by between 2-42% across the benchmark suite, notable because this is heavily used across core (Brian White) [#1571](https://github.com/nodejs/node/pull/1571) - - New `process.geteuid()`, `process.seteuid(id)`, `process.getegid()` and `process.setegid(id)` methods allow you to get and set effective UID and GID of the process (Evan Lucas) [#1536](https://github.com/nodejs/node/pull/1536) - * **repl**: - - REPL history can be persisted across sessions if the `NODE_REPL_HISTORY_FILE` environment variable is set to a user accessible file, `NODE_REPL_HISTORY_SIZE` can set the maximum history size and defaults to `1000` (Chris Dickinson) [#1513](https://github.com/nodejs/node/pull/1513) - - The REPL can be placed in to one of three modes using the `NODE_REPL_MODE` environment variable: `sloppy`, `strict` or `magic` (default); the new `magic` mode will automatically run "strict mode only" statements in strict mode (Chris Dickinson) [#1513](https://github.com/nodejs/node/pull/1513) - * **smalloc**: the 'smalloc' module has been deprecated due to changes coming in V8 4.4 that will render it unusable - * **util**: add Promise, Map and Set inspection support (Christopher Monsanto) [#1471](https://github.com/nodejs/node/pull/1471) - * **V8**: upgrade to 4.2.77.18, see the [ChangeLog](https://chromium.googlesource.com/v8/v8/+/refs/heads/4.2.77/ChangeLog) for full details. Notable items: - - Classes have moved out of staging; the `class` keyword is now usable in strict mode without flags - - Object literal enhancements have moved out of staging; shorthand method and property syntax is now usable (`{ method() { }, property }`) - - Rest parameters (`function(...args) {}`) are implemented in staging behind the `--harmony-rest-parameters` flag - - Computed property names (`{['foo'+'bar']:'bam'}`) are implemented in staging behind the `--harmony-computed-property-names` flag - - Unicode escapes (`'\u{xxxx}'`) are implemented in staging behind the `--harmony_unicode` flag and the `--harmony_unicode_regexps` flag for use in regular expressions - * **Windows**: - - Random process termination on Windows fixed (Fedor Indutny) [#1512](https://github.com/nodejs/node/issues/1512) / [#1563](https://github.com/nodejs/node/pull/1563) - - The delay-load hook introduced to fix issues with process naming (iojs.exe / node.exe) has been made opt-out for native add-ons. Native add-ons should include `'win_delay_load_hook': 'false'` in their binding.gyp to disable this feature if they experience problems . (Bert Belder) [#1433](https://github.com/nodejs/node/pull/1433) - * **Governance**: - - Rod Vagg (@rvagg) was added to the Technical Committee (TC) - - Jeremiah Senkpiel (@Fishrock123) was added to the Technical Committee (TC) - - ### Known issues - - See https://github.com/nodejs/node/labels/confirmed-bug for complete and current list of known issues. - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - * readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) - - ### Commits - - * [[`5404cbc745`](https://github.com/nodejs/node/commit/5404cbc745)] - **buffer**: fix copy() segfault with zero arguments (Trevor Norris) [#1520](https://github.com/nodejs/node/pull/1520) - * [[`3d3083b91f`](https://github.com/nodejs/node/commit/3d3083b91f)] - **buffer**: little improve for Buffer.concat method (Jackson Tian) [#1437](https://github.com/nodejs/node/pull/1437) - * [[`e67542ae17`](https://github.com/nodejs/node/commit/e67542ae17)] - **build**: disable -Og when building with clang (Ben Noordhuis) [#1609](https://github.com/nodejs/node/pull/1609) - * [[`78f4b038f8`](https://github.com/nodejs/node/commit/78f4b038f8)] - **build**: turn on debug-safe optimizations with -Og (Ben Noordhuis) [#1569](https://github.com/nodejs/node/pull/1569) - * [[`a5dcff827a`](https://github.com/nodejs/node/commit/a5dcff827a)] - **build**: Use option groups in configure output (Johan Bergström) [#1533](https://github.com/nodejs/node/pull/1533) - * [[`2a3c8c187e`](https://github.com/nodejs/node/commit/2a3c8c187e)] - **build**: remove -J from test-ci (Rod Vagg) [#1544](https://github.com/nodejs/node/pull/1544) - * [[`e6874dd0f9`](https://github.com/nodejs/node/commit/e6874dd0f9)] - **crypto**: track external memory for SSL structures (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) - * [[`935c9d3fa7`](https://github.com/nodejs/node/commit/935c9d3fa7)] - **deps**: make node-gyp work with io.js (cjihrig) [#990](https://github.com/nodejs/node/pull/990) - * [[`56e4255382`](https://github.com/nodejs/node/commit/56e4255382)] - **deps**: upgrade npm to 2.9.0 (Forrest L Norvell) [#1573](https://github.com/nodejs/node/pull/1573) - * [[`509b59ea7c`](https://github.com/nodejs/node/commit/509b59ea7c)] - **deps**: enable v8 postmortem debugging again (Ben Noordhuis) [#1232](https://github.com/nodejs/node/pull/1232) - * [[`01652c7709`](https://github.com/nodejs/node/commit/01652c7709)] - **deps**: upgrade v8 to 4.2.77.18 (Chris Dickinson) [#1506](https://github.com/nodejs/node/pull/1506) - * [[`01e6632d70`](https://github.com/nodejs/node/commit/01e6632d70)] - **deps**: upgrade v8 to 4.2.77.15 (Ben Noordhuis) [#1399](https://github.com/nodejs/node/pull/1399) - * [[`db4ded5903`](https://github.com/nodejs/node/commit/db4ded5903)] - **deps**: enable v8 postmortem debugging again (Ben Noordhuis) [#1232](https://github.com/nodejs/node/pull/1232) - * [[`36cd5fb9d2`](https://github.com/nodejs/node/commit/36cd5fb9d2)] - **(SEMVER-MAJOR)** **deps**: upgrade v8 to 4.2.77.13 (Ben Noordhuis) [#1232](https://github.com/nodejs/node/pull/1232) - * [[`b3a7da1091`](https://github.com/nodejs/node/commit/b3a7da1091)] - **deps**: update http_parser to 2.5.0 (Fedor Indutny) [#1517](https://github.com/nodejs/node/pull/1517) - * [[`ac1fb39ce8`](https://github.com/nodejs/node/commit/ac1fb39ce8)] - **doc**: add rvagg to the TC (Rod Vagg) [#1613](https://github.com/nodejs/node/pull/1613) - * [[`dacc1fa35c`](https://github.com/nodejs/node/commit/dacc1fa35c)] - **doc**: update AUTHORS list (Rod Vagg) [#1586](https://github.com/nodejs/node/pull/1586) - * [[`2a3a1909ab`](https://github.com/nodejs/node/commit/2a3a1909ab)] - **doc**: add require() lines to child.stdio example (Nick Raienko) [#1504](https://github.com/nodejs/node/pull/1504) - * [[`02388dbf40`](https://github.com/nodejs/node/commit/02388dbf40)] - **doc**: fix some cross-references (Alexander Gromnitsky) [#1584](https://github.com/nodejs/node/pull/1584) - * [[`57c4cc26e2`](https://github.com/nodejs/node/commit/57c4cc26e2)] - **doc**: add TC meeting 2015-04-22 minutes (Rod Vagg) [#1556](https://github.com/nodejs/node/pull/1556) - * [[`b4ad5d7050`](https://github.com/nodejs/node/commit/b4ad5d7050)] - **doc**: improve http.request and https.request opts (Roman Reiss) [#1551](https://github.com/nodejs/node/pull/1551) - * [[`7dc8eec0a6`](https://github.com/nodejs/node/commit/7dc8eec0a6)] - **doc**: deprecate smalloc module (Ben Noordhuis) [#1566](https://github.com/nodejs/node/pull/1566) - * [[`1bcdf46ca7`](https://github.com/nodejs/node/commit/1bcdf46ca7)] - **doc**: add TC meeting 2015-04-15 minutes (Rod Vagg) [#1498](https://github.com/nodejs/node/pull/1498) - * [[`391cae3595`](https://github.com/nodejs/node/commit/391cae3595)] - **doc**: Add Known issues to v1.7.0/1.7.1 CHANGELOG (Yosuke Furukawa) [#1473](https://github.com/nodejs/node/pull/1473) - * [[`e55fdc47a7`](https://github.com/nodejs/node/commit/e55fdc47a7)] - **doc**: fix util.deprecate example (Nick Raienko) [#1535](https://github.com/nodejs/node/pull/1535) - * [[`5178f93bc0`](https://github.com/nodejs/node/commit/5178f93bc0)] - **doc**: Add Addon API (NAN) to working group list (Julian Duque) [#1523](https://github.com/nodejs/node/pull/1523) - * [[`f3cc50f811`](https://github.com/nodejs/node/commit/f3cc50f811)] - **doc**: add TC meeting 2015-04-08 minutes (Rod Vagg) [#1497](https://github.com/nodejs/node/pull/1497) - * [[`bb254b533b`](https://github.com/nodejs/node/commit/bb254b533b)] - **doc**: update branch to master (Roman Reiss) [#1511](https://github.com/nodejs/node/pull/1511) - * [[`22aafa5597`](https://github.com/nodejs/node/commit/22aafa5597)] - **doc**: add Fishrock123 to the TC (Jeremiah Senkpiel) [#1507](https://github.com/nodejs/node/pull/1507) - * [[`b16a328ede`](https://github.com/nodejs/node/commit/b16a328ede)] - **doc**: add spaces to child.kill example (Nick Raienko) [#1503](https://github.com/nodejs/node/pull/1503) - * [[`26327757f8`](https://github.com/nodejs/node/commit/26327757f8)] - **doc**: update AUTHORS list (Rod Vagg) [#1476](https://github.com/nodejs/node/pull/1476) - * [[`f9c681cf62`](https://github.com/nodejs/node/commit/f9c681cf62)] - **fs**: validate fd on fs.write (Julian Duque) [#1553](https://github.com/nodejs/node/pull/1553) - * [[`801b47acc5`](https://github.com/nodejs/node/commit/801b47acc5)] - **gitignore**: ignore xcode workspaces and projects (Roman Klauke) [#1562](https://github.com/nodejs/node/pull/1562) - * [[`d5ce47e433`](https://github.com/nodejs/node/commit/d5ce47e433)] - **(SEMVER-MINOR)** **lib**: deprecate the smalloc module (Ben Noordhuis) [#1564](https://github.com/nodejs/node/pull/1564) - * [[`7384ca83f9`](https://github.com/nodejs/node/commit/7384ca83f9)] - **module**: remove '' from Module.globalPaths (Chris Yip) [#1488](https://github.com/nodejs/node/pull/1488) - * [[`b4f5898395`](https://github.com/nodejs/node/commit/b4f5898395)] - **net**: ensure Write/ShutdownWrap references handle (Fedor Indutny) [#1590](https://github.com/nodejs/node/pull/1590) - * [[`4abe2fa1cf`](https://github.com/nodejs/node/commit/4abe2fa1cf)] - **(SEMVER-MINOR)** **net**: add lookup option to Socket.prototype.connect (Evan Lucas) [#1505](https://github.com/nodejs/node/pull/1505) - * [[`1bef717476`](https://github.com/nodejs/node/commit/1bef717476)] - **(SEMVER-MINOR)** **net**: cleanup connect logic (Evan Lucas) [#1505](https://github.com/nodejs/node/pull/1505) - * [[`c7782c0af8`](https://github.com/nodejs/node/commit/c7782c0af8)] - **node**: improve nextTick performance (Brian White) [#1571](https://github.com/nodejs/node/pull/1571) - * [[`b57cc51d8d`](https://github.com/nodejs/node/commit/b57cc51d8d)] - **(SEMVER-MAJOR)** **os**: remove trailing slash from os.tmpdir() (Christian Tellnes) [#747](https://github.com/nodejs/node/pull/747) - * [[`ca219b00d1`](https://github.com/nodejs/node/commit/ca219b00d1)] - **repl**: fix for a+ fd clearing the file on read (Chris Dickinson) [#1605](https://github.com/nodejs/node/pull/1605) - * [[`051d482b15`](https://github.com/nodejs/node/commit/051d482b15)] - **repl**: fix \_debugger by properly proxying repl (Chris Dickinson) [#1605](https://github.com/nodejs/node/pull/1605) - * [[`2e2fce0502`](https://github.com/nodejs/node/commit/2e2fce0502)] - **repl**: fix persistent history and env variable name (Roman Reiss) [#1593](https://github.com/nodejs/node/pull/1593) - * [[`ea5195ccaf`](https://github.com/nodejs/node/commit/ea5195ccaf)] - **repl**: do not save history for non-terminal repl (Fedor Indutny) [#1575](https://github.com/nodejs/node/pull/1575) - * [[`0450ce7db2`](https://github.com/nodejs/node/commit/0450ce7db2)] - **repl**: add mode detection, cli persistent history (Chris Dickinson) [#1513](https://github.com/nodejs/node/pull/1513) - * [[`af9fe3bbc7`](https://github.com/nodejs/node/commit/af9fe3bbc7)] - **(SEMVER-MAJOR)** **src**: bump NODE_MODULE_VERSION due to V8 API (Rod Vagg) [#1532](https://github.com/nodejs/node/pull/1532) - * [[`279f6116aa`](https://github.com/nodejs/node/commit/279f6116aa)] - **src**: fix -Wmissing-field-initializers warning (Ben Noordhuis) [#1606](https://github.com/nodejs/node/pull/1606) - * [[`73062521a4`](https://github.com/nodejs/node/commit/73062521a4)] - **src**: deprecate smalloc public functions (Ben Noordhuis) [#1565](https://github.com/nodejs/node/pull/1565) - * [[`ccb199af17`](https://github.com/nodejs/node/commit/ccb199af17)] - **src**: fix deprecation warnings (Ben Noordhuis) [#1565](https://github.com/nodejs/node/pull/1565) - * [[`609fa0de03`](https://github.com/nodejs/node/commit/609fa0de03)] - **src**: fix NODE_DEPRECATED macro (Ben Noordhuis) [#1565](https://github.com/nodejs/node/pull/1565) - * [[`3c92ca2b5c`](https://github.com/nodejs/node/commit/3c92ca2b5c)] - **(SEMVER-MINOR)** **src**: add ability to get/set effective uid/gid (Evan Lucas) [#1536](https://github.com/nodejs/node/pull/1536) - * [[`30b7349176`](https://github.com/nodejs/node/commit/30b7349176)] - **stream_base**: dispatch reqs in the stream impl (Fedor Indutny) [#1563](https://github.com/nodejs/node/pull/1563) - * [[`0fa6c4a6fc`](https://github.com/nodejs/node/commit/0fa6c4a6fc)] - **string_decoder**: don't cache Buffer.isEncoding (Brian White) [#1548](https://github.com/nodejs/node/pull/1548) - * [[`f9b226c1c1`](https://github.com/nodejs/node/commit/f9b226c1c1)] - **test**: extend timeouts for ARMv6 (Rod Vagg) [#1554](https://github.com/nodejs/node/pull/1554) - * [[`bfae8236b1`](https://github.com/nodejs/node/commit/bfae8236b1)] - **test**: fix test-net-dns-custom-lookup test assertion (Evan Lucas) [#1531](https://github.com/nodejs/node/pull/1531) - * [[`547213913b`](https://github.com/nodejs/node/commit/547213913b)] - **test**: adjust Makefile/test-ci, add to vcbuild.bat (Rod Vagg) [#1530](https://github.com/nodejs/node/pull/1530) - * [[`550c2638c0`](https://github.com/nodejs/node/commit/550c2638c0)] - **tls**: use `SSL_set_cert_cb` for async SNI/OCSP (Fedor Indutny) [#1464](https://github.com/nodejs/node/pull/1464) - * [[`1787416376`](https://github.com/nodejs/node/commit/1787416376)] - **tls**: destroy singleUse context immediately (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) - * [[`2684c902c4`](https://github.com/nodejs/node/commit/2684c902c4)] - **tls**: zero SSL_CTX freelist for a singleUse socket (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) - * [[`2d241b3b82`](https://github.com/nodejs/node/commit/2d241b3b82)] - **tls**: destroy SSL once it is out of use (Fedor Indutny) [#1529](https://github.com/nodejs/node/pull/1529) - * [[`f7620fb96d`](https://github.com/nodejs/node/commit/f7620fb96d)] - **tls_wrap**: Unlink TLSWrap and SecureContext objects (Сковорода Никита Андреевич) [#1580](https://github.com/nodejs/node/pull/1580) - * [[`a7d74633f2`](https://github.com/nodejs/node/commit/a7d74633f2)] - **tls_wrap**: use localhost if options.host is empty (Guilherme Souza) [#1493](https://github.com/nodejs/node/pull/1493) - * [[`702997c1f0`](https://github.com/nodejs/node/commit/702997c1f0)] - ***Revert*** "**url**: significantly improve the performance of the url module" (Rod Vagg) [#1602](https://github.com/nodejs/node/pull/1602) - * [[`0daed24883`](https://github.com/nodejs/node/commit/0daed24883)] - ***Revert*** "**url**: delete href cache on all setter code paths" (Rod Vagg) [#1602](https://github.com/nodejs/node/pull/1602) - * [[`0f39ef4ca1`](https://github.com/nodejs/node/commit/0f39ef4ca1)] - ***Revert*** "**url**: fix treatment of some values as non-empty" (Rod Vagg) [#1602](https://github.com/nodejs/node/pull/1602) - * [[`66877216bd`](https://github.com/nodejs/node/commit/66877216bd)] - **url**: fix treatment of some values as non-empty (Petka Antonov) [#1589](https://github.com/nodejs/node/pull/1589) - * [[`dbdd81a91b`](https://github.com/nodejs/node/commit/dbdd81a91b)] - **url**: delete href cache on all setter code paths (Petka Antonov) [#1589](https://github.com/nodejs/node/pull/1589) - * [[`3fd7fc429c`](https://github.com/nodejs/node/commit/3fd7fc429c)] - **url**: significantly improve the performance of the url module (Petka Antonov) [#1561](https://github.com/nodejs/node/pull/1561) - * [[`bf7ac08dd0`](https://github.com/nodejs/node/commit/bf7ac08dd0)] - **util**: add Map and Set inspection support (Christopher Monsanto) [#1471](https://github.com/nodejs/node/pull/1471) - * [[`30e83d2e84`](https://github.com/nodejs/node/commit/30e83d2e84)] - **win,node-gyp**: optionally allow node.exe/iojs.exe to be renamed (Bert Belder) [#1266](https://github.com/nodejs/node/pull/1266) - * [[`3bda6cbfa4`](https://github.com/nodejs/node/commit/3bda6cbfa4)] - **(SEMVER-MAJOR)** **win,node-gyp**: enable delay-load hook by default (Bert Belder) [#1433](https://github.com/nodejs/node/pull/1433) - - - - ## 2015-04-20, Version 1.8.1, @chrisdickinson - - ### Notable changes - - * **NOTICE**: Skipped v1.8.0 due to problems with release tooling. - See [#1436](https://github.com/nodejs/node/issues/1436) for details. - * **build**: Support for building io.js as a static library (Marat Abdullin) [#1341](https://github.com/nodejs/node/pull/1341) - * **deps**: Upgrade openssl to 1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * Users should see performance improvements when using the crypto API. - See [here](https://github.com/nodejs/node/wiki/Crypto-Performance-Notes-for-OpenSSL-1.0.2a-on-iojs-v1.8.0) - for details. - * **npm**: Upgrade npm to 2.8.3. See the [release notes](https://github.com/npm/npm/releases/tag/v2.8.3) for details. Includes improved git support. Summary: - * [`387f889`](https://github.com/npm/npm/commit/387f889c0e8fb617d9cc9a42ed0a3ec49424ab5d) - [#7961](https://github.com/npm/npm/issues/7961) Ensure that hosted git SSH - URLs always have a valid protocol when stored in `resolved` fields in - `npm-shrinkwrap.json`. ([@othiym23](https://github.com/othiym23)) - * [`394c2f5`](https://github.com/npm/npm/commit/394c2f5a1227232c0baf42fbba1402aafe0d6ffb) - Switch the order in which hosted Git providers are checked to `git:`, - `git+https:`, then `git+ssh:` (from `git:`, `git+ssh:`, then `git+https:`) in - an effort to go from most to least likely to succeed, to make for less - confusing error message. ([@othiym23](https://github.com/othiym23)) - * [`431c3bf`](https://github.com/npm/npm/commit/431c3bf6cdec50f9f0c735f478cb2f3f337d3313) - [#7699](https://github.com/npm/npm/issues/7699) `npm-registry-client@6.3.2`: - Don't send body with HTTP GET requests when logging in. - ([@smikes](https://github.com/smikes)) - * [`15efe12`](https://github.com/npm/npm/commit/15efe124753257728a0ddc64074fa5a4b9c2eb30) - [#7872](https://github.com/npm/npm/issues/7872) Use the new version of - `hosted-git-info` to pass along credentials embedded in git URLs. Test it. - Test it a lot. ([@othiym23](https://github.com/othiym23)) - * [`b027319`](https://github.com/npm/npm/commit/b0273190c71eba14395ddfdd1d9f7ba625297523) - [#7920](https://github.com/npm/npm/issues/7920) Scoped packages with - `peerDependencies` were installing the `peerDependencies` into the wrong - directory. ([@ewie](https://github.com/ewie)) - * [`6b0f588`](https://github.com/npm/npm/commit/6b0f58877f37df9904490ffbaaad33862bd36dce) - [#7867](https://github.com/npm/npm/issues/7867) Use git shorthand and git - URLs as presented by user. Support new `hosted-git-info` shortcut syntax. - Save shorthand in `package.json`. Try cloning via `git:`, `git+ssh:`, and - `git+https:`, in that order, when supported by the underlying hosting - provider. ([@othiym23](https://github.com/othiym23)) - * **src**: Allow multiple arguments to be passed to process.nextTick (Trevor Norris) [#1077](https://github.com/nodejs/node/pull/1077) - * **module**: The interaction of `require('.')` with `NODE_PATH` has been restored and deprecated. This functionality - will be removed at a later point. (Roman Reiss) [#1363](https://github.com/nodejs/node/pull/1363) - - ### Known issues - - * Some problems with unreferenced timers running during `beforeExit` are still to be resolved. See [#1264](https://github.com/nodejs/node/issues/1264). - * Surrogate pair in REPL can freeze terminal [#690](https://github.com/nodejs/node/issues/690) - * `process.send()` is not synchronous as the docs suggest, a regression introduced in 1.0.2, see [#760](https://github.com/nodejs/node/issues/760) and fix in [#774](https://github.com/nodejs/node/issues/774) - * Calling `dns.setServers()` while a DNS query is in progress can cause the process to crash on a failed assertion [#894](https://github.com/nodejs/node/issues/894) - * `url.resolve` may transfer the auth portion of the url when resolving between two full hosts, see [#1435](https://github.com/nodejs/node/issues/1435). - * readline: split escapes are processed incorrectly, see [#1403](https://github.com/nodejs/node/issues/1403) - - ### Commits - - * [[`53ed89d927`](https://github.com/nodejs/node/commit/53ed89d927)] - ***Revert*** "**build**: use %PYTHON% instead of python" (Rod Vagg) [#1475](https://github.com/nodejs/node/pull/1475) - * [[`2b744b0ab7`](https://github.com/nodejs/node/commit/2b744b0ab7)] - **src**: revert NODE_MODULE_VERSION to 43 (Chris Dickinson) [#1460](https://github.com/nodejs/node/pull/1460) - * [[`431673ebd1`](https://github.com/nodejs/node/commit/431673ebd1)] - **buffer**: fast-case for empty string in byteLength (Jackson Tian) [#1441](https://github.com/nodejs/node/pull/1441) - * [[`1b22bad35f`](https://github.com/nodejs/node/commit/1b22bad35f)] - **build**: fix logic for shared library flags (Jeremiah Senkpiel) [#1454](https://github.com/nodejs/node/pull/1454) - * [[`91943a99d5`](https://github.com/nodejs/node/commit/91943a99d5)] - **build**: use %PYTHON% instead of python (Rod Vagg) [#1444](https://github.com/nodejs/node/pull/1444) - * [[`c7769d417b`](https://github.com/nodejs/node/commit/c7769d417b)] - **build**: Expose xz compression level (Johan Bergström) [#1428](https://github.com/nodejs/node/pull/1428) - * [[`a530b2baf1`](https://github.com/nodejs/node/commit/a530b2baf1)] - **build**: fix error message in configure (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`92dfb794f9`](https://github.com/nodejs/node/commit/92dfb794f9)] - **build**: enable ssl support on arm64 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`7de0dcde83`](https://github.com/nodejs/node/commit/7de0dcde83)] - **deps**: make node-gyp work with io.js (cjihrig) [#990](https://github.com/nodejs/node/pull/990) - * [[`4870213f9e`](https://github.com/nodejs/node/commit/4870213f9e)] - **deps**: upgrade npm to 2.8.3 (Forrest L Norvell) - * [[`49bb7ded2c`](https://github.com/nodejs/node/commit/49bb7ded2c)] - **deps**: fix git case sensitivity issue in npm (Chris Dickinson) [#1456](https://github.com/nodejs/node/pull/1456) - * [[`4830b4bce8`](https://github.com/nodejs/node/commit/4830b4bce8)] - **deps**: add docs to upgrade openssl (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`11bec72c87`](https://github.com/nodejs/node/commit/11bec72c87)] - **deps**: update asm files for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`53924d8ebe`](https://github.com/nodejs/node/commit/53924d8ebe)] - **deps**: update asm Makefile for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`418e839456`](https://github.com/nodejs/node/commit/418e839456)] - **deps**: update openssl.gyp/gypi for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`02f12ab666`](https://github.com/nodejs/node/commit/02f12ab666)] - **deps**: update opensslconf.h for 1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`eb7a23595f`](https://github.com/nodejs/node/commit/eb7a23595f)] - **deps**: add x32 and arm64 support for opensslconf.h (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`033a663127`](https://github.com/nodejs/node/commit/033a663127)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`ae8831f240`](https://github.com/nodejs/node/commit/ae8831f240)] - **deps**: backport openssl patch of alt cert chains 1 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`71316c46d9`](https://github.com/nodejs/node/commit/71316c46d9)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`d293a4f096`](https://github.com/nodejs/node/commit/d293a4f096)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`e4872d7405`](https://github.com/nodejs/node/commit/e4872d7405)] - **deps**: upgrade openssl to 1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`a1c9ef3142`](https://github.com/nodejs/node/commit/a1c9ef3142)] - **deps, build**: add support older assembler (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`76f219c128`](https://github.com/nodejs/node/commit/76f219c128)] - **doc**: Document forced pushing with git (Johan Bergström) [#1420](https://github.com/nodejs/node/pull/1420) - * [[`12e51d56c1`](https://github.com/nodejs/node/commit/12e51d56c1)] - **doc**: add Addon API WG (Rod Vagg) [#1226](https://github.com/nodejs/node/pull/1226) - * [[`7956a13dad`](https://github.com/nodejs/node/commit/7956a13dad)] - **http**: logically respect maxSockets (fengmk2) [#1242](https://github.com/nodejs/node/pull/1242) - * [[`5b844e140b`](https://github.com/nodejs/node/commit/5b844e140b)] - **module**: fix style (Roman Reiss) [#1453](https://github.com/nodejs/node/pull/1453) - * [[`3ad82c335d`](https://github.com/nodejs/node/commit/3ad82c335d)] - **(SEMVER-MINOR)** **module**: handle NODE_PATH in require('.') (Roman Reiss) [#1363](https://github.com/nodejs/node/pull/1363) - * [[`cd60ff0328`](https://github.com/nodejs/node/commit/cd60ff0328)] - **net**: add fd into listen2 debug info (Jackson Tian) [#1442](https://github.com/nodejs/node/pull/1442) - * [[`10e31ba56c`](https://github.com/nodejs/node/commit/10e31ba56c)] - **(SEMVER-MINOR)** **node**: allow multiple arguments passed to nextTick (Trevor Norris) [#1077](https://github.com/nodejs/node/pull/1077) - * [[`116c54692a`](https://github.com/nodejs/node/commit/116c54692a)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`62f5f4cec9`](https://github.com/nodejs/node/commit/62f5f4cec9)] - **src**: remove duplicate byteLength from Buffer (Jackson Tian) [#1438](https://github.com/nodejs/node/pull/1438) - * [[`51d0808c90`](https://github.com/nodejs/node/commit/51d0808c90)] - **stream**: remove duplicated expression (Yazhong Liu) [#1444](https://github.com/nodejs/node/pull/1444) - * [[`deb9d23d7b`](https://github.com/nodejs/node/commit/deb9d23d7b)] - **test**: fix error message check for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) - * [[`ca8c9ec2c8`](https://github.com/nodejs/node/commit/ca8c9ec2c8)] - **win,node-gyp**: optionally allow node.exe/iojs.exe to be renamed (Bert Belder) [#1266](https://github.com/nodejs/node/pull/1266) +* [[`53ed89d927`](https://github.com/nodejs/node/commit/53ed89d927)] - ***Revert*** "**build**: use %PYTHON% instead of python" (Rod Vagg) [#1475](https://github.com/nodejs/node/pull/1475) +* [[`2b744b0ab7`](https://github.com/nodejs/node/commit/2b744b0ab7)] - **src**: revert NODE_MODULE_VERSION to 43 (Chris Dickinson) [#1460](https://github.com/nodejs/node/pull/1460) +* [[`431673ebd1`](https://github.com/nodejs/node/commit/431673ebd1)] - **buffer**: fast-case for empty string in byteLength (Jackson Tian) [#1441](https://github.com/nodejs/node/pull/1441) +* [[`1b22bad35f`](https://github.com/nodejs/node/commit/1b22bad35f)] - **build**: fix logic for shared library flags (Jeremiah Senkpiel) [#1454](https://github.com/nodejs/node/pull/1454) +* [[`91943a99d5`](https://github.com/nodejs/node/commit/91943a99d5)] - **build**: use %PYTHON% instead of python (Rod Vagg) [#1444](https://github.com/nodejs/node/pull/1444) +* [[`c7769d417b`](https://github.com/nodejs/node/commit/c7769d417b)] - **build**: Expose xz compression level (Johan Bergström) [#1428](https://github.com/nodejs/node/pull/1428) +* [[`a530b2baf1`](https://github.com/nodejs/node/commit/a530b2baf1)] - **build**: fix error message in configure (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`92dfb794f9`](https://github.com/nodejs/node/commit/92dfb794f9)] - **build**: enable ssl support on arm64 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`7de0dcde83`](https://github.com/nodejs/node/commit/7de0dcde83)] - **deps**: make node-gyp work with io.js (cjihrig) [#990](https://github.com/nodejs/node/pull/990) +* [[`4870213f9e`](https://github.com/nodejs/node/commit/4870213f9e)] - **deps**: upgrade npm to 2.8.3 (Forrest L Norvell) +* [[`49bb7ded2c`](https://github.com/nodejs/node/commit/49bb7ded2c)] - **deps**: fix git case sensitivity issue in npm (Chris Dickinson) [#1456](https://github.com/nodejs/node/pull/1456) +* [[`4830b4bce8`](https://github.com/nodejs/node/commit/4830b4bce8)] - **deps**: add docs to upgrade openssl (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`11bec72c87`](https://github.com/nodejs/node/commit/11bec72c87)] - **deps**: update asm files for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`53924d8ebe`](https://github.com/nodejs/node/commit/53924d8ebe)] - **deps**: update asm Makefile for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`418e839456`](https://github.com/nodejs/node/commit/418e839456)] - **deps**: update openssl.gyp/gypi for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`02f12ab666`](https://github.com/nodejs/node/commit/02f12ab666)] - **deps**: update opensslconf.h for 1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`eb7a23595f`](https://github.com/nodejs/node/commit/eb7a23595f)] - **deps**: add x32 and arm64 support for opensslconf.h (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`033a663127`](https://github.com/nodejs/node/commit/033a663127)] - **deps**: replace all headers in openssl (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`ae8831f240`](https://github.com/nodejs/node/commit/ae8831f240)] - **deps**: backport openssl patch of alt cert chains 1 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`71316c46d9`](https://github.com/nodejs/node/commit/71316c46d9)] - **deps**: fix asm build error of openssl in x86_win32 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`d293a4f096`](https://github.com/nodejs/node/commit/d293a4f096)] - **deps**: fix openssl assembly error on ia32 win32 (Fedor Indutny) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`e4872d7405`](https://github.com/nodejs/node/commit/e4872d7405)] - **deps**: upgrade openssl to 1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`a1c9ef3142`](https://github.com/nodejs/node/commit/a1c9ef3142)] - **deps, build**: add support older assembler (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`76f219c128`](https://github.com/nodejs/node/commit/76f219c128)] - **doc**: Document forced pushing with git (Johan Bergström) [#1420](https://github.com/nodejs/node/pull/1420) +* [[`12e51d56c1`](https://github.com/nodejs/node/commit/12e51d56c1)] - **doc**: add Addon API WG (Rod Vagg) [#1226](https://github.com/nodejs/node/pull/1226) +* [[`7956a13dad`](https://github.com/nodejs/node/commit/7956a13dad)] - **http**: logically respect maxSockets (fengmk2) [#1242](https://github.com/nodejs/node/pull/1242) +* [[`5b844e140b`](https://github.com/nodejs/node/commit/5b844e140b)] - **module**: fix style (Roman Reiss) [#1453](https://github.com/nodejs/node/pull/1453) +* [[`3ad82c335d`](https://github.com/nodejs/node/commit/3ad82c335d)] - **(SEMVER-MINOR)** **module**: handle NODE_PATH in require('.') (Roman Reiss) [#1363](https://github.com/nodejs/node/pull/1363) +* [[`cd60ff0328`](https://github.com/nodejs/node/commit/cd60ff0328)] - **net**: add fd into listen2 debug info (Jackson Tian) [#1442](https://github.com/nodejs/node/pull/1442) +* [[`10e31ba56c`](https://github.com/nodejs/node/commit/10e31ba56c)] - **(SEMVER-MINOR)** **node**: allow multiple arguments passed to nextTick (Trevor Norris) [#1077](https://github.com/nodejs/node/pull/1077) +* [[`116c54692a`](https://github.com/nodejs/node/commit/116c54692a)] - **openssl**: fix keypress requirement in apps on win32 (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`62f5f4cec9`](https://github.com/nodejs/node/commit/62f5f4cec9)] - **src**: remove duplicate byteLength from Buffer (Jackson Tian) [#1438](https://github.com/nodejs/node/pull/1438) +* [[`51d0808c90`](https://github.com/nodejs/node/commit/51d0808c90)] - **stream**: remove duplicated expression (Yazhong Liu) [#1444](https://github.com/nodejs/node/pull/1444) +* [[`deb9d23d7b`](https://github.com/nodejs/node/commit/deb9d23d7b)] - **test**: fix error message check for openssl-1.0.2a (Shigeki Ohtsu) [#1389](https://github.com/nodejs/node/pull/1389) +* [[`ca8c9ec2c8`](https://github.com/nodejs/node/commit/ca8c9ec2c8)] - **win,node-gyp**: optionally allow node.exe/iojs.exe to be renamed (Bert Belder) [#1266](https://github.com/nodejs/node/pull/1266) ## 2015-04-14, Version 1.7.1, @rvagg diff --git a/doc/changelogs/CHANGELOG_V010.md b/doc/changelogs/CHANGELOG_V010.md index 0a728326dff..505a018438c 100644 --- a/doc/changelogs/CHANGELOG_V010.md +++ b/doc/changelogs/CHANGELOG_V010.md @@ -309,14 +309,16 @@ https://github.com/nodejs/node/commit/8d045a30e95602b443eb259a5021d33feb4df079 * uv: Update to v0.10.29 * child_process: properly support optional args (cjihrig) * crypto: Disable autonegotiation for SSLv2/3 by default (Fedor Indutny, - Timothy J Fontaine, Alexis Campailla) - This is a behavior change, by default we will not allow the negotiation to - SSLv2 or SSLv3. If you want this behavior, run Node.js with either - `--enable-ssl2` or `--enable-ssl3` respectively. - This does not change the behavior for users specifically requesting - `SSLv2_method` or `SSLv3_method`. While this behavior is not advised, it is - assumed you know what you're doing since you're specifically asking to use - these methods. + Timothy J Fontaine, Alexis Campailla) + + This is a behavior change, by default we will not allow the negotiation to + SSLv2 or SSLv3. If you want this behavior, run Node.js with either + `--enable-ssl2` or `--enable-ssl3` respectively. + + This does not change the behavior for users specifically requesting + `SSLv2_method` or `SSLv3_method`. While this behavior is not advised, it is + assumed you know what you're doing since you're specifically asking to use + these methods. ## 2014.09.16, Version 0.10.32 (Stable) diff --git a/doc/changelogs/CHANGELOG_V6.md b/doc/changelogs/CHANGELOG_V6.md index 709c03b9106..fbc0e2b6231 100644 --- a/doc/changelogs/CHANGELOG_V6.md +++ b/doc/changelogs/CHANGELOG_V6.md @@ -30,7 +30,6 @@ October 2016. - ## 2016-07-21, Version 6.3.1 (Current), @evanlucas ### Notable changes @@ -39,7 +38,7 @@ October 2016. * Improve performance of Buffer.from(str, 'hex') and Buffer#write(str, 'hex'). (Christopher Jeffrey) [#7602](https://github.com/nodejs/node/pull/7602) * Fix creating from zero-length ArrayBuffer. (Ingvar Stepanyan) [#7176](https://github.com/nodejs/node/pull/7176) * **deps**: - * Upgrade to V8 5.0.71.xx. (Ben Noordhuis) [#7531](https://github.com/nodejs/node/pull/7531) + * Upgrade to V8 5.0.71.57. (Ben Noordhuis) [#7531](https://github.com/nodejs/node/pull/7531) * Backport V8 instanceof bugfix (Franziska Hinkelmann) [#7638](https://github.com/nodejs/node/pull/7638) * **repl**: Fix issue with function redeclaration. (Prince J Wesley) [#7794](https://github.com/nodejs/node/pull/7794) * **util**: Fix inspecting of boxed symbols. (Anna Henningsen) [#7641](https://github.com/nodejs/node/pull/7641) diff --git a/doc/ctc-meetings/2016-06-15.md b/doc/ctc-meetings/2016-06-15.md index 4168b361313..9046cdee2ba 100644 --- a/doc/ctc-meetings/2016-06-15.md +++ b/doc/ctc-meetings/2016-06-15.md @@ -67,7 +67,7 @@ Extracted from **ctc-agenda** labelled issues and pull requests from the **nodej * Keeping up with issues * Brian White @mscdex (CTC) - * Landed some old PRs + * Landed some old PRs * Submitting PRs to fix some regressions * Reviewed PRs and issues diff --git a/doc/ctc-meetings/2016-06-22.md b/doc/ctc-meetings/2016-06-22.md new file mode 100644 index 00000000000..9e87b13b539 --- /dev/null +++ b/doc/ctc-meetings/2016-06-22.md @@ -0,0 +1,151 @@ +# Node Foundation CTC Meeting 2016-06-22 + +## Links + +* **Audio Recording**: TBP +* **GitHub Issue**: https://github.com/nodejs/node/issues/7366 +* **Minutes Google Doc**: +* _Previous Minutes Google Doc: _ + +## Present + +* Bradley Meck @bmeck (observer/GoDaddy/TC39) +* Chris Dickinson @chrisdickinson (CTC) +* Evan Lucas @evanlucas (CTC) +* James M Snell @jasnell (CTC) +* John-David Dalton @jdalton (observer/Lodash/Microsoft) +* Yuval Brik @jhamhader (observer) +* Josh Gavant @joshgav (observer/Microsoft) +* Michael Dawson @mhdawson (CTC) +* Brian White @mscdex (CTC) +* Ali Ijaz Sheikh @ofrobots (CTC) +* Shigeki Ohtsu @shigeki (CTC) +* Steven R. Loomis @srl295 (observer/IBM/ICU) +* Trevor Norris @trevnorris (CTC) +* Rich Trott @Trott (CTC) + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) + +## Standup + +* Bradley Meck @bmeck (observer/GoDaddy/TC39) + * Need for APM / JIT Cache hooks investigation + * Investigation into VM support for V8 and ES Modules +* Chris Dickinson @chrisdickinson (CTC) + * Keeping track of ES Modules proposals + * tooling gn to be npm installable +* Evan Lucas @evanlucas (CTC) + * working on security fixes + * looking for ways to streamline landing commits +* James M Snell @jasnell (CTC) + * Vacation last week (worked on an experimental http/2 impl) + * Working on WHATWG URL implementation + * Various other performance related and doc PRs + * And a heads up.. Will be on vacation again the 2nd and 3rd weeks of July. +* John-David Dalton @jdalton (observer/Lodash/Microsoft) + * Retooled proposal to simplify it and make it more generic so it will work with things other than just script and module + * Babel now supports export {} and therefore supports Unambiguous Modules proposal + * Pinged some v8 devs to ask about impact there + * Met with TypeScript folks too to discuss things that are a bit out of the scope of Unambiguous JavaScript but still modules + * Initial round of feedback on Unambiguous JavaScript. Will be in JavaScript Weekly tomorrow. +* Josh Gavant @joshgav (observer/Microsoft) + * hacking on inspector and tracing stuff + * es6 modules a bit + * monitoring issues, PRs, etc. +* Michael Dawson @mhdawson (CTC) + * Chasing PPC machine issues + * Chasing new AIX machines (expect this month) + * Contributing to ABI stable module API PoC (NaN examples 1-8 now work) + * Misc reviews/commenting + * misc PRs/lands + * Keeping up with issues +* Brian White @mscdex (CTC) + * Reviewing PRs/issues +* Shigeki Ohtsu @shigeki (CTC) + * Reviewing just one PR for root cert update. +* Steven R. Loomis @srl295 (observer/IBM/ICU) + * helping @jasnell (a little) with https://github.com/nodejs/node/pull/7355 +* Trevor Norris @trevnorris (CTC) + * Additional work on the AsyncWrap EP + * Misc PR reviews +* Rich Trott @Trott (CTC) + * CO: Continuous Onboarding (welcome @RReverser!) + * CI: Investigating and fixing flaky tests as time allows +* Ali Ijaz Sheikh @ofrobots(CTC) + * Working on FFI, and other miscellaneous things. + + +## Minutes + +### Review of last meeting + +* 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) +* ES6 Modules + +### fs.realpath + +- https://github.com/nodejs/node/issues/7175 +- https://github.com/nodejs/CTC/issues/9 +- https://github.com/nodejs/node/issues/7192 +- https://github.com/nodejs/node/issues/7044 +- https://github.com/nodejs/node/issues/7294 + +When we made changes to rely on libuv realpath it was a semver-major change which introduced new errors and removed `cache` argument. This broke some ecosystem modules, notably `glob`. Also broke some path-related stuff in Windows. + +We chose libuv realpath because it’s much more performant. + +Options: +- Revert to old behavior. Would lose perf gains. Would be semver-major change. +- Add new method e.g. `realpath2` which uses old behavior. +- **Keep new behavior and add logic in Node to handle new/unexpected errors.** + +@jasnell - We did a semver-major revert for the symlink issue.
+@trevnorris - No need to revert, just handle the errors.
+@jasnell - Do we really know what the errors are so we can be sure we’re handling all of them?
+@trevnorris - we can compare to old impl.
+@jasnell - Add an option to the options object to suppress errors, turn on by default.
+ +**@trevnorris will work on option 3.** + +Post-mortem: https://github.com/nodejs/CTC/issues/9 +- Postpone till Rod is present. +- @jasnell - We didn’t follow typical deprecation path for `cache` parameter change. + + +### ES6 modules + +- https://github.com/bmeck/UnambiguousJavaScriptGrammar + +- Any code with `import` or `export` is a module, otherwise a script. +- `modules.root` aspect removed, so “fat packages” (i.e. incl. both ES6 and CJS) are not addressed. Recommendation is to use one or the other and transpile as needed. Or discuss `modules.root` separately. +- Users can explicitly specify module goal in package.json. This way even if dev removes all `import/export` from their code it’s still treated as a module. +- TC39 could provide a “recommendation” or endorsement supporting this. They may suggest a spec extension. + +@bradleymeck - still need modules.root for fat packages. + +What about bytecode caching? Provide hooks to allow user to handle as desired. That means caching is in userland. Might split this into separate proposal. + +@trevnorris analyzed perf hit of double parsing and found max 25% perf hit. + +In-band detection (from the code itself) is preferable to out-of-band detections (e.g. package.json, file extension). + +CJS and ES6 semantic interoperability: Bradley is working on this, working with WHATWG Loader spec and V8. +- `this` value +- live bindings for getters (get updated values) (?) +- immutability - hooks for APM providers to wrap original functions. To be handled by WHATWG Loader spec. + +**@jdalton - How do we finalize consensus on this?** +- **PR to change [node-eps:/002-es6-modules.md](https://github.com/nodejs/node-eps/blob/master/002-es6-modules.md)** + +### Q/A on public fora +None. + +### Next Meeting +2016-06-29 diff --git a/doc/ctc-meetings/2016-06-29.md b/doc/ctc-meetings/2016-06-29.md new file mode 100644 index 00000000000..859cdc1df27 --- /dev/null +++ b/doc/ctc-meetings/2016-06-29.md @@ -0,0 +1,187 @@ +# Node Foundation CTC Meeting 2016-06-29 + +## Links + +* **Audio Recording**: TBP +* **GitHub Issue**: https://github.com/nodejs/node/issues/7474 +* **Minutes Google Doc**: +* _Previous Minutes Google Doc: _ + +## Present + +* Bradley Meck @bmeck (observer/GoDaddy/TC39) +* Сковорода Никита Андреевич @ChALkeR (CTC) +* Colin Ihrig @cjihrig (CTC) +* Evan Lucas @evanlucas (CTC) +* Jeremiah Senkpiel @Fishrock123 (CTC) +* James M Snell @jasnell (CTC) +* John-David Dalton @jdalton (observer/Lodash/Microsoft) +* Josh Gavant @joshgav (observer/Microsoft) +* Michael Dawson @mhdawson (CTC) +* Brian White @mscdex (CTC) +* Ali Ijaz Sheikh @ofrobots (CTC) +* Rod Vagg @rvagg (CTC) +* Trevor Norris @trevnorris (CTC) +* Rich Trott @Trott (CTC) + + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* New Buffer API backport to v4.x [#7475](https://github.com/nodejs/node/pull/7475) +* child_process: validate fork/execFile arguments [#7399](https://github.com/nodejs/node/pull/7399) +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) +* repl: Default `useGlobal` to false in CLI REPL. [#5703](https://github.com/nodejs/node/pull/5703) +* Seek legal advice on LICENSE and copyright blocks in code [#3979](https://github.com/nodejs/node/issues/3979) + +### nodejs/LTS + +* Mention odd-number release has eight months support as Current. [#113](https://github.com/nodejs/LTS/issues/113) + +### nodejs/node-eps + +* AsyncWrap public API proposal [#18](https://github.com/nodejs/node-eps/pull/18) + +## Standup + +* Bradley Meck @bmeck (observer/GoDaddy/TC39) + * Trying to gather all stakeholders in ES Module implementations into a meeting + * Back and forth with V8 about details of CJS bridge +* John-David Dalton @jdalton (observer/Lodash/Microsoft) + * Dropped caching from unambiguous JS proposal + * PR to Node EPS repo + * Discussed with V8 (Adam Klein) and Chakra about adding the API, no blockers +* Сковорода Никита Андреевич @ChALkeR (CTC) + * Filed #7475 to backport new Buffer API to 4.x LTS +* Colin Ihrig @cjihrig (CTC) + * Reviewing issues and PRs. Made a couple libuv PRs. +* Evan Lucas @evanlucas (CTC) + * Merged pr to allow passing prompt to readline + * Merged pr that prints experimental warning when using inspector + * Worked on v6.x branch a little +* Jeremiah Senkpiel @Fishrock123 (CTC) + * Was away a bit adjusting to Europe. + * Misc PRs/Issues work. + * Also working to resolve https://github.com/nodejs/node/issues/5426 (ages old timers issue) +* Josh Gavant @joshgav (observer/Microsoft) + * Scheduled next Diag WG meeting (7/13 12 Pacific) (https://github.com/nodejs/diagnostics/issues/60) + * “Inspector Gateway” proposal (https://github.com/nodejs/node/issues/7393) + * Module discussions +* Michael Dawson @mhdawson (CTC) + * Testing problematic PPC machine after move to new node, adding back to regular CI runs + * Working on ABI stable API prototype with Ian/Sampson + * Post mortem work with Richard C + * Misc PR reviews/lands + * Adding linuxOne to master test jobs in CI (since 5.1 landed there) + * LTS, Build WG meetings + * Starting to work on presentations for upcoming conferences +* Brian White @mscdex (CTC) + * Landed a fix for a StringDecoder regression + * Reviewed PRs, commented on issues +* Ali Ijaz Sheikh @ofrobots (CTC) + * Busy with non-Node stuff mostly. +* Rod Vagg @rvagg (CTC) + * Chat with Electron team + * Foundation board meeting + * npm publish bug hunt + * node-gyp release, fix for latest MSVS 2015 release +* Steven R Loomis @srl295 (observer/IBM/ICU) + * regrets for this meeting- nothing to add at this point(hopefully soon) +* Trevor Norris @trevnorris (CTC) + * working on solution for user API for AsyncWrap (?) +* Rich Trott @Trott (CTC) + * child_process fixes + * examining https://node-core-coverage.addaleax.net/ results (thanks, @addaleax!) + * re-certifying flaky tests + +## Minutes + +### child_process: validate fork/execFile arguments [#7399](https://github.com/nodejs/node/pull/7399) + +@trott: Semver-major change requires review. + +@trott: fixing a bug that James filed some time ago - if nonsensical arguments are passed to these methods they silently ignore those arguments. Rich and James think it should throw if you give it garbage. + +@nodejs/ctc: No objections. + +### Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) + +@trevnorris was to work on capturing new errors and handling them. Discovered that all fs methods suffer same issue. Trevor has idea on how to handle it, will submit PR in the next day or two. + +@bzoz understands Windows issues and will address them. + +### buffer: backport --zero-fill-buffers command line option [#5745](https://github.com/nodejs/node/pull/5745) + +See also [#7475](https://github.com/nodejs/node/pull/7475). + +Backport to v4. Was discussed and CTC thought it wasn’t a good idea, but want to revisit now. What was previous issue? @Fishrock123 - another change, possibly security-related, blocked it. + +@rvagg: Same objections as backport to 0.12, should be treated the same. + +@nodejs/ctc: No objections currently. This is relevant to security. + +### repl: Default `useGlobal` to false in CLI REPL. [#5703](https://github.com/nodejs/node/pull/5703) + +* Some discussion in the original issue: https://github.com/nodejs/node/issues/5659#issuecomment-195543607 +* Moving back to GitHub. + +### Mention odd-number release has eight months support as Current. [lts#113](https://github.com/nodejs/LTS/issues/113) + +* Current state is that Current (formerly Stable) branch is supported for **two** months after next release but some people think it’s **three** months. For example, v5 is supported till end of June 2016. But we’d like this to be stated clearly. + +@mhdawson: discussion in last LTS meeting but it’s not in the scope of the LTS WG’s work so it’s up to the CTC. Is it Current+2 or Current+3? + +@nodejs/ctc: Previous Current version is supported for two months after next version is released. + +@rvagg: v5 is still heavily used. + +@Fishrock123: npm metrics also show high usage of v5, not much decline. + +Need to make clear that people need to upgrade. Should we push this harder or adjust to usage pattern? + +@nodejs/ctc: Stick with plan to stop supporting v5 shortly. + +Metrics: https://nodejs.org/metrics/summaries/version.png + + +### AsyncWrap public API proposal [node-eps#18](https://github.com/nodejs/node-eps/pull/18) + +@Fishrock123 - responses have been primarily positive, time for CTC to consider. + +@rvagg - Goal is to raise awareness amongst CTC today, vote on it next week. + +@rvagg - currently marked as experimental. We should associate a message/warning with experimental API usage. EPs are for experimental APIs. + +@trevnorris - AsyncWrap cannot track callbacks from native addons. Also investigating why sometimes messages are dropped (?). + +### replace section 5.1 with unambiguous JavaScript grammar [node-eps#33](https://github.com/nodejs/node-eps/pull/33) + +@jdalton wants to get agreement from Node.js CTC so that he can proceed to browser vendors. + +TC39 may want to add other “goals” for files in addition to module and script such as asm.js, “frozen realms”. + +@rvagg: If we go with `.mjs` we’d have to have extensions for new parse goals too... + +@rvagg: We prefer a spec change in TC39/ES262 or an acknowledgement at least. @jdalton will add that caveat into the PR. + +@Fishrock123: What about avoiding double parsing? +@bmeck: Chakra said maybe, V8 said probably not. @trevnorris did benchmarks and they weren’t too bad. + +`module.root` for fat packages? With .mjs it wasn’t needed, people would include .js and .mjs files; but with new proposal it is needed. However `module.root` isn’t foolproof because people could use it for general redirection/hiding of package internals instead of only for ES6 modules. + +@rvagg: Let’s slate for vote on Wednesday 7/6, those who are unavailable can vote in the issues. + +## Q/A on public fora + +None. + +## Next Meeting + +* AsyncWrap public API proposal [node-eps#18](https://github.com/nodejs/node-eps/pull/18) +* replace section 5.1 with unambiguous JavaScript grammar. +[node-eps#33](https://github.com/nodejs/node-eps/pull/33) + +CTC: 2016-07-06 diff --git a/doc/ctc-meetings/2016-07-06.md b/doc/ctc-meetings/2016-07-06.md new file mode 100644 index 00000000000..232b83b9c7d --- /dev/null +++ b/doc/ctc-meetings/2016-07-06.md @@ -0,0 +1,150 @@ +# Node Foundation CTC Meeting 2016-07-06 + +## Links + +* **Audio Recording**: TBP +* **GitHub Issue**: https://github.com/nodejs/node/issues/7558 +* **Minutes Google Doc**: +* _Previous Minutes Google Doc: _ + +## Present + +* Сковорода Никита Андреевич @ChALkeR (CTC) +* Colin Ihrig @cjihrig (CTC) +* Evan Lucas @evanlucas (CTC) +* Jeremiah Senkpiel @Fishrock123 (CTC) +* James Snell @jasnell (CTC) +* John-David Dalton @jdalton (observer/Microsoft) +* Josh Gavant @joshgav (observer/Microsoft) +* Michael Dawson @mhdawson (CTC) +* Brian White @mscdex (CTC) +* Alexis Campailla @orangemocha (CTC) +* Shigeki Ohtsu @shigeki (CTC) +* Trevor Norris @trevnorris (CTC) +* Rich Trott @Trott (CTC) + +## Standup + +* Сковорода Никита Андреевич @ChALkeR (CTC) + * Nothing significant. +* Colin Ihrig @cjihrig (CTC) + * Reviewed issues. Reviewed pull requests. Opened a couple PRs +* Evan Lucas @evanlucas (CTC) + * Commented on a few issues, not much else +* Jeremiah Senkpiel @Fishrock123 (CTC) + * v6.3.0 Release, most difficult to date, lots of merge conflicts. + * Various PR / Issue review +* John-David Dalton @jdalton (observer/Microsoft) + * Another round of questions with Chakra dev about Unambiguous JS Grammar confirming difficulty level of API is not significant + * Updated Unambiguous JS Grammar based on feedback +* Josh Gavant @joshgav (observer/Microsoft) + * Out for July 4th holiday. +* Michael Dawson @mhdawson (CTC) + * Added linuxOne to regression tests/watched for issues, all looks good, next step is to add to nightly releases + * Chasing down AIX build breaks test failures + * Continued work on ABI stable module API and scheduling of next WG meeting + * misc PR/Issue reviews/pull requests + * post-mortem work and scheduling of next meeting + * small update to benchmark graphs + * keeping up to date with issues +* Brian White @mscdex (CTC) + * Started the process of rebasing the old js http parser onto master to see how it compares to the current http implementation + * Reviewed PRs, commented on issues +* Alexis Campailla @orangemocha (CTC) + * Nothing to report (was out on vacation) +* Shigeki Ohtsu @shigeki (CTC) + * Reviewed only one PR for crypto doc +* Trevor Norris @trevnorris (CTC) + * Updated AsyncWrap EP + * fs.realpath() deep symlink PR +* Rich Trott @Trott (CTC) + * Onboarded @bzoz + * Fixing test-net-write-slow on FreeBSD (PR #7555) +* James M Snell @jasnell (CTC) + * WHATWG http implementation + * Closing up other business before going on vacation for a week + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/issues/7484) +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) + +### nodejs/node-eps + +* Replace section 5.1 with unambiguous JavaScript grammar. [#33](https://github.com/nodejs/node-eps/pull/33) +* AsyncWrap public API proposal [#18](https://github.com/nodejs/node-eps/pull/18) + +## Previous Meeting + +* New Buffer API backport to v4.x [#7475](https://github.com/nodejs/node/pull/7475) + + * New PR: https://github.com/nodejs/node/pull/7562 + +* child_process: validate fork/execFile arguments [#7399](https://github.com/nodejs/node/pull/7399) +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) +* repl: Default `useGlobal` to false in CLI REPL. [#5703](https://github.com/nodejs/node/pull/5703) +* Seek legal advice on LICENSE and copyright blocks in code [#3979](https://github.com/nodejs/node/issues/3979) +* Mention odd-number release has eight months support as Current. [#113](https://github.com/nodejs/LTS/issues/113) +* AsyncWrap public API proposal [#18](https://github.com/nodejs/node-eps/pull/18) + +## Minutes + +### build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/issues/7484) (@jasnell) + +Consider v6 and v7 separately. All agree on moving to VS 2015 for v7. Only question is v6 prior to LTS. We need more info to make decision on v6. + +If we stay with 2013 for v6 we’ll have to support it for the entire lifetime of v6 LTS. But it needs to still be possible to build native addons with 2013. + +@jasnell - Our recommendation is to build native addons with VS 2015 unless it doesn’t work (e.g. in [node-sass#1283](https://github.com/sass/node-sass/issues/1283). + +@orangemocha - No problem building `node.exe` with VS 2015 in v7. But dropping support for 2013 would break some modules (breaking change) due to ABI incompatibilities, so it might not be appropriate for v6. Need more time to assess impact. + +### Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) + +@trevnorris - fix is working, test in development. Comment further in the PR. + +### Replace section 5.1 with unambiguous JavaScript grammar. [#33](https://github.com/nodejs/node-eps/pull/33) + +@jdalton added line stating explicitly that the .mjs proposal is still possible. + +Vote taken in favor of merging this PR. Alexis officially abstained. + +### AsyncWrap public API proposal [#18](https://github.com/nodejs/node-eps/pull/18) + +See also [#7565](https://github.com/nodejs/node/issues/7565), which questions whether AsyncWrap should exist (from @bnoordhuis). + +@jasnell - Error handling should be addressed. + +@trott - A vote for the EP means “*if* we implement, this is what the JavaScript API will look like” and not necessarily “we intend to implement this.” + +@trevnorris - Correct. Confirm the API, then more work is needed on implementation, e.g. to include info on promises. + +@trevnorris - biggest missing chunk is public C++ API. Trouble is that it requires exposing some things which are not currently in public headers. + +@trevnorris - Goal is to include this as experimental in v6 before LTS. But still waiting on additional hooks into promises from V8. + +@Fishrock123 - AsyncWrap is best bet for CLS across async activities, replaces deprecated domains. + +Vote: 7-8 ayes, 0 opposed, 0 abstentions. + + +## Q/A on public fora + +None. + +## Next Meeting + +* Move to VS 2015 for release build in v6? Is this a breaking change? + +## Upcoming TLP & WG Meetings + +* CTC: 2016-07-13 +* TSC: 2016-07-14 +* Diagnostics: 2016-07-13 +* Post-Mortem: [nodejs/post-mortem#31](https://github.com/nodejs/post-mortem/issues/31) +* LTS: +* Build: diff --git a/doc/ctc-meetings/2016-07-13.md b/doc/ctc-meetings/2016-07-13.md new file mode 100644 index 00000000000..0c38f3b066a --- /dev/null +++ b/doc/ctc-meetings/2016-07-13.md @@ -0,0 +1,236 @@ +# Node Foundation CTC Meeting 2016-07-13 + +## Links + +* **Audio Recording**: TBP +* **GitHub Issue**: https://github.com/nodejs/node/issues/7707 +* [Minutes Google Doc](https://docs.google.com/document/d/1fP9_ZNcPoFh2VWCgUFu9-rDiDcMP88vhCC_oX6Aj528) +* _[Previous Minutes Google Doc](https://docs.google.com/document/d/1NWIKwYxDTApvc9Xbq5JTMorRPKIBuBKAA0zcjm8K_II)_ + +## Present + +* Anna Henningsen @addaleax (observer) +* Bradley Meck @bmeck (observer/GoDaddy/TC39) +* Ben Noordhuis @bnoordhuis (CTC) +* Colin Ihrig @cjihrig (CTC) +* Evan Lucas @evanlucas (CTC) +* Jeremiah Senkpiel @Fishrock123 (CTC) +* Fedor Indutny @indutny (CTC) +* 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) +* Stephen Loomis @srl295 (observer/ICU) +* Myles Borins @TheAlphaNerd (observer) +* Trevor Norris @trevnorris (CTC) +* Rich Trott @Trott (CTC) + + +## Standup + +* Anna Henningsen @addaleax (observer) + * PRs & issues + * Some v4.x backports +* Bradley Meck @bmeck (observer/GoDaddy/TC39) + * Bad news from V8/Chakra. Can’t do property hoisting for Babel like CJS interop. + * Figuring out hooks for creating Modules in older Node versions +* Ben Noordhuis @bnoordhuis (CTC) + * Back-porting patches + * Moving stuff over from malloc() to new[] because of AIX + * ABI compatibility tool + * PRs & issues, of course - how could I forget? +* Colin Ihrig @cjihrig (CTC) + * Reviewed issues and PRs + * Opened a few PRs +* Evan Lucas @evanlucas (CTC) + * Simple doc fix + * Working on cherry-picking into v6.x +* Jeremiah Senkpiel @Fishrock123 (CTC) + * Fixed a TTY test that was silently failing for over a year + * misc PR & issue work +* Fedor Indutny @indutny (CTC) + * Various GYP-related tooling + * Code reviews, and fixing issues +* Josh Gavant @joshgav (observer/Microsoft) + * Diagnostics WG meeting + * debugging docs +* Michael Dawson @mhdawson (CTC) + * Added LinuxOne to v8 tests in CI + * Involvement on some AIX issues + * Working on ABI stable API, API WG meeting this week + * Re-scheduled post-mortem WG meeting for next week, LTS and diagnostic WG meetings + * misc reviews/lands and keeping up on issues +* Brian White @mscdex (CTC) + * Worked on PR to check for accidental git conflict markers when linting in CI + * Backported some commits to v4.x + * Reviewed PRs and commented on issues +* Ali Ijaz Sheikh @ofrobots (CTC) + * Back from vacation, buried in email (sorry for late responses!) +* Alexis Campailla @orangemocha (CTC) + * Investigating ABI incompatibilities. Preparing to drop VS 2013. + * Reviewed miscellaneous Windows issues. + * Resumed work on a PR for case normalization of the module cache on Windows +* Rod Vagg @rvagg (CTC) + * LTS README rework +* Steven Loomis @srl295 (observer/ICU) + * not much here, just trying to keep an eye on issues/PRs +* Myles Borins @TheAlphaNerd (observer) + * Working on v4.5.0 release https://github.com/nodejs/node/pull/7688 + * CITGM Enhancements (XML + Queue) + * Working with V8 team to improve workflow for managing floated commits https://github.com/nodejs/LTS/issues/111 +* Trevor Norris @trevnorris (CTC) + * Working fix for one of the realpath bugs + * Backporting for v4.x + * Working on AsyncWrap implementation details +* Rich Trott @Trott (CTC) + * Trying to handle flaky test outbreak on FreeBSD in CI + * Various ESLint updates/improvements + * Banging my head against test-tick-processor flakiness which is easily the longest-standing flaky test. + + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/pull/7484) +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/pull/7175) +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) +* v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) + +### nodejs/node-eps + +* proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + + +## Previous Meeting + +### build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/issues/7484) (@jasnell) + +To be discussed again. + +### Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) + +@trevnorris was to complete changes, to be discussed again. + +### Replace section 5.1 with unambiguous JavaScript grammar. [#33](https://github.com/nodejs/node-eps/pull/33) + +@jdalton’s proposal was merged. + +### AsyncWrap public API proposal [#18](https://github.com/nodejs/node-eps/pull/18) + +API was accepted, implementation TBD before October. + + +## Minutes + +### build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/issues/7484) + +@orangemocha: Decision to drop in v7 isn’t controversial. Will need to add tests for modules compiled with 2013 used with Node compiled with 2015. + +@orangemocha: Main question is switching in v6 before LTS. Is it a breaking change? + +Issue with node-sass module only comes up on Windows XP so can be discounted. + +No way to be sure if user modules compiled with 2013 might be incompatible with Node compiled with 2015. Have to run tests. Will CITGM provide sufficient testing? + +@myles: may not be enough native modules in CITGM to provide confidence. + +@Fishrock123: be sure to also test on pre-gyp’ed modules. + +@orangemocha: we may never have complete confidence that this isn’t a breaking change, but node-sass is the only issue ever reported. + +@orangemocha: Should we support modules built with 2013 in v7? +@rvagg: need to include that in tests. + +**Next steps**: Run tests with modules compiled with 2013 to see if there are issues. Keep on agenda for next week and check on progress. + +### Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/pull/7175) + +* ELOOP fix: https://github.com/nodejs/node/pull/7548 +* Windows PR: https://github.com/nodejs/node/pull/7559 (see also https://github.com/nodejs/node/issues/7192) + +ELOOP issue has been resolved. Windows problem being addressed in another PR. May have to use JS impl for Windows. + +@rvagg: If libuv can’t handle the realpath issue for Windows what should we do? + +@orangemocha: We’re using the JS impl for Windows. + +@trevnorris: we can use the libuv impl and defer to the JS impl if the libuv impl throws unexpectedly. + +@rvagg: should we just revert? How common is the case where this provides a speed-up? + +@trevnorris: keep both libuv and js impl for now. + +**Next steps**: All please review #7548 and #7559. + +### http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +@mscdex: Prevent clash of header names with properties inherited from Object (e.g., `__proto__`). An object with a null prototype is already being used for the same purpose in `querystring.parse` since v6 release. + +@mscdex: Some have suggested cherry-picking some methods from Object such as `toString`: + + * So that object can be inspected. + * To ensure backward compatibility. + +@mscdex: An eventual goal may be to store headers in an ES6 Map instead of on a plain object, but that will change the API considerably. + +@evanlucas: we should follow what we did with query string parameters. + +@rvagg: first need to review as some opposition to that. + +**Next steps**: All review PR. + +### proposal: WHATWG URL standard implementation [node-eps#28](https://github.com/nodejs/node-eps/pull/28) + +@trevnorris: Some discussion about supporting unregistered schemes (e.g. `chrome://`). We should support them, Chrome supports them. + +@trevnorris: `url.parse` can handle incomplete URLs (e.g. no scheme). + +@rvagg: Most important question is should `URL` be a global? There would be a `url` module and a different `URL` global. + +@fishrock123: there would be a transition period and then functionality would be in `URL` + +@rvagg: new impl is quite different from existing `url` module. Would like to see a diff. Migration will be difficult. + +**Next steps**: Waiting for @jasnell to return. Review again next week. + +### v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) + +@thealphanerd: + +* Would like to include libuv v1.9.1. +* Would like very extensive testing prior to release to exclude breaking changes. + +How can we best test? + +@rvagg: Promote the RC on social media. + +@thealphanerd: npm could help test, Myles will reach out. + +@rvagg: Heroku? (Hunter Loftis) Travis CI? Probably not because it depends on nvm which doesn’t do RC’s yet. + +@thealphanerd: will talk with @ljharb about nvm support for RCs. + +**Next steps**: @thealphanerd will ping all to test RC. + +### ES Modules update + +@bmeck: named imports from CJS modules (e.g. `import {use, route} from "express"` or `import {readFile, readFileSync} from "fs"`) can’t work. + +Updates to come on the topic via: https://github.com/nodejs/node-eps/issues/26 + +## Q/A on public fora + +## Upcoming Meetings + +* CTC: 2016-07-20 +* TSC: 2016-07-14 +* Diagnostics: 2016-08-03 +* Post-Mortem: 2016-07-18 +* API: 2016-07-14 +* LTS: 2016-07-25 +* Build: 2016-07-19 diff --git a/doc/ctc-meetings/2016-07-20.md b/doc/ctc-meetings/2016-07-20.md new file mode 100644 index 00000000000..02f16ae2ac2 --- /dev/null +++ b/doc/ctc-meetings/2016-07-20.md @@ -0,0 +1,202 @@ +# Node Foundation CTC Meeting 2016-07-20 + +## Links + +* **Audio Recording**: TBP +* **GitHub Issue**: https://github.com/nodejs/node/issues/7809 +* **Minutes Google Doc**: +* _Previous Minutes Google Doc: _ + +## Present + +* Anna Henningsen @addaleax (observer) +* Ben Noordhuis @bnoordhuis (CTC) +* Сковорода Никита Андреевич @ChALkeR (CTC) +* Colin Ihrig @cjihrig (CTC) +* Evan Lucas @evanlucas (CTC) +* Jeremiah Senkpiel @Fishrock123 (CTC) +* Josh Gavant @joshgav (observer/Microsoft) +* Michael Dawson @mhdawson (CTC) +* Julien Gilli @misterdjules (CTC) +* Brian White @mscdex (CTC) +* Ali Ijaz Sheikh @ofrobots (CTC) +* Alexis Campailla @orangemocha (CTC) +* Rod Vagg @rvagg (CTC) +* Seth Thompson @s3ththompson (observer/Google) +* Shigeki Ohtsu @shigeki (CTC) +* Steven R Loomis @srl295 (observer/IBM/ICU) +* Myles Borins @TheAlphaNerd (observer) +* Trevor Norris @trevnorris (CTC) +* Rich Trott @Trott (CTC) + + +## Standup + +* Anna Henningsen @addaleax (observer) + * Issues & PRs + * looking into porting JS-based realpath to C +* Ben Noordhuis @bnoordhuis (CTC) + * The usual (PR review and comment) + * Updating code base to do less manual memory management. PR coming soon. +* Сковорода Никита Андреевич @ChALkeR (CTC) + * Some initial work on docs linting. + * Some comments on issues and PRs. +* Colin Ihrig @cjihrig (CTC) + * Reviewed issues and PRs + * Opened PRs +* Evan Lucas @evanlucas (CTC) + * working on v6.3.1 release + * working on repl bugfix +* Jeremiah Senkpiel @Fishrock123 (CTC) + * Did some timers review for https://github.com/nodejs/node/commit/5aac4c42da104c30d8f701f1042d61c2f06b7e6c + * Clearing out some other old stuff I’ve assigned myself to +* Josh Gavant @joshgav (observer/Microsoft) + * Internal Microsoft work. +* Michael Dawson @mhdawson (CTC) + * Misc issues with PPC machines, added new PPC + machines from newer openstack + * Working with Ian/Sampson on ABI stable abi, status + update at API WG meeting + * Working with Richard/Howard on post-mortem activities, + post-mortem WG meeting this week. + * Misc reviews/lands + * Reading/keeping up/commenting on issues + * Getting ready for Node Summit talk. +* Julien Gilli @misterdjules (CTC) + * Looking forward to getting more involved again + * Investigating timers bug. Looking for someone to mentor on it + * Reviewing and commenting on pull requests +* Brian White @mscdex (CTC) + * Diving deep into reworking API docs + * Reviewing PRs, commenting on issues +* Ali Ijaz Sheikh @ofrobots (CTC) + * shepherding some V8 backports, v8_inspector license issue and roll +* Alexis Campailla @orangemocha (CTC) + * Nothing to report. +* Rod Vagg @rvagg (CTC) + * Usual administrative stuff, some build maintenance +* Seth Thompson @s3ththompson (observer/Google) + * Setting priorities for the next quarter. + * Team is continuing work on v8_inspector. + * Migrating v8_inspector into V8 itself. +* Shigeki Ohtsu @shigeki (CTC) + * Nothing special. Working internal jobs. +* Steven R Loomis @srl295 (observer/IBM/ICU) + * Nodesummit prep… +* Myles Borins @TheAlphaNerd (observer) + * v4.5.0-rc.2 released + * Email sent to npm team +* Trevor Norris @trevnorris (CTC) + * realpath fix +* Rich Trott @Trott (CTC) + * CTC governance doc updates + * onboarded @andrasq, will set up something with @princejwesley next, open to other nominations for after that + * eliminating more flaky tests (IT NEVER ENDS!!!!11!!!) + + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* [meta] realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) +* v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +### nodejs/node-eps + +* proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + +## Previous Meeting + +* build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/pull/7484) + +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/pull/7175) + +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +* v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) + +* proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + +## Minutes + +### [meta] realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) + +@rvagg: some discussion of reversion to v5 behavior, i.e. JS implementation rather than libuv implementation. + +@trevnorris: looks like everybody’s leaning towards a full revert (or at least a partial revert). I don’t like this plan but will go along. + +@addaleax: Unfortunate to have to do full revert for *nix systems. But having alternate impl for Windows increases maintenance costs. + +As part of the new implementation, the `cache` parameter was removed from the method. It was created to improve perf for the JS impl but is considered less necessary since the native impl performs better anyway. + +Should we reinstate the `cache` parameter as part of the revert? Would this be a semver-major again? Does caching in the JS impl provide a significant perf benefit? + +@addaleax: Benchmarking fs perf will show how much benefit the caching capability in libuv provides. + +@mhdawson: we run two benchmarks nightly: one with caching and one without. + +@orangemocha: It seems okay to have two impl’s, one for Windows and one for *nix, increased maintenance surface isn’t a concern, libuv manages libuv impl. + +@rvagg: As we move v6 to LTS it would be best to have a known-good implementation. So would prefer a full revert, then fix libuv impl independently, then re-integrate. + +@thealphanerd: Could we provide both interfaces? Revert the primary one to original behavior and add a second one with libuv behavior? + +@rvagg: Still doesn’t address breaking change in Windows. + +@fishrock123: also in favor of reverting. This has been going on for a long time, best to revert and then fix. + +@orangemocha: should not compromise correctness for performance. + +@trevnorris: caching could be separated from fs API. For example, it could be part of `module` module. + +@rvagg: This is why I’m in favor of a full reversion. These other discussions may continue for a month and we need to correct problem now. + +@thealphanerd: do we have a list of the original bugs the libuv patch addressed? + +@saghul has a list. + +@rvagg: back to github for now. + +**Next steps**: continue discussion in GH. + +### v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) + +@thealphanerd is raising visibility for tests and feedback. + +@misterdjules may have some testers. + +### http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +@rvagg: Need choices to vote on. + +@ofrobots: Wants to explore more options including `map` so wait for vote. If the goal is to go to a map why don’t we do that now? + +@Fishrock123: Because community has taken dependencies on it being an object. + +@ofrobots: headers end up with “megamorphic IC’s” so wants to research further. + +@Fishrock123: We are fixing this because header names like `__proto__` conflict with default object properties. + +We should really just make an API for headers. + +@rvagg: We’ll come back to this next week. Prepare wording for vote if ready. + +**Next steps**: List available options and conduct vote next week. + + +## Q/A on public fora + +None. + +## Upcoming Meetings + +* CTC: 2016-07-27 +* TSC: 2016-07-28 +* Build: 2016-08-07 +* LTS: 2016-07-25 +* Diagnostics: 2016-08-03 +* Post-Mortem: August +* API: August diff --git a/doc/ctc-meetings/2016-07-27.md b/doc/ctc-meetings/2016-07-27.md new file mode 100644 index 00000000000..d0b19393865 --- /dev/null +++ b/doc/ctc-meetings/2016-07-27.md @@ -0,0 +1,237 @@ +# Node Foundation CTC Meeting 2016-07-27 + +## Links + +* **Audio Recording**: https://www.youtube.com/watch?v=QAufnqo4ElY +* **GitHub Issue**: https://github.com/nodejs/node/issues/7881 +* **Minutes Google Doc**: +* _Previous Minutes Google Doc: _ + +## Present + +* Anna Henningsen @addaleax (observer) +* Сковорода Никита Андреевич @ChALkeR (CTC) +* Jeremiah Senkpiel @Fishrock123 (CTC) +* Fedor Indutny @indutny (CTC) +* James M Snell @jasnell (CTC) +* Julien Gilli @misterdjules (CTC) +* Mikeal Rogers @mikeal (observer/Node.js Foundation) +* Brian White @mscdex (CTC) +* Alexis Campailla @orangemocha (CTC) +* Rod Vagg @rvagg (CTC) +* Steven R Loomis @srl295 (observer/IBM/ICU) +* Trevor Norris @trevnorris (CTC) +* Rich Trott @Trott (CTC) +* William Kapke @williamkapke (observer) + + +## Standup + +* Anna Henningsen @addaleax (observer) + * Issues & PRs + * Some realpath work +* Сковорода Никита Андреевич @ChALkeR (CTC) + * Mostly comments and reviews, nothing significant +* Fedor Indutny @indutny (CTC) + * Issues, PRs, Direct-to-BIO experiments +* James M Snell @jasnell (CTC) + * Glorious vacation … + * Catching up + * Small clarification PR for IRC moderation +* Julien Gilli @misterdjules (CTC) + * PR reviews, especially https://github.com/nodejs/node/pull/7827, which looks like a very solid first contribution from a new contributor. +* Brian White @mscdex (CTC) + * Continued reworking of API docs + * Reviewed PRs, commented on issues +* Alexis Campailla @orangemocha (CTC) + * Investigating issues related to fs.realPath + * Investigating binary compatibility between Node and native modules compiled with different VS versions + * Working with team on various Windows issues in Node and libuv +* Rod Vagg @rvagg (CTC) + * NodeSummit / travel, Node v5 blog post nearly ready to post, bug in require() (still need to post in nodejs/node) + * Steven R Loomis @srl295 (observer/IBM/ICU) + * @ NodeSummit / prep… thinking about how to keep an eye on upcoming v8 changes. Did some more work on https://github.com/nodejs/node/issues/3460 (detect full-icu module). +* Trevor Norris @trevnorris (CTC) + * NodeSummit talk + * fs.realpath() + * Prepping AsyncWrap, target end of August +* Rich Trott @Trott (CTC) + * Updating governance text and whatnot + * Flaky tests + * NodeSummit talk +* William Kapke @williamkapke (Observer) + + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* Role of CTC in semver-major changes needs clarification [#7848](https://github.com/nodejs/node/issues/7848) +* Revert fs changes [#7846](https://github.com/nodejs/node/pull/7846) +* doc: add information about CTC quorum rules [#7813](https://github.com/nodejs/node/pull/7813) +* meta: provide example activities [#7744](https://github.com/nodejs/node/pull/7744) +* meta: realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) +* v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) +* punycode: deprecate punycode module [#7552](https://github.com/nodejs/node/pull/7552) +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) +* Seek legal advice on LICENSE and copyright blocks in code [#3979](https://github.com/nodejs/node/issues/3979) + +### nodejs/post-mortem + +* Repositories to contribute collaboratively [#30](https://github.com/nodejs/post-mortem/issues/30) + +### nodejs/node-eps + +* proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + + +## Previous Meeting + +### nodejs/node + +* [meta] realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) +* v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +### nodejs/node-eps + +* proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + +## Minutes + + +### Role of CTC in semver-major changes needs clarification [#7848](https://github.com/nodejs/node/issues/7848) + + + + +### Revert fs changes [#7846](https://github.com/nodejs/node/pull/7846) + + +James: has to do with recent changes - making callback mandatory on all async functions apparently _broke the planet_, quite a few modules broke including a number used by npm, so `npm set` failed to work for example. + +James: technically this should be viewed as a bugfix but we’ve already treated things involving errors as sensitive but this is on master and things a broken right now so suggesting that we revert this. Some alternatives are: not revert and get fixes in the ecosystem, revert and add warning. + +Rich: Myles endorsed [#7897](https://github.com/nodejs/node/pull/7897) as a better alternative to reverting as it includes a warning. What’s the preferred approach here James? + +James: revert, even though I don’t like it, we should revert and revisit. + +Trevor: the fact that it was allowed was a bad decision because throwing can lead to hard-to-debug situations. Reverting is the _only course of action_. + +Rod: wanted to clarify as a matter of culture - we should fix master as soon as we’re aware of breakage in the ecosystem and deal with things more cleanly as we can. + +Julien: multiple commits in the revert PR, we should have separate discussions about them. + +James: will ask on the PR that they be split into two. + +James: second question here is whether we want to emit a warning instead? + +Rod: the graceful-fs warnings are still widespread because lots of packages rely on very old versions and it’s taking a long time to get updates through the ecosystem. We have to be careful about (1) warning fatigue, (2) users not understanding the subtlety and interpreting warnings as errors. Would be good if we go a bit slower on moving to warnings. + +James: we could run with warnings off by default as a way of dealing warning fatigue but that’s another discussion we can have on GitHub. + +Rich: moving on, this can be done on Github. + +### doc: add information about CTC quorum rules [#7813](https://github.com/nodejs/node/pull/7813) + +Rich: there was a counter-proposal which seemed to be better so I updated to use Chalker’s alternative wording. **If anyone doesn’t want this to land please comment on it within the next 24 hours or so**. There hasn’t been too much discussion or disagreement. + +### meta: provide example activities [#7744](https://github.com/nodejs/node/pull/7744) + +Rich: Similar to the previous issue - have not got a whole lot of response, or a luke-warm response at least. Please comment in there if you have any problems with it, there are no negatives so it’ll land in the next 24 hours or so so please comment! + +### \[meta\] realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) + +Trevor: ran some benchmarks in CI to see how much time it would take to require() with and without cache in realpath. Haven’t done Windows but on the others there was between 10% to 100%, which is between 30us to 300us difference per require(). + +Alexis: [#7899](https://github.com/nodejs/node/pull/7899) reverts and also includes Myles’ reversions from the other fs issues. + +Trevor: probably should revert and leave cache out, we might take a small hit now in perf but will lead to greater potential in the future. + +Alexis: the cache was never a great API in the first place anyway. + +Trevor: propose we revert and leave the cache and introduce a better fix. + +Anna: agree with Trevor and Alexis. + +Rod: should we get benchmarks on Windows? + +Alexis: much more concerned about correctness than performance. + +Trevor: this is a short-term fix, so we shouldn’t have a problem bringing it in. + +Rich asked for disagreement with moving forward with reversion without cache? No disagreement. Need to comment on 7899, review & lgtm. Anna, Trevor or Alexis will move it forward. + +### v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) + +James: because this adds some semver-minor’s Myles is very concerned about stability. + +Julien: any ideas on how we might be able to get more testers for these? + +James: maybe in a week, will get some suggestions posted to the LTS repo that we can discuss. + +### punycode: deprecate punycode module [#7552](https://github.com/nodejs/node/pull/7552) + +James: this is a 3rd party dependency that we expose and there’s some fairly extensive usage out there but there is a newer version out there in npm that people should be using. + +Rich: no more comments? Please post on the repo. + +Rod: deprecation is fine but would really like a long deprecation cycle. + +James: how about soft deprecation in v7 and hard in v8? + +Rod: soft in v7 and revisit decision to hard prior to v8. + +Brian: if people build without ICU what would happen to punycode since we need it? + +James: This particular PR introduces a hard deprecation that moves it to internal/ and has a shim that exposes it, so we could still use it internally but just deprecate the external API. + +Brian: are we going to continue updating the non-ICU version for people going forward or just leave it? + +James: would prefer to just leave it as is. + +Chalker: on npm it has 5.7M downloads per month so people are already using it. + +James: clarify: soft deprecate now and revisit hard deprecation prior to v8? + +### http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +Rod: wanted to mention that Chris Dickinson expressed concerns on Twitter about us doing this same thing on querystring and that it was causing problems for him and didn’t like that it crept in to v6. + +James: Doug, from the express side, thinks this is a good decision and cleans up things for users. The querystring thing has + +… discussion tended towards accepting the change but CTC would like to solicit input from Chris Dickinson before getting it landed since he had raised some objections + +### Seek legal advice on LICENSE and copyright blocks in code [#3979](https://github.com/nodejs/node/issues/3979) + +Mikeal Rogers: discussing the SPDX stuff and restoration of licenses in the files. Mikeal and Rod will take the lead on moving forward with this. + +### Repositories to contribute collaboratively [post-mortem#30](https://github.com/nodejs/post-mortem/issues/30) + +Move to TSC meeting + +### proposal: WHATWG URL standard implementation [node-eps#28](https://github.com/nodejs/node-eps/pull/28) + +James: Passing WHATWG tests except some intentional ones. Performance is slower than our own url impl because of tests we fail. Any objections to moving forward? + +Rod: we’re going to have two implementations, this seems like a difficult thing to agree on. + +James: would like to eventually deprecate existing url.parse. + +Rich: let’s move on because this will be a big conversation. Let’s have a brief conversation next week and slot a bigger discussion next week. + +## Q/A on public fora + +No questions. + +## Upcoming Meetings + +* CTC: 2016-08-03 +* TSC: 2016-07-28 +* Build: 2016-08-09 +* Diagnostics: 2016-08-03 +* Post-Mortem: August +* API: August diff --git a/doc/ctc-meetings/2016-08-03.md b/doc/ctc-meetings/2016-08-03.md new file mode 100644 index 00000000000..96884b42e1d --- /dev/null +++ b/doc/ctc-meetings/2016-08-03.md @@ -0,0 +1,336 @@ +# Node Foundation CTC Meeting 2016-08-03 + +## Links + +* **Audio Recording**: TBP +* **GitHub Issue**: https://github.com/nodejs/node/issues/7948 +* **Minutes Google Doc**: +* _Previous Minutes Google Doc: _ + + +## Present + +* Anna Henningsen @addaleax (observer) +* Bradley Meck @bmeck (observer/GoDaddy/TC39) +* Ben Noordhuis @bnoordhuis (CTC) +* Сковорода Никита Андреевич @ChALkeR (CTC) +* Colin Ihrig @cjihrig (CTC) +* Evan Lucas @evanlucas (CTC) +* Jeremiah Senkpiel @Fishrock123 (CTC) +* James M Snell @jasnell (CTC) +* Josh Gavant @joshgav (observer/Microsoft) +* Michael Dawson @mhdawson (CTC) +* Brian White @mscdex (CTC) +* Ali Ijaz Sheikh @ofrobots (CTC) +* Bert Belder @piscisaureus (CTC) +* Saúl Ibarra Corretgé @saghul (observer) +* Rich Trott @Trott (CTC) + + +## Standup + +* Anna Henningsen @addaleax (observer) + * Issues & PR review +* Bradley Meck @bmeck (observer/GoDaddy/TC39) + * Went to TC39 + * Modules are going to take a different direction +* Ben Noordhuis @bnoordhuis (CTC) + * Nothing special. +* Сковорода Никита Андреевич @ChALkeR (CTC) + * Working on the npm dataset rebuilding tool. Some comments on issues and PRs as usual. +* Colin Ihrig @cjihrig (CTC) + * Was on vacation + * Reviewing issues and PRs since I've been back +* Evan Lucas @evanlucas (CTC) + * A little cherry-picking to v6.x + * Working on getting commit validator running for PRs +* Jeremiah Senkpiel @Fishrock123 (CTC) + * Mostly away, experimenting with nucleus-js. +* James M Snell @jasnell (CTC) + * Node Summit + * Exploring the possibility of an HTTP/2 implementation in core + * Continued evaluation of the WHATWG URL implementation + * Foundation-y / TSC-y stuff + * Reviewing PRs, catching up still from vacation +* Josh Gavant @joshgav (observer/Microsoft) + * internal stuff, vacation +* Michael Dawson @mhdawson (CTC) + * Node Summit/catching up on issues after Node Summit + * Starting to add linuxOne release machine/jobs + * Adding new AIX machine from osuosl + * landed a few minutes PRs +* Brian White @mscdex (CTC) + * Commenting on issues/PRs. +* Ali Ijaz Sheikh @ofrobots (CTC) + * Node Summit & internal stuff. Spent rest of time shepherding some backports. + * Planning on writing a proposal for managing V8 for LTS +* Bert Belder @piscisaureus (CTC) + * Commented on an issue. +* Rich Trott @Trott (CTC) + * CTC/governance documentation updates + * Onboarding (danbev postponed but we’ll get there, now scheduling with fhinkel, additional nominees welcome) + * fixed a flaky test, investigating others + +## Agenda + +Extracted from **ctc-agenda** labelled issues and pull requests from the **nodejs org** prior to the meeting. + +### nodejs/node + +* CTC membership nomination: @addaleax [#7607](https://github.com/nodejs/node/issues/7607) + +* Revert fs changes [#7846](https://github.com/nodejs/node/pull/7846) + +* [meta] realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) + +* v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) + +* build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/issues/7484) + +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + + +### nodejs/node-eps + +* proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + +### other + +* doc: @piscisaureus has stepped-down from the CTC [#7969](https://github.com/nodejs/node/pull/7969) + +## Previous Meeting + +### nodejs/node + +* Role of CTC in semver-major changes needs clarification [#7848](https://github.com/nodejs/node/issues/7848) +* Revert fs changes [#7846](https://github.com/nodejs/node/pull/7846) +* doc: add information about CTC quorum rules [#7813](https://github.com/nodejs/node/pull/7813) +* meta: provide example activities [#7744](https://github.com/nodejs/node/pull/7744) +* meta: realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) +* v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) +* punycode: deprecate punycode module [#7552](https://github.com/nodejs/node/pull/7552) +* Node 6 fs.realpath behavior changes [#7175](https://github.com/nodejs/node/issues/7175) +* http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) +* Seek legal advice on LICENSE and copyright blocks in code [#3979](https://github.com/nodejs/node/issues/3979) + +### nodejs/post-mortem + +* Repositories to contribute collaboratively [#30](https://github.com/nodejs/post-mortem/issues/30) + +### nodejs/node-eps + +* proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + +## Minutes + +### CTC membership nomination: @addaleax [#7607](https://github.com/nodejs/node/issues/7607) + +Unanimous `aye`. + +**Next steps**: @rvagg to merge. + +--- + +### Revert fs changes [#7846](https://github.com/nodejs/node/pull/7846) + +Reverts: +https://github.com/nodejs/node/pull/7846 +https://github.com/nodejs/node/pull/7950 + +Warn instead of throw when callback is omitted, as in v5: +https://github.com/nodejs/node/pull/7897 + +@bnoordhuis: This change makes omitting the callback an immediate error. + +@trott: What do we need to do to get those PRs to land? + +@addaleax: Myles split off one commit to [#7950](https://github.com/nodejs/node/pull/7950). Not controversial, was requested by CTC last week. +This must be landed prior to #7846. + +@jasnell: Would like to see a CI and CITGM run and some additional testing to make sure we have exactly the right set of reverts. @jasnell will start it. + +@bnoordhuis: We need to print a deprecation warning [instead of throwing, when no callback]. + +@addaleax: That’s the plan after the reverts have landed. @thefourtheye plans to work on it. [see #7897]) + +@jasnell: process warning or deprecation warning? Will we use `util.printDeprecationWarning` or `process.emitWarning()`? +Deprecation warning is semver-major, process warning is semver-minor or even patch. + +[It's `printDeprecationWarning`, see [here](https://github.com/thefourtheye/io.js/blob/8c65f7b6a253ab4e26ffe0de791dc41fcee92244/lib/fs.js#L48).] + +@addaleax: PR to print warning already opened. Could be used instead of reverting, but we agreed to revert last week and it blocks the realpath revert. + +@Fishrock123: Unbreaking a break and replacing with warning shouldn’t be semver-major. + +@trott: @jasnell’s PR on semver policies says it should be semver-major. + +@Fishrock123: Since we already changed it in the v6 transition let’s just change it to a deprecation. + +@trott: Let’s do the reverts (#7846, #7950), discuss deprecation warning separately in GH (#7897). + +OK with everybody. + +**Next steps**: Do the reverts (#7846, #7950). Continue discussion on throw -> warning in #7897. + +--- + +### [meta] realpath issues in v6 [#7726](https://github.com/nodejs/node/issues/7726) + +@trott: Last week we concluded that Anna, Trevor, or Alexis would move it forward. + +@trott: Just the two reverts that are blocking. + +@addaleax: Yes. + +@saghul: Old JS impl did not resolve subst’ed drives. New libuv impl does. A test looks for the new behavior. ] + +@saghul: Some people are relying on the old JS impl behavior to shorten paths on Windows. What are the right semantics? Should `subst`ed drives resolve to original path or to shortened path? + +@piscisaureus: The whole reason we use realpath in `module` is to avoid a module being loaded multiple times via multiple symlinked paths. So the goal should be to always resolve to the true path. + +@piscisaureus: Path limit is 64k not likely to encounter. + +@saghul: There’s a test for the new code which expects realpath on a subst’ed drive to give the original path. We need to revert this test for reverted behavior. + +@addaleax: Reverting to fs JS impl would return to old behavior. + +@trott: Submit a PR to remove that test, or move to known issues tests. + +@piscisaureus: Leave the test to track changes in the future. + +@Fishrock123: Key is to revert to an impl the ecosystem is depending on. Discuss this in another PR in GitHub. + +@jasnell: It’s a revert of the internal impl, not the changed public API [i.e. so we have to consider it now.] + +What about reverting the removal of the `cache` option? + +@addaleax: Not including the `cache` option now would allow additional/alternate improvements in the future. + +@bnoordhuis: Are these changes to land in v7? + +@jasnell: The idea is to get these into *v6* before it goes LTS. + +* The realpath change would land in v6. +* The other changes (revert throwing error on callback) is only in master and would not land in v6. +* Are the realpath changes dependent on the others? +* Only Myles’ changes conflict with realpath [see previous item]. + +@jasnell: Do we have the steps lined up? + +@addaleax: Myles revert (#7846, #7950), then realpath revert. + +@? apply semver-major changes that were reverted, with deprecation warning. + +@chalker: Can we keep tests which were added? Revert removes some tests which aren’t actually related to changes. + +@piscisareus: Same as @saghul’s comment, and we agreed to keep the new tests. So yes we should keep them. + +**Next steps**: + +* Modify PR to keep tests related to new behavior for reference. +* Apply Myles' reverts (#7846, #7950) +* Apply `realpath` revert. +* Discuss other items (e.g. throw -> deprecation, proper realpath for subst'ed drives, cache impl) in GH issues. + +--- + +### v4.5.0 proposal [#7688](https://github.com/nodejs/node/pull/7688) + +@trott: Please test the RCs. + +@mhdawson and @jasnell: Building at IBM and not encountered anything. + +--- + +### build: drop support for VS 2013 in v7 [#7484](https://github.com/nodejs/node/issues/7484) + +@bnoordhuis: Based on @joaocgreis’s comment we can move from 2013 without trouble. + +@joshgav: @joaocgreis tested against many modules and with CITGM and encountered no problems. + +@piscisaureus: Can we wait for semver-major? + +@joshgav: Then we’ll be stuck with 2013 through out v6 LTS. + +@piscisaureus: Should we make another issue for v6? + +@jasnell: Let’s get this landed in master and test it out, then make a decision on putting in v6 before October. + +@trott: Getting pretty close, don’t want to be switching just a month before. + +**Next steps**: + +* Merge to master and test. +* Determine in September if we can apply in v6. + +--- + +### http: don't inherit from Object.prototype [#6102](https://github.com/nodejs/node/pull/6102) + +@chrisdickinson has concerns, @mscdex contacted. No response yet. + +@Fishrock123: Let’s remove `ctc-agenda` tag for next week. + +@jasnell: Plenty of discussion, heard from Doug Wilson that it’s a positive change. Would rather not hold up waiting for a response. Would be best to land before v7. + +@ofrobots: If we are going to change this we should have a plan for if/how we’ll get to maps. + +@Fishrock123: There are too many people currently depending on this being a regular object. + +@ofrobots: We shouldn’t break the ecosystem twice. We should target something with maps for v8 or longer timeframe. + +@Fishrock123: Motivation is ? + +Some feel we should wait for maps before making a breaking change. Jeremiah feels we should make an effective change now and not wait for an unknown future. + +@Fishrock123: We’ll need to provide both old and new APIs side by side, and that could be hard to do with maps. + +@ofrobots: We can delegate old API to a Proxy and add deprecation warnings on that handler. + +@?: Is Proxy performant enough? + +@ofrobots: For a deprecated path is it okay to take a performance hit? + +@evan: Okay with current change proposal (i.e. to not inherit from Object) as long as it’s considered semver-major. + +@jasnell will work on this. + +**Next steps**: Decide whether to merge this or wait for maps-based impl. + +--- + +### nodejs/node-eps proposal: WHATWG URL standard implementation [#28](https://github.com/nodejs/node-eps/pull/28) + +@trott: briefing now, longer discussion next week. + +@jasnell: Everyone keep reviewing it. Goal is to land as “experimental” in master, doesn’t have to go in v6. + +@trevnorris: -1 on global `URL` variable. + +@Fishrock123 also against new globals other than lang features. + +@jasnell: It’s a global in browsers. It can be removed, it’s in its own commit. + +**Next steps**: @nodejs/ctc review @jasnell's proposal. Discuss next week. + +--- + +### doc: @piscisaureus has stepped-down from the CTC [#7969](https://github.com/nodejs/node/pull/7969) + +@Fishrock123: submit PR to remove @piscisaureus and/or move to Collaborator. + +--- + +## Q/A on public fora + +No questions. + +## Upcoming Meetings + +* CTC: 2016-08-03 +* TSC: 2016-07-28 +* Build: 2016-08-07 +* LTS: 2016-07-25 +* Diagnostics: Sept +* Post-Mortem: August +* API: August diff --git a/doc/node.1 b/doc/node.1 index cec87222b54..1ec0d0ea486 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -1,10 +1,28 @@ .TH NODE 1 2016 Node.js Node.js -.\ This is a man page comment. -.\ Man page syntax (actually troff syntax) is somewhat obscure, but the -.\ important part is is that . specifies 's syntax for that -.\ line, and \f specifies it for the characters that follow. -.\ See http://liw.fi/manpages/ for more info. +.\" This is a man page comment. + +.\" Man page syntax (actually roff syntax) is somewhat obscure, but the +.\" important part is is that . specifies 's syntax for that +.\" line, and \f specifies it for the characters that follow. + +.\" .B Bold line +.\" .I Italic line (Rendered as underlined text in terminals) +.\" .BI Alternating bold/italics without spaces between arguments. +.\" Use `\ ` to include an "unpaddable" (literal) space in the output. +.\" .RI Alternating roman/italic + +.\" See http://liw.fi/manpages/ for an overview, or http://www.troff.org/54.pdf +.\" for detailed language reference. + +.\" Macro to display an underlined URL in bold +.de ur +.nr CF \\n(.f +.ft 4 +\\$1 +.ft \\n(CF +.. + .SH NAME @@ -14,15 +32,22 @@ node \- Server-side JavaScript runtime .SH SYNOPSIS .B node -[\fIoptions\fR] [\fIv8 options\fR] -[\fIscript.js\fR | \fB\-e \fR"\fIscript\fR"] -[\fIarguments\fR] +.RI [ options ] +.RI [ v8\ options ] +.RI [ script.js \ | +.B -e +.RI \&" script \&"] +.RI [ arguments ] .br .B node debug -[\fIscript.js\fR | \fB\-e \fR"\fIscript\fR" | \fI:\fR] \fI... +.RI [ script.js " | " +.B \-e +.RI \&" script \&"\ | +.IR : ] +.I ... .br .B node -[\fB\-\-v8-options\fR] +.RB [ \-\-v8-options ] Execute without arguments to start the REPL. @@ -169,17 +194,30 @@ Path to the file used to store the persistent REPL history. The default path is ~/.node_repl_history, which is overridden by this variable. Setting the value to an empty string ("" or " ") disables persistent REPL history. +.TP +.BR NODE_TTY_UNSAFE_ASYNC=1 +When set to 1, writes to stdout and stderr will be non-blocking and asynchronous +when outputting to a TTY on platforms which support async stdio. +Setting this will void any guarantee that stdio will not be interleaved or +dropped at program exit. \fBAvoid use.\fR + .SH RESOURCES AND DOCUMENTATION -Website: \fBhttps://nodejs.org/\fR +Website: +.ur https://nodejs.org/ -Documentation: \fBhttps://nodejs.org/api/\fR +Documentation: +.ur https://nodejs.org/api/ -GitHub repository & Issue Tracker: \fBhttps://github.com/nodejs/node\fR +GitHub repository & Issue Tracker: +.ur https://github.com/nodejs/node -Mailing list: \fBhttp://groups.google.com/group/nodejs\fR +Mailing list: +.ur http://groups.google.com/group/nodejs -IRC (general questions): \fBchat.freenode.net #node.js\fR +IRC (general questions): +.ur "chat.freenode.net #node.js" -IRC (node core development): \fBchat.freenode.net #node-dev\fR +IRC (node core development): +.ur "chat.freenode.net #node-dev" diff --git a/doc/onboarding.md b/doc/onboarding.md index 99fbc61935c..a44d2170bca 100644 --- a/doc/onboarding.md +++ b/doc/onboarding.md @@ -1,14 +1,12 @@ -## pre-setup +# Onboarding -Ensure everyone is added to https://github.com/orgs/nodejs/teams/collaborators +This document is an outline of the things we tell new Collaborators at their +onboarding session. +* Prior to the onboarding session, add the new Collaborators to +[the Collaborators team](https://github.com/orgs/nodejs/teams/collaborators). -## onboarding to nodejs - -### intros - - -### **thank you** for doing this +## **thank you** for doing this * going to cover four things: * local setup @@ -16,8 +14,7 @@ Ensure everyone is added to https://github.com/orgs/nodejs/teams/collaborators * issues, labels, and reviewing code * merging code - -### setup: +## setup * notifications setup * use https://github.com/notifications or set up email @@ -34,7 +31,7 @@ Ensure everyone is added to https://github.com/orgs/nodejs/teams/collaborators * `#node-dev` on `chat.freenode.net` is the best place to interact with the CTC / other collaborators -### a little deeper about the project +## a little deeper about the project * collaborators are effectively part owners * the project has the goals of its contributors @@ -46,7 +43,7 @@ Ensure everyone is added to https://github.com/orgs/nodejs/teams/collaborators * generally: try to be nice to people -### managing the issue tracker +## managing the issue tracker * you have (mostly) free rein – don't hesitate to close an issue if you are confident that it should be closed * this will come more naturally over time @@ -110,11 +107,10 @@ Ensure everyone is added to https://github.com/orgs/nodejs/teams/collaborators * To start CI testing from this screen, you need to fill in two elements on the form: * The `CERTIFY_SAFE` box should be checked. By checking it, you are indicating that you have reviewed the code you are about to test and you are confident that it does not contain any malicious code. (We don't want people hijacking our CI hosts to attack other hosts on the internet, for example!) * The `PR_ID` box should be filled in with the number identifying the pull request containing the code you wish to test. For example, if the URL for the pull request is https://github.com/nodejs/node/issues/7006, then put `7006` in the `PR_ID`. - * The remaining elements on the form are typically unchanged. - * There is a checkbox for `POST_STATUS_TO_PR`. At the time of this writing, that checkbox does not do anything, but that is likely to change soon. Until that functionality is working, you will want to go back to the PR you are testing and paste `CI: ` into a comment on the pull request. + * The remaining elements on the form are typically unchanged with the exception of `POST_STATUS_TO_PR`. Check that if you want a CI status indicator to be automatically inserted into the PR. -### process for getting code in: +## process for getting code in * the collaborator guide is a great resource: https://github.com/nodejs/node/blob/master/COLLABORATOR_GUIDE.md#technical-howto @@ -146,7 +142,7 @@ Ensure everyone is added to https://github.com/orgs/nodejs/teams/collaborators * Info on PRs that don't like to apply found under [**"If `git am` fails"**](./onboarding-extras.md#if-git-am-fails). -### Landing PRs +## Landing PRs * Please never use GitHub's green "Merge Pull Request" button. * If you do, please force-push removing the merge. @@ -169,12 +165,13 @@ Landing a PR * `Reviewed-By: human ` * Easiest to use `git log` then do a search * (`/Name` + `enter` (+ `n` as much as you need to) in vim) + * Only include collaborators who have commented "LGTM" * `PR-URL: ` * `git push upstream master` * close the original PR with "Landed in ``". -### exercise: make PRs adding yourselves to the README. +## exercise: make PRs adding yourselves to the README * Example: https://github.com/nodejs/node/commit/7b09aade8468e1c930f36b9c81e6ac2ed5bc8732 * to see full URL: `git log 7b09aade8468e1c930f36b9c81e6ac2ed5bc8732 -1` @@ -184,7 +181,7 @@ Landing a PR * Make sure to added the `PR-URL: `! -### final notes: +## final notes * don't worry about making mistakes: everybody makes them, there's a lot to internalize and that takes time (and we recognize that!) * very few (no?) mistakes are unrecoverable diff --git a/doc/releases.md b/doc/releases.md index b5e57d12517..25cdb56a479 100644 --- a/doc/releases.md +++ b/doc/releases.md @@ -216,10 +216,16 @@ Once you have produced builds that you're happy with, create a new tag. By waiti Tag summaries have a predictable format, look at a recent tag to see, `git tag -v v6.0.0`. The message should look something like `2016-04-26 Node.js v6.0.0 (Current) Release`. +Install `git-secure-tag` npm module: + +```console +$ npm install -g git-secure-tag +``` + Create a tag using the following command: ```sh -$ git tag -sm 'YYYY-MM-DD Node.js vx.y.z (Release Type) Release' +$ git secure-tag -sm 'YYYY-MM-DD Node.js vx.y.z (Release Type) Release' ``` The tag **must** be signed using the GPG key that's listed for you on the project README. diff --git a/doc/template.html b/doc/template.html index 71e3a21e1d4..af680645d15 100644 --- a/doc/template.html +++ b/doc/template.html @@ -2,7 +2,7 @@ - __SECTION__ Node.js __VERSION__ Manual & Documentation + __SECTION__ | Node.js __VERSION__ Documentation diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index f28aecae710..c5c294a1b35 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -338,8 +338,6 @@ OutgoingMessage.prototype.setHeader = function(name, value) { if (!common._checkIsHttpToken(name)) throw new TypeError( 'Header name must be a valid HTTP Token ["' + name + '"]'); - if (typeof name !== 'string') - throw new TypeError('"name" should be a string in setHeader(name, value)'); if (value === undefined) throw new Error('"value" required in setHeader("' + name + '", value)'); if (this._header) @@ -413,6 +411,9 @@ OutgoingMessage.prototype._renderHeaders = function() { return headers; }; +OutgoingMessage.prototype._implicitHeader = function() { + throw new Error('_implicitHeader() method is not implemented'); +}; Object.defineProperty(OutgoingMessage.prototype, 'headersSent', { configurable: true, diff --git a/lib/assert.js b/lib/assert.js index ba316d38ff6..8a316ffa793 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -180,8 +180,12 @@ function _deepEqual(actual, expected, strict, memos) { pToString(actual) === pToString(expected) && !(actual instanceof Float32Array || actual instanceof Float64Array)) { - return compare(Buffer.from(actual.buffer), - Buffer.from(expected.buffer)) === 0; + return compare(Buffer.from(actual.buffer, + actual.byteOffset, + actual.byteLength), + Buffer.from(expected.buffer, + expected.byteOffset, + expected.byteLength)) === 0; // 7.5 For all other Object pairs, including Array objects, equivalence is // determined by having the same number of owned properties (as verified diff --git a/lib/buffer.js b/lib/buffer.js index 009e97d4a74..0ff79a5e937 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -112,8 +112,14 @@ Object.setPrototypeOf(Buffer, Uint8Array); markNoSpeciesConstructor(Buffer); function assertSize(size) { - if (typeof size !== 'number') { - const err = new TypeError('"size" argument must be a number'); + let err = null; + + if (typeof size !== 'number') + err = new TypeError('"size" argument must be a number'); + else if (size < 0) + err = new RangeError('"size" argument must not be negative'); + + if (err) { // The following hides the 'assertSize' method from the // callstack. This is done simply to hide the internal // details of the implementation from bleeding out to users. diff --git a/lib/child_process.js b/lib/child_process.js index 6e77caba23f..0362b5fde27 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -351,7 +351,11 @@ function normalizeSpawnArguments(file /*, args, options*/) { } } - args.unshift(file); + if (typeof options.argv0 === 'string') { + args.unshift(options.argv0); + } else { + args.unshift(file); + } var env = options.env || process.env; var envPairs = []; diff --git a/lib/cluster.js b/lib/cluster.js index 38e6885f675..05397ca69fb 100644 --- a/lib/cluster.js +++ b/lib/cluster.js @@ -322,6 +322,7 @@ function masterInit() { env: workerEnv, silent: cluster.settings.silent, execArgv: execArgv, + stdio: cluster.settings.stdio, gid: cluster.settings.gid, uid: cluster.settings.uid }); diff --git a/lib/dgram.js b/lib/dgram.js index c088bffa7ff..9037666d174 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -53,9 +53,6 @@ function newHandle(type) { return handle; } - if (type == 'unix_dgram') - throw new Error('"unix_dgram" type sockets are not supported any more'); - throw new Error('Bad socket type specified. Valid types are: udp4, udp6'); } diff --git a/lib/events.js b/lib/events.js index f0b323e15c1..171f4868a66 100644 --- a/lib/events.js +++ b/lib/events.js @@ -425,9 +425,9 @@ EventEmitter.prototype.listeners = function listeners(type) { if (!evlistener) ret = []; else if (typeof evlistener === 'function') - ret = [evlistener]; + ret = [evlistener.listener || evlistener]; else - ret = arrayClone(evlistener, evlistener.length); + ret = unwrapListeners(evlistener); } return ret; @@ -475,3 +475,11 @@ function arrayClone(arr, i) { copy[i] = arr[i]; return copy; } + +function unwrapListeners(arr) { + const ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} diff --git a/lib/fs.js b/lib/fs.js index e48b79e4403..2fc22b1bdde 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -38,6 +38,7 @@ const O_WRONLY = constants.O_WRONLY || 0; const isWindows = process.platform === 'win32'; +const DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); const errnoException = util._errnoException; var printDeprecation; @@ -81,20 +82,39 @@ function throwOptionsError(options) { 'but got ' + typeof options + ' instead'); } -function isFD(fd) { - return Number.isInteger(fd) && fd >= 0 && fd <= 0xFFFFFFFF; +function rethrow() { + // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and + // is fairly slow to generate. + if (DEBUG) { + var backtrace = new Error(); + return function(err) { + if (err) { + backtrace.stack = err.name + ': ' + err.message + + backtrace.stack.substr(backtrace.name.length); + throw backtrace; + } + }; + } + + return function(err) { + if (err) { + throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs + } + }; } -function sanitizeFD(fd) { - if (!isFD(fd)) - throw new TypeError('file descriptor must be a unsigned 32-bit integer'); - return fd; +function maybeCallback(cb) { + return typeof cb === 'function' ? cb : rethrow(); } // Ensure that callbacks run in the global context. Only use this function // for callbacks that are passed to the binding layer, callbacks that are // invoked from JS already run in the proper scope. function makeCallback(cb) { + if (cb === undefined) { + return rethrow(); + } + if (typeof cb !== 'function') { throw new TypeError('"callback" argument must be a function'); } @@ -122,6 +142,10 @@ function nullCheck(path, callback) { return true; } +function isFd(path) { + return (path >>> 0) === path; +} + // Static method to set the stats properties on a Stats object. fs.Stats = function( dev, @@ -197,9 +221,11 @@ fs.Stats.prototype.isSocket = function() { }); fs.access = function(path, mode, callback) { - callback = makeCallback(arguments[arguments.length - 1]); if (typeof mode === 'function') { + callback = mode; mode = fs.F_OK; + } else if (typeof callback !== 'function') { + throw new TypeError('"callback" argument must be a function'); } if (!nullCheck(path, callback)) @@ -207,7 +233,7 @@ fs.access = function(path, mode, callback) { mode = mode | 0; var req = new FSReqWrap(); - req.oncomplete = callback; + req.oncomplete = makeCallback(callback); binding.access(pathModule._makeLong(path), mode, req); }; @@ -223,13 +249,12 @@ fs.accessSync = function(path, mode) { }; fs.exists = function(path, callback) { - callback = makeCallback(arguments[arguments.length - 1]); if (!nullCheck(path, cb)) return; var req = new FSReqWrap(); req.oncomplete = cb; binding.stat(pathModule._makeLong(path), req); function cb(err, stats) { - callback(err ? false : true); + if (callback) callback(err ? false : true); } }; @@ -243,8 +268,8 @@ fs.existsSync = function(path) { } }; -fs.readFile = function(path, options, callback) { - callback = makeCallback(arguments[arguments.length - 1]); +fs.readFile = function(path, options, callback_) { + var callback = maybeCallback(arguments[arguments.length - 1]); if (!options || typeof options === 'function') { options = { encoding: null, flag: 'r' }; @@ -263,7 +288,7 @@ fs.readFile = function(path, options, callback) { return; var context = new ReadFileContext(callback, encoding); - context.isUserFd = isFD(path); // file descriptor ownership + context.isUserFd = isFd(path); // file descriptor ownership var req = new FSReqWrap(); req.context = context; req.oncomplete = readFileAfterOpen; @@ -479,7 +504,7 @@ fs.readFileSync = function(path, options) { assertEncoding(encoding); var flag = options.flag || 'r'; - var isUserFd = isFD(path); // file descriptor ownership + var isUserFd = isFd(path); // file descriptor ownership var fd = isUserFd ? path : fs.openSync(path, flag, 0o666); var st = tryStatSync(fd, isUserFd); @@ -577,11 +602,11 @@ Object.defineProperty(exports, '_stringToFlags', { fs.close = function(fd, callback) { var req = new FSReqWrap(); req.oncomplete = makeCallback(callback); - binding.close(sanitizeFD(fd), req); + binding.close(fd, req); }; fs.closeSync = function(fd) { - return binding.close(sanitizeFD(fd)); + return binding.close(fd); }; function modeNum(m, def) { @@ -594,8 +619,8 @@ function modeNum(m, def) { return undefined; } -fs.open = function(path, flags, mode, callback) { - callback = makeCallback(arguments[arguments.length - 1]); +fs.open = function(path, flags, mode, callback_) { + var callback = makeCallback(arguments[arguments.length - 1]); mode = modeNum(mode, 0o666); if (!nullCheck(path, callback)) return; @@ -617,8 +642,6 @@ fs.openSync = function(path, flags, mode) { var readWarned = false; fs.read = function(fd, buffer, offset, length, position, callback) { - callback = makeCallback(arguments[arguments.length - 1]); - fd = sanitizeFD(fd); if (!(buffer instanceof Buffer)) { // legacy string interface (fd, length, position, encoding, callback) readWarned = printDeprecation('fs.read\'s legacy String interface ' + @@ -642,20 +665,20 @@ fs.read = function(fd, buffer, offset, length, position, callback) { if (bytesRead > 0) { tryToStringWithEnd(buffer, encoding, bytesRead, cb); } else { - cb(err, '', bytesRead); + (cb)(err, '', bytesRead); } }; } if (length === 0) { return process.nextTick(function() { - callback(null, 0, buffer); + callback && callback(null, 0, buffer); }); } function wrapper(err, bytesRead) { // Retain a reference to buffer so that it can't be GC'ed too soon. - callback(err, bytesRead || 0, buffer); + callback && callback(err, bytesRead || 0, buffer); } var req = new FSReqWrap(); @@ -679,7 +702,6 @@ fs.readSync = function(fd, buffer, offset, length, position) { var legacy = false; var encoding; - fd = sanitizeFD(fd); if (!(buffer instanceof Buffer)) { // legacy string interface (fd, length, position, encoding, callback) readSyncWarned = printDeprecation('fs.readSync\'s legacy String interface' + @@ -720,8 +742,6 @@ fs.readSync = function(fd, buffer, offset, length, position) { // OR // fs.write(fd, string[, position[, encoding]], callback); fs.write = function(fd, buffer, offset, length, position, callback) { - callback = makeCallback(arguments[arguments.length - 1]); - fd = sanitizeFD(fd); function wrapper(err, written) { // Retain a reference to buffer so that it can't be GC'ed too soon. callback(err, written || 0, buffer); @@ -733,8 +753,10 @@ fs.write = function(fd, buffer, offset, length, position, callback) { if (buffer instanceof Buffer) { // if no position is passed then assume null if (typeof position === 'function') { + callback = position; position = null; } + callback = maybeCallback(callback); return binding.writeBuffer(fd, buffer, offset, length, position, req); } @@ -749,6 +771,7 @@ fs.write = function(fd, buffer, offset, length, position, callback) { } length = 'utf8'; } + callback = maybeCallback(position); return binding.writeString(fd, buffer, offset, length, req); }; @@ -757,7 +780,6 @@ fs.write = function(fd, buffer, offset, length, position, callback) { // OR // fs.writeSync(fd, string[, position[, encoding]]); fs.writeSync = function(fd, buffer, offset, length, position) { - fd = sanitizeFD(fd); if (buffer instanceof Buffer) { if (position === undefined) position = null; @@ -771,7 +793,7 @@ fs.writeSync = function(fd, buffer, offset, length, position) { }; fs.rename = function(oldPath, newPath, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(oldPath, callback)) return; if (!nullCheck(newPath, callback)) return; var req = new FSReqWrap(); @@ -789,20 +811,17 @@ fs.renameSync = function(oldPath, newPath) { }; fs.truncate = function(path, len, callback) { - callback = makeCallback(arguments[arguments.length - 1]); - - if (isFD(path)) + if (typeof path === 'number') { return fs.ftruncate(path, len, callback); - - if (typeof path !== 'string') - throw new TypeError('path must be a string'); - - if (typeof len === 'function' || len == undefined) { + } + if (typeof len === 'function') { + callback = len; + len = 0; + } else if (len === undefined) { len = 0; - } else if (!Number.isInteger(len) || len < 0) { - throw new TypeError('length must be a positive integer'); } + callback = maybeCallback(callback); fs.open(path, 'r+', function(er, fd) { if (er) return callback(er); var req = new FSReqWrap(); @@ -816,18 +835,13 @@ fs.truncate = function(path, len, callback) { }; fs.truncateSync = function(path, len) { - if (isFD(path)) + if (typeof path === 'number') { + // legacy return fs.ftruncateSync(path, len); - - if (typeof path !== 'string') - throw new TypeError('path must be a string'); - - if (len === undefined || len === null) { + } + if (len === undefined) { len = 0; - } else if (!Number.isInteger(len) || len < 0) { - throw new TypeError('length must be a positive integer'); } - // allow error to be thrown, but still close fd. var fd = fs.openSync(path, 'r+'); var ret; @@ -841,35 +855,26 @@ fs.truncateSync = function(path, len) { }; fs.ftruncate = function(fd, len, callback) { - callback = makeCallback(arguments[arguments.length - 1]); - - fd = sanitizeFD(fd); - - if (typeof len === 'function' || len == undefined) { + if (typeof len === 'function') { + callback = len; + len = 0; + } else if (len === undefined) { len = 0; - } else if (!Number.isInteger(len) || len < 0) { - throw new TypeError('length must be a positive integer'); } - var req = new FSReqWrap(); - req.oncomplete = callback; + req.oncomplete = makeCallback(callback); binding.ftruncate(fd, len, req); }; fs.ftruncateSync = function(fd, len) { - fd = sanitizeFD(fd); - - if (len === undefined || len === null) { + if (len === undefined) { len = 0; - } else if (!Number.isInteger(len) || len < 0) { - throw new TypeError('length must be a positive integer'); } - return binding.ftruncate(fd, len); }; fs.rmdir = function(path, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = maybeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -884,25 +889,26 @@ fs.rmdirSync = function(path) { fs.fdatasync = function(fd, callback) { var req = new FSReqWrap(); req.oncomplete = makeCallback(callback); - binding.fdatasync(sanitizeFD(fd), req); + binding.fdatasync(fd, req); }; fs.fdatasyncSync = function(fd) { - return binding.fdatasync(sanitizeFD(fd)); + return binding.fdatasync(fd); }; fs.fsync = function(fd, callback) { var req = new FSReqWrap(); req.oncomplete = makeCallback(callback); - binding.fsync(sanitizeFD(fd), req); + binding.fsync(fd, req); }; fs.fsyncSync = function(fd) { - return binding.fsync(sanitizeFD(fd)); + return binding.fsync(fd); }; fs.mkdir = function(path, mode, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + if (typeof mode === 'function') callback = mode; + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -918,9 +924,9 @@ fs.mkdirSync = function(path, mode) { }; fs.readdir = function(path, options, callback) { - callback = makeCallback(arguments[arguments.length - 1]); options = options || {}; if (typeof options === 'function') { + callback = options; options = {}; } else if (typeof options === 'string') { options = {encoding: options}; @@ -928,6 +934,7 @@ fs.readdir = function(path, options, callback) { if (typeof options !== 'object') throw new TypeError('"options" must be a string or an object'); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -947,11 +954,11 @@ fs.readdirSync = function(path, options) { fs.fstat = function(fd, callback) { var req = new FSReqWrap(); req.oncomplete = makeCallback(callback); - binding.fstat(sanitizeFD(fd), req); + binding.fstat(fd, req); }; fs.lstat = function(path, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -959,7 +966,7 @@ fs.lstat = function(path, callback) { }; fs.stat = function(path, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -967,7 +974,7 @@ fs.stat = function(path, callback) { }; fs.fstatSync = function(fd) { - return binding.fstat(sanitizeFD(fd)); + return binding.fstat(fd); }; fs.lstatSync = function(path) { @@ -981,15 +988,16 @@ fs.statSync = function(path) { }; fs.readlink = function(path, options, callback) { - callback = makeCallback(arguments[arguments.length - 1]); options = options || {}; if (typeof options === 'function') { + callback = options; options = {}; } else if (typeof options === 'string') { options = {encoding: options}; } if (typeof options !== 'object') throw new TypeError('"options" must be a string or an object'); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -1049,7 +1057,7 @@ fs.symlinkSync = function(target, path, type) { }; fs.link = function(srcpath, dstpath, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(srcpath, callback)) return; if (!nullCheck(dstpath, callback)) return; @@ -1069,7 +1077,7 @@ fs.linkSync = function(srcpath, dstpath) { }; fs.unlink = function(path, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -1083,17 +1091,17 @@ fs.unlinkSync = function(path) { fs.fchmod = function(fd, mode, callback) { var req = new FSReqWrap(); - req.oncomplete = makeCallback(arguments[arguments.length - 1]); - binding.fchmod(sanitizeFD(fd), modeNum(mode), req); + req.oncomplete = makeCallback(callback); + binding.fchmod(fd, modeNum(mode), req); }; fs.fchmodSync = function(fd, mode) { - return binding.fchmod(sanitizeFD(fd), modeNum(mode)); + return binding.fchmod(fd, modeNum(mode)); }; if (constants.hasOwnProperty('O_SYMLINK')) { fs.lchmod = function(path, mode, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = maybeCallback(callback); fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) { if (err) { callback(err); @@ -1132,7 +1140,7 @@ if (constants.hasOwnProperty('O_SYMLINK')) { fs.chmod = function(path, mode, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -1148,7 +1156,7 @@ fs.chmodSync = function(path, mode) { if (constants.hasOwnProperty('O_SYMLINK')) { fs.lchown = function(path, uid, gid, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = maybeCallback(callback); fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) { if (err) { callback(err); @@ -1166,16 +1174,16 @@ if (constants.hasOwnProperty('O_SYMLINK')) { fs.fchown = function(fd, uid, gid, callback) { var req = new FSReqWrap(); - req.oncomplete = makeCallback(arguments[arguments.length - 1]); - binding.fchown(sanitizeFD(fd), uid, gid, req); + req.oncomplete = makeCallback(callback); + binding.fchown(fd, uid, gid, req); }; fs.fchownSync = function(fd, uid, gid) { - return binding.fchown(sanitizeFD(fd), uid, gid); + return binding.fchown(fd, uid, gid); }; fs.chown = function(path, uid, gid, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -1209,7 +1217,7 @@ function toUnixTimestamp(time) { fs._toUnixTimestamp = toUnixTimestamp; fs.utimes = function(path, atime, mtime, callback) { - callback = makeCallback(arguments[arguments.length - 1]); + callback = makeCallback(callback); if (!nullCheck(path, callback)) return; var req = new FSReqWrap(); req.oncomplete = callback; @@ -1227,24 +1235,21 @@ fs.utimesSync = function(path, atime, mtime) { }; fs.futimes = function(fd, atime, mtime, callback) { - callback = makeCallback(arguments[arguments.length - 1]); - fd = sanitizeFD(fd); atime = toUnixTimestamp(atime); mtime = toUnixTimestamp(mtime); var req = new FSReqWrap(); - req.oncomplete = callback; + req.oncomplete = makeCallback(callback); binding.futimes(fd, atime, mtime, req); }; fs.futimesSync = function(fd, atime, mtime) { - fd = sanitizeFD(fd); atime = toUnixTimestamp(atime); mtime = toUnixTimestamp(mtime); binding.futimes(fd, atime, mtime); }; -function writeAll(fd, isUserFd, buffer, offset, length, position, callback) { - callback = makeCallback(arguments[arguments.length - 1]); +function writeAll(fd, isUserFd, buffer, offset, length, position, callback_) { + var callback = maybeCallback(arguments[arguments.length - 1]); // write(fd, buffer, offset, length, position, callback) fs.write(fd, buffer, offset, length, position, function(writeErr, written) { @@ -1275,8 +1280,8 @@ function writeAll(fd, isUserFd, buffer, offset, length, position, callback) { }); } -fs.writeFile = function(path, data, options, callback) { - callback = makeCallback(arguments[arguments.length - 1]); +fs.writeFile = function(path, data, options, callback_) { + var callback = maybeCallback(arguments[arguments.length - 1]); if (!options || typeof options === 'function') { options = { encoding: 'utf8', mode: 0o666, flag: 'w' }; @@ -1290,7 +1295,7 @@ fs.writeFile = function(path, data, options, callback) { var flag = options.flag || 'w'; - if (isFD(path)) { + if (isFd(path)) { writeFd(path, true); return; } @@ -1324,7 +1329,7 @@ fs.writeFileSync = function(path, data, options) { assertEncoding(options.encoding); var flag = options.flag || 'w'; - var isUserFd = isFD(path); // file descriptor ownership + var isUserFd = isFd(path); // file descriptor ownership var fd = isUserFd ? path : fs.openSync(path, flag, options.mode); if (!(data instanceof Buffer)) { @@ -1347,8 +1352,8 @@ fs.writeFileSync = function(path, data, options) { } }; -fs.appendFile = function(path, data, options, callback) { - callback = makeCallback(arguments[arguments.length - 1]); +fs.appendFile = function(path, data, options, callback_) { + var callback = maybeCallback(arguments[arguments.length - 1]); if (!options || typeof options === 'function') { options = { encoding: 'utf8', mode: 0o666, flag: 'a' }; @@ -1362,7 +1367,7 @@ fs.appendFile = function(path, data, options, callback) { options = util._extend({ flag: 'a' }, options); // force append behavior when using a supplied file descriptor - if (isFD(path)) + if (isFd(path)) options.flag = 'a'; fs.writeFile(path, data, options, callback); @@ -1381,7 +1386,7 @@ fs.appendFileSync = function(path, data, options) { options = util._extend({ flag: 'a' }, options); // force append behavior when using a supplied file descriptor - if (isFD(path)) + if (isFd(path)) options.flag = 'a'; fs.writeFileSync(path, data, options); @@ -1503,7 +1508,6 @@ StatWatcher.prototype.stop = function() { const statWatchers = new Map(); fs.watchFile = function(filename, options, listener) { - listener = makeCallback(arguments[arguments.length - 1]); nullCheck(filename); filename = pathModule.resolve(filename); var stat; @@ -1519,9 +1523,14 @@ fs.watchFile = function(filename, options, listener) { if (options !== null && typeof options === 'object') { options = util._extend(defaults, options); } else { + listener = options; options = defaults; } + if (typeof listener !== 'function') { + throw new Error('"watchFile()" requires a listener function'); + } + stat = statWatchers.get(filename); if (stat === undefined) { @@ -1554,20 +1563,125 @@ fs.unwatchFile = function(filename, listener) { }; -fs.realpathSync = function realpathSync(path, options) { +// Regexp that finds the next portion of a (partial) path +// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] +const nextPartRe = isWindows ? + /(.*?)(?:[\/\\]+|$)/g : + /(.*?)(?:[\/]+|$)/g; + +// Regex to find the device root, including trailing slash. E.g. 'c:\\'. +const splitRootRe = isWindows ? + /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/ : + /^[\/]*/; + +function encodeRealpathResult(result, options, err) { + if (!options || !options.encoding || options.encoding === 'utf8' || err) + return result; + const asBuffer = Buffer.from(result); + if (options.encoding === 'buffer') { + return asBuffer; + } else { + return asBuffer.toString(options.encoding); + } +} + +fs.realpathSync = function realpathSync(p, options) { if (!options) options = {}; else if (typeof options === 'string') options = {encoding: options}; else if (typeof options !== 'object') throw new TypeError('"options" must be a string or an object'); - nullCheck(path); - return binding.realpath(pathModule._makeLong(path), options.encoding); + nullCheck(p); + + p = p.toString('utf8'); + p = pathModule.resolve(p); + + const seenLinks = {}; + const knownHard = {}; + + // current character position in p + var pos; + // the partial path so far, including a trailing slash if any + var current; + // the partial path without a trailing slash (except when pointing at a root) + var base; + // the partial path scanned in the previous round, with slash + var previous; + + start(); + + function start() { + // Skip over roots + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstatSync(base); + knownHard[base] = true; + } + } + + // walk down the path, swapping out linked pathparts for their real + // values + // NB: p.length changes. + while (pos < p.length) { + // find the next part + nextPartRe.lastIndex = pos; + var result = nextPartRe.exec(p); + previous = current; + current += result[0]; + base = previous + result[1]; + pos = nextPartRe.lastIndex; + + // continue if not a symlink + if (knownHard[base]) { + continue; + } + + var resolvedLink; + var stat = fs.lstatSync(base); + if (!stat.isSymbolicLink()) { + knownHard[base] = true; + continue; + } + + // read the link if it wasn't read before + // dev/ino always return 0 on windows, so skip the check. + var linkTarget = null; + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks.hasOwnProperty(id)) { + linkTarget = seenLinks[id]; + } + } + if (linkTarget === null) { + fs.statSync(base); + linkTarget = fs.readlinkSync(base); + } + resolvedLink = pathModule.resolve(previous, linkTarget); + + if (!isWindows) seenLinks[id] = linkTarget; + + // resolve the link, then start over + p = pathModule.resolve(resolvedLink, p.slice(pos)); + start(); + } + + return encodeRealpathResult(p, options); }; -fs.realpath = function realpath(path, options, callback) { - callback = makeCallback(arguments[arguments.length - 1]); +fs.realpath = function realpath(p, options, callback) { + if (typeof callback !== 'function') { + callback = maybeCallback(options); + options = {}; + } + if (!options) { options = {}; } else if (typeof options === 'function') { @@ -1577,22 +1691,119 @@ fs.realpath = function realpath(path, options, callback) { } else if (typeof options !== 'object') { throw new TypeError('"options" must be a string or an object'); } - if (!nullCheck(path, callback)) + if (!nullCheck(p, callback)) return; - var req = new FSReqWrap(); - req.oncomplete = callback; - binding.realpath(pathModule._makeLong(path), options.encoding, req); - return; -}; + p = p.toString('utf8'); + p = pathModule.resolve(p); + + const seenLinks = {}; + const knownHard = {}; + + // current character position in p + var pos; + // the partial path so far, including a trailing slash if any + var current; + // the partial path without a trailing slash (except when pointing at a root) + var base; + // the partial path scanned in the previous round, with slash + var previous; + + start(); + + function start() { + // Skip over roots + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstat(base, function(err) { + if (err) return callback(err); + knownHard[base] = true; + LOOP(); + }); + } else { + process.nextTick(LOOP); + } + } + + // walk down the path, swapping out linked pathparts for their real + // values + function LOOP() { + // stop if scanned past end of path + if (pos >= p.length) { + return callback(null, encodeRealpathResult(p, options)); + } + + // find the next part + nextPartRe.lastIndex = pos; + var result = nextPartRe.exec(p); + previous = current; + current += result[0]; + base = previous + result[1]; + pos = nextPartRe.lastIndex; + + // continue if not a symlink + if (knownHard[base]) { + return process.nextTick(LOOP); + } + + return fs.lstat(base, gotStat); + } + + function gotStat(err, stat) { + if (err) return callback(err); + + // if not a symlink, skip to the next path part + if (!stat.isSymbolicLink()) { + knownHard[base] = true; + return process.nextTick(LOOP); + } + + // stat & read the link if not read before + // call gotTarget as soon as the link target is known + // dev/ino always return 0 on windows, so skip the check. + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks.hasOwnProperty(id)) { + return gotTarget(null, seenLinks[id], base); + } + } + fs.stat(base, function(err) { + if (err) return callback(err); + + fs.readlink(base, function(err, target) { + if (!isWindows) seenLinks[id] = target; + gotTarget(err, target); + }); + }); + } + + function gotTarget(err, target, base) { + if (err) return callback(err); + + var resolvedLink = pathModule.resolve(previous, target); + gotResolvedLink(resolvedLink); + } + + function gotResolvedLink(resolvedLink) { + // resolve the link, then start over + p = pathModule.resolve(resolvedLink, p.slice(pos)); + start(); + } +}; fs.mkdtemp = function(prefix, options, callback) { - callback = makeCallback(arguments[arguments.length - 1]); if (!prefix || typeof prefix !== 'string') throw new TypeError('filename prefix is required'); options = options || {}; if (typeof options === 'function') { + callback = options; options = {}; } else if (typeof options === 'string') { options = {encoding: options}; @@ -1600,6 +1811,7 @@ fs.mkdtemp = function(prefix, options, callback) { if (typeof options !== 'object') throw new TypeError('"options" must be a string or an object'); + callback = makeCallback(callback); if (!nullCheck(prefix, callback)) { return; } @@ -1668,6 +1880,7 @@ function ReadStream(path, options) { this.end = options.end; this.autoClose = options.autoClose === undefined ? true : options.autoClose; this.pos = undefined; + this.bytesRead = 0; if (this.start !== undefined) { if (typeof this.start !== 'number') { @@ -1763,8 +1976,10 @@ ReadStream.prototype._read = function(n) { self.emit('error', er); } else { var b = null; - if (bytesRead > 0) + if (bytesRead > 0) { + self.bytesRead += bytesRead; b = thisPool.slice(start, start + bytesRead); + } self.push(b); } @@ -1965,7 +2180,7 @@ function SyncWriteStream(fd, options) { options = options || {}; - this.fd = sanitizeFD(fd); + this.fd = fd; this.writable = true; this.readable = false; this.autoClose = options.autoClose === undefined ? true : options.autoClose; diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js index 35bbc6d6776..17e34f40361 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap_node.js @@ -50,6 +50,11 @@ _process.setupRawDebug(); + Object.defineProperty(process, 'argv0', { + enumerable: true, + configurable: false, + value: process.argv[0] + }); process.argv[0] = process.execPath; // There are various modes that Node can run in. The most common two @@ -221,15 +226,52 @@ } function setupGlobalConsole() { + var inspectorConsole; + var wrapConsoleCall; + if (process.inspector) { + inspectorConsole = global.console; + wrapConsoleCall = process.inspector.wrapConsoleCall; + delete process.inspector; + } + var console; Object.defineProperty(global, 'console', { configurable: true, enumerable: true, get: function() { - return NativeModule.require('console'); + if (!console) { + console = NativeModule.require('console'); + installInspectorConsoleIfNeeded(console, + inspectorConsole, + wrapConsoleCall); + } + return console; } }); } + function installInspectorConsoleIfNeeded(console, + inspectorConsole, + wrapConsoleCall) { + if (!inspectorConsole) + return; + var config = {}; + for (const key of Object.keys(console)) { + if (!inspectorConsole.hasOwnProperty(key)) + continue; + // If node console has the same method as inspector console, + // then wrap these two methods into one. Native wrapper will preserve + // the original stack. + console[key] = wrapConsoleCall(inspectorConsole[key], + console[key], + config); + } + for (const key of Object.keys(inspectorConsole)) { + if (console.hasOwnProperty(key)) + continue; + console[key] = inspectorConsole[key]; + } + } + function setupProcessFatal() { process._fatalException = function(er) { diff --git a/lib/internal/repl.js b/lib/internal/repl.js index dd14f42fa52..7782d6b84bb 100644 --- a/lib/internal/repl.js +++ b/lib/internal/repl.js @@ -5,7 +5,8 @@ const REPL = require('repl'); const path = require('path'); const fs = require('fs'); const os = require('os'); -const debug = require('util').debuglog('repl'); +const util = require('util'); +const debug = util.debuglog('repl'); module.exports = Object.create(REPL); module.exports.createInternalRepl = createRepl; @@ -19,12 +20,12 @@ function createRepl(env, opts, cb) { cb = opts; opts = null; } - opts = opts || { + opts = util._extend({ ignoreUndefined: false, terminal: process.stdout.isTTY, useGlobal: true, breakEvalOnSigint: true - }; + }, opts); if (parseInt(env.NODE_NO_READLINE)) { opts.terminal = false; diff --git a/lib/internal/util.js b/lib/internal/util.js index e3d9a66b3b2..073879d9e9f 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -60,9 +60,18 @@ exports._deprecate = function(fn, msg) { var warned = false; function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); + if (new.target) { + return Reflect.construct(fn, arguments, new.target); + } return fn.apply(this, arguments); } + // The wrapper will keep the same prototype as fn to maintain prototype chain + Object.setPrototypeOf(deprecated, fn); + if (fn.prototype) { + Object.setPrototypeOf(deprecated.prototype, fn.prototype); + } + return deprecated; }; diff --git a/lib/module.js b/lib/module.js index b473631780a..fe9700f7a67 100644 --- a/lib/module.js +++ b/lib/module.js @@ -221,17 +221,29 @@ if (process.platform === 'win32') { // note: this approach *only* works when the path is guaranteed // to be absolute. Doing a fully-edge-case-correct path.split // that works on both Windows and Posix is non-trivial. + + // return root node_modules when path is 'D:\\'. + // path.resolve will make sure from.length >=3 in Windows. + if (from.charCodeAt(from.length - 1) === 92/*\*/ && + from.charCodeAt(from.length - 2) === 58/*:*/) + return [from + 'node_modules']; + const paths = []; var p = 0; var last = from.length; for (var i = from.length - 1; i >= 0; --i) { const code = from.charCodeAt(i); - if (code === 92/*\*/ || code === 47/*/*/) { + // The path segment separator check ('\' and '/') was used to get + // node_modules path for every path segment. + // Use colon as an extra condition since we can get node_modules + // path for dirver root like 'C:\node_modules' and don't need to + // parse driver name. + if (code === 92/*\*/ || code === 47/*/*/ || code === 58/*:*/) { if (p !== nmLen) paths.push(from.slice(0, last) + '\\node_modules'); last = i; p = 0; - } else if (p !== -1 && p < nmLen) { + } else if (p !== -1) { if (nmChars[p] === code) { ++p; } else { @@ -265,7 +277,7 @@ if (process.platform === 'win32') { paths.push(from.slice(0, last) + '/node_modules'); last = i; p = 0; - } else if (p !== -1 && p < nmLen) { + } else if (p !== -1) { if (nmChars[p] === code) { ++p; } else { @@ -274,6 +286,9 @@ if (process.platform === 'win32') { } } + // Append /node_modules to handle root paths. + paths.push('/node_modules'); + return paths; }; } diff --git a/lib/readline.js b/lib/readline.js index 402923e9255..9d34bb740db 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -41,6 +41,7 @@ function Interface(input, output, completer, terminal) { this._sawReturn = false; this.isCompletionEnabled = true; + this._previousKey = null; EventEmitter.call(this); var historySize; @@ -391,7 +392,7 @@ Interface.prototype._insertString = function(c) { } }; -Interface.prototype._tabComplete = function() { +Interface.prototype._tabComplete = function(lastKeypressWasTab) { var self = this; self.pause(); @@ -407,9 +408,7 @@ Interface.prototype._tabComplete = function() { const completeOn = rv[1]; // the text that was completed if (completions && completions.length) { // Apply/show completions. - if (completions.length === 1) { - self._insertString(completions[0].slice(completeOn.length)); - } else { + if (lastKeypressWasTab) { self._writeToOutput('\r\n'); var width = completions.reduce(function(a, b) { return a.length > b.length ? a : b; @@ -429,16 +428,15 @@ Interface.prototype._tabComplete = function() { } } handleGroup(self, group, width, maxColumns); + } - // If there is a common prefix to all matches, then apply that - // portion. - var f = completions.filter(function(e) { if (e) return e; }); - var prefix = commonPrefix(f); - if (prefix.length > completeOn.length) { - self._insertString(prefix.slice(completeOn.length)); - } - + // If there is a common prefix to all matches, then apply that portion. + const f = completions.filter(function(e) { if (e) return e; }); + const prefix = commonPrefix(f); + if (prefix.length > completeOn.length) { + self._insertString(prefix.slice(completeOn.length)); } + self._refreshLine(); } }); @@ -474,6 +472,7 @@ function commonPrefix(strings) { if (!strings || strings.length == 0) { return ''; } + if (strings.length === 1) return strings[0]; var sorted = strings.slice().sort(); var min = sorted[0]; var max = sorted[sorted.length - 1]; @@ -688,7 +687,9 @@ Interface.prototype._moveCursor = function(dx) { // handle a write from the tty Interface.prototype._ttyWrite = function(s, key) { + const previousKey = this._previousKey; key = key || {}; + this._previousKey = key; // Ignore escape key - Fixes #2876 if (key.name == 'escape') return; @@ -892,7 +893,8 @@ Interface.prototype._ttyWrite = function(s, key) { case 'tab': // If tab completion enabled, do that... if (typeof this.completer === 'function' && this.isCompletionEnabled) { - this._tabComplete(); + const lastKeypressWasTab = previousKey && previousKey.name === 'tab'; + this._tabComplete(lastKeypressWasTab); break; } // falls through diff --git a/lib/repl.js b/lib/repl.js index 9e9f05612bd..94b8c7ccb70 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -223,6 +223,7 @@ function REPLServer(prompt, self.underscoreAssigned = false; self.last = undefined; self.breakEvalOnSigint = !!breakEvalOnSigint; + self.editorMode = false; self._inTemplateLiteral = false; @@ -241,7 +242,7 @@ function REPLServer(prompt, var err, result, retry = false, input = code, wrappedErr; // first, create the Script object to check the syntax - if (code === '\n') + if (code === '\n' || code === '\r\n') return cb(null); while (true) { @@ -250,11 +251,11 @@ function REPLServer(prompt, (self.replMode === exports.REPL_MODE_STRICT || retry)) { // "void 0" keeps the repl from returning "use strict" as the // result value for let/const statements. - code = `'use strict'; void 0;\n${code}`; + code = `'use strict'; void 0;\r\n${code}`; } var script = vm.createScript(code, { filename: file, - displayErrors: false + displayErrors: true }); } catch (e) { debug('parse error %j', code, e); @@ -264,7 +265,7 @@ function REPLServer(prompt, if (self.wrappedCmd) { self.wrappedCmd = false; // unwrap and try again - code = `${input.substring(1, input.length - 2)}\n`; + code = `${input.substring(1, input.length - 2)}\r\n`; wrappedErr = e; } else { retry = true; @@ -288,7 +289,13 @@ function REPLServer(prompt, if (!err) { // Unset raw mode during evaluation so that Ctrl+C raises a signal. let previouslyInRawMode; - if (self.breakEvalOnSigint) { + + // Temporarily disabled on Windows due to output problems that likely + // result from the raw mode switches here, see + // https://github.com/nodejs/node/issues/7837 + // Setting NODE_REPL_CTRLC is meant as a temporary opt-in for debugging. + if (self.breakEvalOnSigint && + (process.platform !== 'win32' || process.env.NODE_REPL_CTRLC)) { // Start the SIGINT watchdog before entering raw mode so that a very // quick Ctrl+C doesn’t lead to aborting the process completely. utilBinding.startSigintWatchdog(); @@ -298,7 +305,7 @@ function REPLServer(prompt, try { try { const scriptOptions = { - displayErrors: false, + displayErrors: true, breakOnSigint: self.breakEvalOnSigint }; @@ -308,7 +315,8 @@ function REPLServer(prompt, result = script.runInContext(context, scriptOptions); } } finally { - if (self.breakEvalOnSigint) { + if (self.breakEvalOnSigint && + (process.platform !== 'win32' || process.env.NODE_REPL_CTRLC)) { // Reset terminal mode to its previous value. self._setRawMode(previouslyInRawMode); @@ -350,11 +358,16 @@ function REPLServer(prompt, debug('domain error'); const top = replMap.get(self); internalUtil.decorateErrorStack(e); - if (e.stack && self.replMode === exports.REPL_MODE_STRICT) { + if (e instanceof SyntaxError && e.stack) { + // remove repl:line-number and stack trace + e.stack = e.stack + .replace(/^repl:\d+\r?\n/, '') + .replace(/^\s+at\s.*\n?/gm, ''); + } else if (e.stack && self.replMode === exports.REPL_MODE_STRICT) { e.stack = e.stack.replace(/(\s+at\s+repl:)(\d+)/, (_, pre, line) => pre + (line - 1)); } - top.outputStream.write((e.stack || e) + '\n'); + top.outputStream.write((e.stack || e) + '\r\n'); top.lineParser.reset(); top.bufferedCommand = ''; top.lines.level = []; @@ -389,7 +402,12 @@ function REPLServer(prompt, // Figure out which "complete" function to use. self.completer = (typeof options.completer === 'function') ? options.completer - : complete; + : completer; + + function completer(text, cb) { + complete.call(self, text, self.editorMode + ? self.completeOnEditorMode(cb) : cb); + } Interface.call(this, { input: self.inputStream, @@ -423,9 +441,11 @@ function REPLServer(prompt, }); var sawSIGINT = false; + var sawCtrlD = false; self.on('SIGINT', function() { var empty = self.line.length === 0; self.clearLine(); + self.turnOffEditorMode(); if (!(self.bufferedCommand && self.bufferedCommand.length > 0) && empty) { if (sawSIGINT) { @@ -433,7 +453,7 @@ function REPLServer(prompt, sawSIGINT = false; return; } - self.output.write('(To exit, press ^C again or type .exit)\n'); + self.output.write('(To exit, press ^C again or type .exit)\r\n'); sawSIGINT = true; } else { sawSIGINT = false; @@ -449,6 +469,11 @@ function REPLServer(prompt, debug('line %j', cmd); sawSIGINT = false; + if (self.editorMode) { + self.bufferedCommand += cmd + '\r\n'; + return; + } + // leading whitespaces in template literals should not be trimmed. if (self._inTemplateLiteral) { self._inTemplateLiteral = false; @@ -465,7 +490,7 @@ function REPLServer(prompt, if (self.parseREPLKeyword(keyword, rest) === true) { return; } else if (!self.bufferedCommand) { - self.outputStream.write('Invalid REPL keyword\n'); + self.outputStream.write('Invalid REPL keyword\r\n'); finish(null); return; } @@ -484,8 +509,8 @@ function REPLServer(prompt, self.wrappedCmd = false; if (e && !self.bufferedCommand && cmd.trim().startsWith('npm ')) { self.outputStream.write('npm should be run outside of the ' + - 'node repl, in your normal shell.\n' + - '(Press Control-D to exit.)\n'); + 'node repl, in your normal shell.\r\n' + + '(Press Control-D to exit.)\r\n'); self.lineParser.reset(); self.bufferedCommand = ''; self.displayPrompt(); @@ -494,12 +519,13 @@ function REPLServer(prompt, // If error was SyntaxError and not JSON.parse error if (e) { - if (e instanceof Recoverable && !self.lineParser.shouldFail) { + if (e instanceof Recoverable && !self.lineParser.shouldFail && + !sawCtrlD) { // Start buffering data like that: // { // ... x: 1 // ... } - self.bufferedCommand += cmd + '\n'; + self.bufferedCommand += cmd + '\r\n'; self.displayPrompt(); return; } else { @@ -510,6 +536,7 @@ function REPLServer(prompt, // Clear buffer if no SyntaxErrors self.lineParser.reset(); self.bufferedCommand = ''; + sawCtrlD = false; // If we got any output - print it (if no error) if (!e && @@ -521,7 +548,7 @@ function REPLServer(prompt, if (!self.underscoreAssigned) { self.last = ret; } - self.outputStream.write(self.writer(ret) + '\n'); + self.outputStream.write(self.writer(ret) + '\r\n'); } // Display prompt again @@ -550,9 +577,55 @@ function REPLServer(prompt, }); self.on('SIGCONT', function() { - self.displayPrompt(true); + if (self.editorMode) { + self.outputStream.write(`${self._initialPrompt}.editor\r\n`); + self.outputStream.write( + '// Entering editor mode (^D to finish, ^C to cancel)\r\n'); + self.outputStream.write(`${self.bufferedCommand}\r\n`); + self.prompt(true); + } else { + self.displayPrompt(true); + } }); + // Wrap readline tty to enable editor mode + const ttyWrite = self._ttyWrite.bind(self); + self._ttyWrite = (d, key) => { + if (!self.editorMode || !self.terminal) { + ttyWrite(d, key); + return; + } + + // editor mode + if (key.ctrl && !key.shift) { + switch (key.name) { + case 'd': // End editor mode + self.turnOffEditorMode(); + sawCtrlD = true; + ttyWrite(d, { name: 'return' }); + break; + case 'n': // Override next history item + case 'p': // Override previous history item + break; + default: + ttyWrite(d, key); + } + } else { + switch (key.name) { + case 'up': // Override previous history item + case 'down': // Override next history item + break; + case 'tab': + // prevent double tab behavior + self._previousKey = null; + ttyWrite(d, key); + break; + default: + ttyWrite(d, key); + } + } + }; + self.displayPrompt(); } inherits(REPLServer, Interface); @@ -640,7 +713,7 @@ REPLServer.prototype.createContext = function() { this.last = value; if (!this.underscoreAssigned) { this.underscoreAssigned = true; - this.outputStream.write('Expression assignment to _ now disabled.\n'); + this.outputStream.write('Expression assignment to _ now disabled.\r\n'); } } }); @@ -675,6 +748,12 @@ REPLServer.prototype.setPrompt = function setPrompt(prompt) { REPLServer.super_.prototype.setPrompt.call(this, prompt); }; +REPLServer.prototype.turnOffEditorMode = function() { + this.editorMode = false; + this.setPrompt(this._initialPrompt); +}; + + // A stream to push an array into a REPL // used in REPLServer.complete function ArrayStream() { @@ -683,7 +762,7 @@ function ArrayStream() { this.run = function(data) { var self = this; data.forEach(function(line) { - self.emit('data', line + '\n'); + self.emit('data', line + '\r\n'); }); }; } @@ -982,6 +1061,39 @@ function complete(line, callback) { } } +function longestCommonPrefix(arr = []) { + const cnt = arr.length; + if (cnt === 0) return ''; + if (cnt === 1) return arr[0]; + + const first = arr[0]; + // complexity: O(m * n) + for (let m = 0; m < first.length; m++) { + const c = first[m]; + for (let n = 1; n < cnt; n++) { + const entry = arr[n]; + if (m >= entry.length || c !== entry[m]) { + return first.substring(0, m); + } + } + } + return first; +} + +REPLServer.prototype.completeOnEditorMode = (callback) => (err, results) => { + if (err) return callback(err); + + const [completions, completeOn = ''] = results; + const prefixLength = completeOn.length; + + if (prefixLength === 0) return callback(null, [[], completeOn]); + + const isNotEmpty = (v) => v.length > 0; + const trimCompleteOnPrefix = (v) => v.substring(prefixLength); + const data = completions.filter(isNotEmpty).map(trimCompleteOnPrefix); + + callback(null, [[`${completeOn}${longestCommonPrefix(data)}`], completeOn]); +}; /** * Used to parse and execute the Node REPL commands. @@ -1120,7 +1232,7 @@ function defineDefaultCommands(repl) { this.lineParser.reset(); this.bufferedCommand = ''; if (!this.useGlobal) { - this.outputStream.write('Clearing context...\n'); + this.outputStream.write('Clearing context...\r\n'); this.resetContext(); } this.displayPrompt(); @@ -1140,7 +1252,7 @@ function defineDefaultCommands(repl) { var self = this; Object.keys(this.commands).sort().forEach(function(name) { var cmd = self.commands[name]; - self.outputStream.write(name + '\t' + (cmd.help || '') + '\n'); + self.outputStream.write(name + '\t' + (cmd.help || '') + '\r\n'); }); this.displayPrompt(); } @@ -1150,10 +1262,10 @@ function defineDefaultCommands(repl) { help: 'Save all evaluated commands in this REPL session to a file', action: function(file) { try { - fs.writeFileSync(file, this.lines.join('\n') + '\n'); - this.outputStream.write('Session saved to:' + file + '\n'); + fs.writeFileSync(file, this.lines.join('\r\n') + '\r\n'); + this.outputStream.write('Session saved to:' + file + '\r\n'); } catch (e) { - this.outputStream.write('Failed to save:' + file + '\n'); + this.outputStream.write('Failed to save:' + file + '\r\n'); } this.displayPrompt(); } @@ -1167,23 +1279,36 @@ function defineDefaultCommands(repl) { if (stats && stats.isFile()) { var self = this; var data = fs.readFileSync(file, 'utf8'); - var lines = data.split('\n'); + // \r\n, \n, or \r followed by something other than \n + const lineEnding = /\r?\n|\r(?!\n)/; + var lines = data.split(lineEnding); this.displayPrompt(); lines.forEach(function(line) { if (line) { - self.write(line + '\n'); + self.write(line + '\r\n'); } }); } else { this.outputStream.write('Failed to load:' + file + - ' is not a valid file\n'); + ' is not a valid file\r\n'); } } catch (e) { - this.outputStream.write('Failed to load:' + file + '\n'); + this.outputStream.write('Failed to load:' + file + '\r\n'); } this.displayPrompt(); } }); + + repl.defineCommand('editor', { + help: 'Entering editor mode (^D to finish, ^C to cancel)', + action() { + if (!this.terminal) return; + this.editorMode = true; + REPLServer.super_.prototype.setPrompt.call(this, ''); + this.outputStream.write( + '// Entering editor mode (^D to finish, ^C to cancel)\r\n'); + } + }); } function regexpEscape(s) { @@ -1199,7 +1324,9 @@ function regexpEscape(s) { * @param {String} cmd The cmd to convert. * @return {String} The converted command. */ -REPLServer.prototype.convertToContext = function(cmd) { +// TODO(princejwesley): Remove it prior to v8.0.0 release +// Reference: https://github.com/nodejs/node/pull/7829 +REPLServer.prototype.convertToContext = util.deprecate(function(cmd) { const scopeVar = /^\s*var\s*([_\w\$]+)(.*)$/m; const scopeFunc = /^\s*function\s*([_\w\$]+)/; var matches; @@ -1217,7 +1344,7 @@ REPLServer.prototype.convertToContext = function(cmd) { } return cmd; -}; +}, 'replServer.convertToContext() is deprecated'); function bailOnIllegalToken(parser) { return parser._literal === null && diff --git a/lib/timers.js b/lib/timers.js index 7379cfe3591..f6ecf3e100a 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -135,7 +135,7 @@ function insert(item, unrefed) { list._timer._list = list; if (unrefed === true) list._timer.unref(); - list._timer.start(msecs, 0); + list._timer.start(msecs); lists[msecs] = list; list._timer[kOnTimeout] = listOnTimeout; @@ -173,7 +173,7 @@ function listOnTimeout() { if (timeRemaining < 0) { timeRemaining = 0; } - this.start(timeRemaining, 0); + this.start(timeRemaining); debug('%d list wait because diff is %d', msecs, diff); return; } @@ -211,9 +211,13 @@ function listOnTimeout() { debug('%d list empty', msecs); assert(L.isEmpty(list)); this.close(); - if (list._unrefed === true) { + + // Either refedLists[msecs] or unrefedLists[msecs] may have been removed and + // recreated since the reference to `list` was created. Make sure they're + // the same instance of the list before destroying. + if (list._unrefed === true && list === unrefedLists[msecs]) { delete unrefedLists[msecs]; - } else { + } else if (list === refedLists[msecs]) { delete refedLists[msecs]; } } @@ -426,7 +430,7 @@ exports.setInterval = function(callback, repeat) { // If timer is unref'd (or was - it's permanently removed from the list.) if (this._handle) { - this._handle.start(repeat, 0); + this._handle.start(repeat); } else { timer._idleTimeout = repeat; active(timer); @@ -481,7 +485,7 @@ Timeout.prototype.unref = function() { this._handle = handle || new TimerWrap(); this._handle.owner = this; this._handle[kOnTimeout] = unrefdHandle; - this._handle.start(delay, 0); + this._handle.start(delay); this._handle.domain = this.domain; this._handle.unref(); } diff --git a/lib/tty.js b/lib/tty.js index fe0cc2e5219..576144e4013 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -48,12 +48,12 @@ function WriteStream(fd) { writable: true }); - // Prevents interleaved stdout/stderr output in OS X terminals. + // Prevents interleaved or dropped stdout/stderr output for terminals. // As noted in the following reference, local TTYs tend to be quite fast and // this behaviour has become expected due historical functionality on OS X, // even though it was originally intended to change in v1.0.2 (Libuv 1.2.1). // Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671 - if (process.platform === 'darwin') this._handle.setBlocking(true); + this._handle.setBlocking(process.env.NODE_TTY_UNSAFE_ASYNC !== '1'); var winSize = []; var err = this._handle.getWindowSize(winSize); diff --git a/lib/util.js b/lib/util.js index bb588cf475e..99b480d522b 100644 --- a/lib/util.js +++ b/lib/util.js @@ -6,7 +6,16 @@ const internalUtil = require('internal/util'); const binding = process.binding('util'); const isError = internalUtil.isError; -const kDefaultMaxLength = 100; + +const inspectDefaultOptions = Object.seal({ + showHidden: false, + depth: 2, + colors: false, + customInspect: true, + showProxy: false, + maxArrayLength: 100, + breakLength: 60 +}); var Debug; var simdFormatters; @@ -176,29 +185,31 @@ function inspect(obj, opts) { stylize: stylizeNoColor }; // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; + if (arguments[2] !== undefined) ctx.depth = arguments[2]; + if (arguments[3] !== undefined) ctx.colors = arguments[3]; if (typeof opts === 'boolean') { // legacy... ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); } - // set default options - if (ctx.showHidden === undefined) ctx.showHidden = false; - if (ctx.depth === undefined) ctx.depth = 2; - if (ctx.colors === undefined) ctx.colors = false; - if (ctx.customInspect === undefined) ctx.customInspect = true; - if (ctx.showProxy === undefined) ctx.showProxy = false; + // Set default and user-specified options + ctx = Object.assign({}, inspect.defaultOptions, ctx, opts); if (ctx.colors) ctx.stylize = stylizeWithColor; - if (ctx.maxArrayLength === undefined) ctx.maxArrayLength = kDefaultMaxLength; if (ctx.maxArrayLength === null) ctx.maxArrayLength = Infinity; - if (ctx.breakLength === undefined) ctx.breakLength = 60; return formatValue(ctx, obj, ctx.depth); } -exports.inspect = inspect; +Object.defineProperty(inspect, 'defaultOptions', { + get: function() { + return inspectDefaultOptions; + }, + set: function(options) { + if (options === null || typeof options !== 'object') { + throw new TypeError('"options" must be an object'); + } + Object.assign(inspectDefaultOptions, options); + return inspectDefaultOptions; + } +}); // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics inspect.colors = { @@ -231,6 +242,7 @@ inspect.styles = { 'regexp': 'red' }; +exports.inspect = inspect; function stylizeWithColor(str, styleType) { var style = inspect.styles[styleType]; @@ -487,16 +499,13 @@ function formatValue(ctx, value, recurseTimes) { 'byteOffset', 'buffer'); } - } else if (simdFormatters && - typeof value.constructor === 'function' && - (formatter = simdFormatters.get(value.constructor))) { - braces = ['[', ']']; } else { var promiseInternals = inspectPromise(value); if (promiseInternals) { braces = ['{', '}']; formatter = formatPromise; } else { + let maybeSimdFormatter; if (binding.isMapIterator(value)) { constructor = { name: 'MapIterator' }; braces = ['{', '}']; @@ -507,6 +516,11 @@ function formatValue(ctx, value, recurseTimes) { braces = ['{', '}']; empty = false; formatter = formatCollectionIterator; + } else if (simdFormatters && + typeof constructor === 'function' && + (maybeSimdFormatter = simdFormatters.get(constructor))) { + braces = ['[', ']']; + formatter = maybeSimdFormatter; } else { // Unset the constructor to prevent "Object {...}" for ordinary objects. if (constructor && constructor.name === 'Object') @@ -822,9 +836,9 @@ function reduceToSingleString(output, base, braces, breakLength) { // If the opening "brace" is too large, like in the case of "Set {", // we need to force the first item to be on the next line or the // items will not line up correctly. - (base === '' && braces[0].length === 1 ? '' : base + '\n ') + + (base === '' && braces[0].length === 1 ? '' : base + '\r\n ') + ' ' + - output.join(',\n ') + + output.join(',\r\n ') + ' ' + braces[1]; } @@ -987,19 +1001,19 @@ exports.print = internalUtil.deprecate(function() { exports.puts = internalUtil.deprecate(function() { for (var i = 0, len = arguments.length; i < len; ++i) { - process.stdout.write(arguments[i] + '\n'); + process.stdout.write(arguments[i] + '\r\n'); } }, 'util.puts is deprecated. Use console.log instead.'); exports.debug = internalUtil.deprecate(function(x) { - process.stderr.write('DEBUG: ' + x + '\n'); + process.stderr.write('DEBUG: ' + x + '\r\n'); }, 'util.debug is deprecated. Use console.error instead.'); exports.error = internalUtil.deprecate(function(x) { for (var i = 0, len = arguments.length; i < len; ++i) { - process.stderr.write(arguments[i] + '\n'); + process.stderr.write(arguments[i] + '\r\n'); } }, 'util.error is deprecated. Use console.error instead.'); diff --git a/node.gyp b/node.gyp index dfeda52d32a..5e522176f05 100644 --- a/node.gyp +++ b/node.gyp @@ -9,6 +9,7 @@ 'node_use_v8_platform%': 'true', 'node_use_bundled_v8%': 'true', 'node_shared%': 'false', + 'force_dynamic_crt%': 0, 'node_module_version%': '', 'node_shared_zlib%': 'false', 'node_shared_http_parser%': 'false', @@ -143,6 +144,7 @@ 'src/fs_event_wrap.cc', 'src/cares_wrap.cc', 'src/connection_wrap.cc', + 'src/connect_wrap.cc', 'src/handle_wrap.cc', 'src/js_stream.cc', 'src/node.cc', @@ -180,6 +182,7 @@ 'src/base-object.h', 'src/base-object-inl.h', 'src/connection_wrap.h', + 'src/connect_wrap.h', 'src/debug-agent.h', 'src/env.h', 'src/env-inl.h', @@ -246,8 +249,8 @@ 'NODE_SHARED_MODE', ], 'conditions': [ - [ 'node_module_version!=""', { - 'product_extension': 'so.<(node_module_version)', + [ 'node_module_version!="" and OS!="win"', { + 'product_extension': '<(shlib_suffix)', }] ], }], @@ -315,7 +318,7 @@ 'src/inspector_agent.cc', 'src/inspector_socket.cc', 'src/inspector_socket.h', - 'src/inspector-agent.h', + 'src/inspector_agent.h', ], 'dependencies': [ 'deps/v8_inspector/third_party/v8_inspector/platform/' @@ -364,13 +367,20 @@ 'conditions': [ ['OS in "linux freebsd" and node_shared=="false"', { 'ldflags': [ - '-Wl,--whole-archive <(PRODUCT_DIR)/<(OPENSSL_PRODUCT)', + '-Wl,--whole-archive,' + '<(PRODUCT_DIR)/obj.target/deps/openssl/' + '<(OPENSSL_PRODUCT)', '-Wl,--no-whole-archive', ], }], + # openssl.def is based on zlib.def, zlib symbols + # are always exported. ['use_openssl_def==1', { 'sources': ['<(SHARED_INTERMEDIATE_DIR)/openssl.def'], }], + ['OS=="win" and use_openssl_def==0', { + 'sources': ['deps/zlib/win32/zlib.def'], + }], ], }], ], @@ -583,6 +593,8 @@ '-X^DSO', '-X^_', '-X^private_', + # Base generated DEF on zlib.def + '-Bdeps/zlib/win32/zlib.def' ], }, 'conditions': [ diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index bdbbd1a4609..4a9c6f7a9cd 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -36,7 +36,6 @@ namespace cares_wrap { using v8::Array; using v8::Context; using v8::EscapableHandleScope; -using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; diff --git a/src/connect_wrap.cc b/src/connect_wrap.cc new file mode 100644 index 00000000000..df3f093e732 --- /dev/null +++ b/src/connect_wrap.cc @@ -0,0 +1,22 @@ +#include "connect_wrap.h" + +#include "env.h" +#include "env-inl.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" +#include "util.h" +#include "util-inl.h" + +namespace node { + +using v8::Local; +using v8::Object; + + +ConnectWrap::ConnectWrap(Environment* env, + Local req_wrap_obj, + AsyncWrap::ProviderType provider) : ReqWrap(env, req_wrap_obj, provider) { + Wrap(req_wrap_obj, this); +} + +} // namespace node diff --git a/src/connect_wrap.h b/src/connect_wrap.h new file mode 100644 index 00000000000..28d4872d7ed --- /dev/null +++ b/src/connect_wrap.h @@ -0,0 +1,26 @@ +#ifndef SRC_CONNECT_WRAP_H_ +#define SRC_CONNECT_WRAP_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "env.h" +#include "req-wrap.h" +#include "async-wrap.h" +#include "v8.h" + +namespace node { + +class ConnectWrap : public ReqWrap { + public: + ConnectWrap(Environment* env, + v8::Local req_wrap_obj, + AsyncWrap::ProviderType provider); + + size_t self_size() const override { return sizeof(*this); } +}; + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_CONNECT_WRAP_H_ diff --git a/src/debug-agent.cc b/src/debug-agent.cc index 920f42e77ea..14ac382ada0 100644 --- a/src/debug-agent.cc +++ b/src/debug-agent.cc @@ -36,7 +36,6 @@ namespace node { namespace debugger { using v8::Context; -using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; diff --git a/src/env.cc b/src/env.cc index 2598e775e8e..8efe13816c0 100644 --- a/src/env.cc +++ b/src/env.cc @@ -21,7 +21,6 @@ using v8::Local; using v8::Message; using v8::StackFrame; using v8::StackTrace; -using v8::Value; void Environment::Start(int argc, const char* const* argv, diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 66928e09b11..5b6a8f01bb3 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -9,7 +9,11 @@ #include "v8-platform.h" #include "util.h" +#include "platform/v8_inspector/public/InspectorVersion.h" #include "platform/v8_inspector/public/V8Inspector.h" +#include "platform/v8_inspector/public/V8InspectorClient.h" +#include "platform/v8_inspector/public/V8InspectorSession.h" +#include "platform/v8_inspector/public/V8StackTrace.h" #include "platform/inspector_protocol/FrontendChannel.h" #include "platform/inspector_protocol/String16.h" #include "platform/inspector_protocol/Values.h" @@ -36,7 +40,7 @@ const char TAG_CONNECT[] = "#connect"; const char TAG_DISCONNECT[] = "#disconnect"; const char DEVTOOLS_PATH[] = "/node"; -const char DEVTOOLS_HASH[] = "851972d6da7463c353d712d2cb6c1ec23fa6c4fe"; +const char DEVTOOLS_HASH[] = V8_INSPECTOR_REVISION; void PrintDebuggerReadyMessage(int port) { fprintf(stderr, "Debugger listening on port %d.\n" @@ -48,8 +52,8 @@ void PrintDebuggerReadyMessage(int port) { port, DEVTOOLS_HASH, port); } -bool AcceptsConnection(inspector_socket_t* socket, const char* path) { - return strncmp(DEVTOOLS_PATH, path, sizeof(DEVTOOLS_PATH)) == 0; +bool AcceptsConnection(inspector_socket_t* socket, const std::string& path) { + return 0 == path.compare(0, sizeof(DEVTOOLS_PATH) - 1, DEVTOOLS_PATH); } void DisposeInspector(inspector_socket_t* socket, int status) { @@ -63,10 +67,7 @@ void DisconnectAndDisposeIO(inspector_socket_t* socket) { } void OnBufferAlloc(uv_handle_t* handle, size_t len, uv_buf_t* buf) { - if (len > 0) { - buf->base = static_cast(malloc(len)); - CHECK_NE(buf->base, nullptr); - } + buf->base = new char[len]; buf->len = len; } @@ -133,18 +134,19 @@ void SendTargentsListResponse(inspector_socket_t* socket, int port) { SendHttpResponse(socket, buffer, len); } -bool RespondToGet(inspector_socket_t* socket, const char* path, int port) { +bool RespondToGet(inspector_socket_t* socket, const std::string& path, + int port) { const char PATH[] = "/json"; const char PATH_LIST[] = "/json/list"; const char PATH_VERSION[] = "/json/version"; const char PATH_ACTIVATE[] = "/json/activate/"; - if (!strncmp(PATH_VERSION, path, sizeof(PATH_VERSION))) { + if (0 == path.compare(0, sizeof(PATH_VERSION) - 1, PATH_VERSION)) { SendVersionResponse(socket); - } else if (!strncmp(PATH_LIST, path, sizeof(PATH_LIST)) || - !strncmp(PATH, path, sizeof(PATH))) { + } else if (0 == path.compare(0, sizeof(PATH_LIST) - 1, PATH_LIST) || + 0 == path.compare(0, sizeof(PATH) - 1, PATH)) { SendTargentsListResponse(socket, port); - } else if (!strncmp(path, PATH_ACTIVATE, sizeof(PATH_ACTIVATE) - 1) && - atoi(path + (sizeof(PATH_ACTIVATE) - 1)) == getpid()) { + } else if (0 == path.compare(0, sizeof(PATH_ACTIVATE) - 1, PATH_ACTIVATE) && + atoi(path.substr(sizeof(PATH_ACTIVATE) - 1).c_str()) == getpid()) { const char TARGET_ACTIVATED[] = "Target activated"; SendHttpResponse(socket, TARGET_ACTIVATED, sizeof(TARGET_ACTIVATED) - 1); } else { @@ -157,7 +159,8 @@ bool RespondToGet(inspector_socket_t* socket, const char* path, int port) { namespace inspector { -using blink::protocol::DictionaryValue; + +class V8NodeInspector; class AgentImpl { public: @@ -165,24 +168,30 @@ class AgentImpl { ~AgentImpl(); // Start the inspector agent thread - void Start(v8::Platform* platform, int port, bool wait); + bool Start(v8::Platform* platform, int port, bool wait); // Stop the inspector agent void Stop(); bool IsStarted(); - bool IsConnected() { return connected_; } + bool IsConnected() { return state_ == State::kConnected; } void WaitForDisconnect(); + void FatalException(v8::Local error, + v8::Local message); + private: using MessageQueue = std::vector>; + enum class State { kNew, kAccepting, kConnected, kDone, kError }; static void ThreadCbIO(void* agent); static void OnSocketConnectionIO(uv_stream_t* server, int status); static bool OnInspectorHandshakeIO(inspector_socket_t* socket, enum inspector_handshake_event state, - const char* path); + const std::string& path); static void WriteCbIO(uv_async_t* async); + void InstallInspectorOnProcess(); + void WorkerRunIO(); void OnInspectorConnectionIO(inspector_socket_t* socket); void OnRemoteDataIO(inspector_socket_t* stream, ssize_t read, @@ -195,6 +204,7 @@ class AgentImpl { const String16& message); void SwapBehindLock(MessageQueue* vector1, MessageQueue* vector2); void PostIncomingMessage(const String16& message); + State ToState(State state); uv_sem_t start_sem_; ConditionVariable pause_cond_; @@ -205,14 +215,14 @@ class AgentImpl { int port_; bool wait_; - bool connected_; bool shutting_down_; + State state_; node::Environment* parent_env_; - uv_async_t data_written_; + uv_async_t* data_written_; uv_async_t io_thread_req_; inspector_socket_t* client_socket_; - blink::V8Inspector* inspector_; + V8NodeInspector* inspector_; v8::Platform* platform_; MessageQueue incoming_message_queue_; MessageQueue outgoing_message_queue_; @@ -272,16 +282,23 @@ class ChannelImpl final : public blink::protocol::FrontendChannel { AgentImpl* const agent_; }; -class V8NodeInspector : public blink::V8Inspector { +// Used in V8NodeInspector::currentTimeMS() below. +#define NANOS_PER_MSEC 1000000 + +class V8NodeInspector : public blink::V8InspectorClient { public: V8NodeInspector(AgentImpl* agent, node::Environment* env, v8::Platform* platform) - : blink::V8Inspector(env->isolate(), env->context()), - agent_(agent), + : agent_(agent), isolate_(env->isolate()), platform_(platform), terminated_(false), - running_nested_loop_(false) {} + running_nested_loop_(false), + inspector_( + blink::V8Inspector::create(env->isolate(), this)) { + inspector_->contextCreated( + blink::V8ContextInfo(env->context(), 1, "NodeJS Main Context")); + } void runMessageLoopOnPause(int context_group_id) override { if (running_nested_loop_) @@ -300,23 +317,47 @@ class V8NodeInspector : public blink::V8Inspector { running_nested_loop_ = false; } + double currentTimeMS() override { + return uv_hrtime() * 1.0 / NANOS_PER_MSEC; + } + void quitMessageLoopOnPause() override { terminated_ = true; } + void connectFrontend() { + session_ = inspector_->connect(1, new ChannelImpl(agent_), nullptr); + } + + void disconnectFrontend() { + session_.reset(); + } + + void dispatchMessageFromFrontend(const String16& message) { + CHECK(session_); + session_->dispatchProtocolMessage(message); + } + + blink::V8Inspector* inspector() { + return inspector_.get(); + } + private: AgentImpl* agent_; v8::Isolate* isolate_; v8::Platform* platform_; bool terminated_; bool running_nested_loop_; + std::unique_ptr inspector_; + std::unique_ptr session_; }; AgentImpl::AgentImpl(Environment* env) : port_(0), wait_(false), - connected_(false), shutting_down_(false), + state_(State::kNew), parent_env_(env), + data_written_(new uv_async_t()), client_socket_(nullptr), inspector_(nullptr), platform_(nullptr), @@ -324,30 +365,93 @@ AgentImpl::AgentImpl(Environment* env) : port_(0), frontend_session_id_(0), backend_session_id_(0) { CHECK_EQ(0, uv_sem_init(&start_sem_, 0)); - memset(&data_written_, 0, sizeof(data_written_)); memset(&io_thread_req_, 0, sizeof(io_thread_req_)); + CHECK_EQ(0, uv_async_init(env->event_loop(), data_written_, nullptr)); + uv_unref(reinterpret_cast(data_written_)); } AgentImpl::~AgentImpl() { - if (!inspector_) - return; - uv_close(reinterpret_cast(&data_written_), nullptr); + auto close_cb = [](uv_handle_t* handle) { + delete reinterpret_cast(handle); + }; + uv_close(reinterpret_cast(data_written_), close_cb); + data_written_ = nullptr; +} + +void InspectorConsoleCall(const v8::FunctionCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::Local context = isolate->GetCurrentContext(); + + CHECK(info.Data()->IsArray()); + v8::Local args = info.Data().As(); + CHECK_EQ(args->Length(), 3); + + v8::Local inspector_method = + args->Get(context, 0).ToLocalChecked(); + CHECK(inspector_method->IsFunction()); + v8::Local node_method = + args->Get(context, 1).ToLocalChecked(); + CHECK(node_method->IsFunction()); + v8::Local config_value = + args->Get(context, 2).ToLocalChecked(); + CHECK(config_value->IsObject()); + v8::Local config_object = config_value.As(); + + std::vector> call_args(info.Length()); + for (int i = 0; i < info.Length(); ++i) { + call_args[i] = info[i]; + } + + v8::Local in_call_key = OneByteString(isolate, "in_call"); + bool in_call = config_object->Has(context, in_call_key).FromMaybe(false); + if (!in_call) { + CHECK(config_object->Set(context, + in_call_key, + v8::True(isolate)).FromJust()); + CHECK(!inspector_method.As()->Call( + context, + info.Holder(), + call_args.size(), + call_args.data()).IsEmpty()); + } + + v8::TryCatch try_catch(info.GetIsolate()); + node_method.As()->Call(context, + info.Holder(), + call_args.size(), + call_args.data()); + CHECK(config_object->Delete(context, in_call_key).FromJust()); + if (try_catch.HasCaught()) + try_catch.ReThrow(); } -void AgentImpl::Start(v8::Platform* platform, int port, bool wait) { - auto env = parent_env_; - inspector_ = new V8NodeInspector(this, env, platform); +void InspectorWrapConsoleCall(const v8::FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + if (args.Length() != 3 || !args[0]->IsFunction() || + !args[1]->IsFunction() || !args[2]->IsObject()) { + return env->ThrowError("inspector.wrapConsoleCall takes exactly 3 " + "arguments: two functions and an object."); + } - int err; + v8::Local array = v8::Array::New(env->isolate(), args.Length()); + CHECK(array->Set(env->context(), 0, args[0]).FromJust()); + CHECK(array->Set(env->context(), 1, args[1]).FromJust()); + CHECK(array->Set(env->context(), 2, args[2]).FromJust()); + args.GetReturnValue().Set(v8::Function::New(env->context(), + InspectorConsoleCall, + array).ToLocalChecked()); +} +bool AgentImpl::Start(v8::Platform* platform, int port, bool wait) { + auto env = parent_env_; + inspector_ = new V8NodeInspector(this, env, platform); platform_ = platform; - err = uv_loop_init(&child_loop_); - CHECK_EQ(err, 0); - err = uv_async_init(env->event_loop(), &data_written_, nullptr); - CHECK_EQ(err, 0); + InstallInspectorOnProcess(); - uv_unref(reinterpret_cast(&data_written_)); + int err = uv_loop_init(&child_loop_); + CHECK_EQ(err, 0); port_ = port; wait_ = wait; @@ -356,21 +460,20 @@ void AgentImpl::Start(v8::Platform* platform, int port, bool wait) { CHECK_EQ(err, 0); uv_sem_wait(&start_sem_); + if (state_ == State::kError) { + Stop(); + return false; + } + state_ = State::kAccepting; if (wait) { DispatchMessages(); } + return true; } void AgentImpl::Stop() { - // TODO(repenaxa): hop on the right thread. - DisconnectAndDisposeIO(client_socket_); int err = uv_thread_join(&thread_); CHECK_EQ(err, 0); - - uv_run(&child_loop_, UV_RUN_NOWAIT); - - err = uv_loop_close(&child_loop_); - CHECK_EQ(err, 0); delete inspector_; } @@ -384,6 +487,62 @@ void AgentImpl::WaitForDisconnect() { inspector_->runMessageLoopOnPause(0); } +#define READONLY_PROPERTY(obj, str, var) \ + do { \ + obj->DefineOwnProperty(env->context(), \ + OneByteString(env->isolate(), str), \ + var, \ + v8::ReadOnly).FromJust(); \ + } while (0) + +void AgentImpl::InstallInspectorOnProcess() { + auto env = parent_env_; + v8::Local process = env->process_object(); + v8::Local inspector = v8::Object::New(env->isolate()); + READONLY_PROPERTY(process, "inspector", inspector); + env->SetMethod(inspector, "wrapConsoleCall", InspectorWrapConsoleCall); +} + +String16 ToProtocolString(v8::Local value) { + if (value.IsEmpty() || value->IsNull() || value->IsUndefined() || + !value->IsString()) { + return String16(); + } + v8::Local string_value = v8::Local::Cast(value); + wstring buffer(string_value->Length(), '\0'); + string_value->Write(&buffer[0], 0, string_value->Length()); + return String16(buffer); +} + +void AgentImpl::FatalException(v8::Local error, + v8::Local message) { + if (!IsStarted()) + return; + auto env = parent_env_; + v8::Local context = env->context(); + + int script_id = message->GetScriptOrigin().ScriptID()->Value(); + std::unique_ptr stack_trace = + inspector_->inspector()->createStackTrace(message->GetStackTrace()); + + if (stack_trace && !stack_trace->isEmpty() && + String16::fromInteger(script_id) == stack_trace->topScriptId()) { + script_id = 0; + } + + inspector_->inspector()->exceptionThrown( + context, + "Uncaught", + error, + ToProtocolString(message->Get()), + ToProtocolString(message->GetScriptResourceName()), + message->GetLineNumber(context).FromMaybe(0), + message->GetStartColumn(context).FromMaybe(0), + std::move(stack_trace), + script_id); + WaitForDisconnect(); +} + // static void AgentImpl::ThreadCbIO(void* agent) { static_cast(agent)->WorkerRunIO(); @@ -393,7 +552,6 @@ void AgentImpl::ThreadCbIO(void* agent) { void AgentImpl::OnSocketConnectionIO(uv_stream_t* server, int status) { if (status == 0) { inspector_socket_t* socket = new inspector_socket_t(); - memset(socket, 0, sizeof(*socket)); socket->data = server->data; if (inspector_accept(server, socket, AgentImpl::OnInspectorHandshakeIO) != 0) { @@ -404,8 +562,8 @@ void AgentImpl::OnSocketConnectionIO(uv_stream_t* server, int status) { // static bool AgentImpl::OnInspectorHandshakeIO(inspector_socket_t* socket, - enum inspector_handshake_event state, - const char* path) { + enum inspector_handshake_event state, + const std::string& path) { AgentImpl* agent = static_cast(socket->data); switch (state) { case kInspectorHandshakeHttpGet: @@ -429,7 +587,6 @@ void AgentImpl::OnRemoteDataIO(inspector_socket_t* socket, Mutex::ScopedLock scoped_lock(pause_lock_); if (read > 0) { String16 str = String16::fromUTF8(buf->base, read); - PostIncomingMessage(str); // TODO(pfeldman): Instead of blocking execution while debugger // engages, node should wait for the run callback from the remote client // and initiate its startup. This is a change to node.cc that should be @@ -438,11 +595,7 @@ void AgentImpl::OnRemoteDataIO(inspector_socket_t* socket, wait_ = false; uv_sem_post(&start_sem_); } - - platform_->CallOnForegroundThread(parent_env_->isolate(), - new DispatchOnInspectorBackendTask(this)); - parent_env_->isolate()->RequestInterrupt(InterruptCallback, this); - uv_async_send(&data_written_); + PostIncomingMessage(str); } else if (read <= 0) { // EOF if (client_socket_ == socket) { @@ -453,7 +606,7 @@ void AgentImpl::OnRemoteDataIO(inspector_socket_t* socket, DisconnectAndDisposeIO(socket); } if (buf) { - free(buf->base); + delete[] buf->base; } pause_cond_.Broadcast(scoped_lock); } @@ -477,8 +630,10 @@ void AgentImpl::WriteCbIO(uv_async_t* async) { void AgentImpl::WorkerRunIO() { sockaddr_in addr; uv_tcp_t server; - int err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO); - CHECK_EQ(0, err); + int err = uv_loop_init(&child_loop_); + CHECK_EQ(err, 0); + err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO); + CHECK_EQ(err, 0); io_thread_req_.data = this; uv_tcp_init(&child_loop_, &server); uv_ip4_addr("0.0.0.0", port_, &addr); @@ -489,19 +644,26 @@ void AgentImpl::WorkerRunIO() { err = uv_listen(reinterpret_cast(&server), 1, OnSocketConnectionIO); } - if (err == 0) { - PrintDebuggerReadyMessage(port_); - } else { + if (err != 0) { fprintf(stderr, "Unable to open devtools socket: %s\n", uv_strerror(err)); - ABORT(); + state_ = State::kError; // Safe, main thread is waiting on semaphore + uv_close(reinterpret_cast(&io_thread_req_), nullptr); + uv_close(reinterpret_cast(&server), nullptr); + uv_loop_close(&child_loop_); + uv_sem_post(&start_sem_); + return; } + PrintDebuggerReadyMessage(port_); if (!wait_) { uv_sem_post(&start_sem_); } uv_run(&child_loop_, UV_RUN_DEFAULT); uv_close(reinterpret_cast(&io_thread_req_), nullptr); uv_close(reinterpret_cast(&server), nullptr); - uv_run(&child_loop_, UV_RUN_DEFAULT); + DisconnectAndDisposeIO(client_socket_); + uv_run(&child_loop_, UV_RUN_NOWAIT); + err = uv_loop_close(&child_loop_); + CHECK_EQ(err, 0); } void AgentImpl::AppendMessage(MessageQueue* queue, int session_id, @@ -521,7 +683,7 @@ void AgentImpl::PostIncomingMessage(const String16& message) { platform_->CallOnForegroundThread(isolate, new DispatchOnInspectorBackendTask(this)); isolate->RequestInterrupt(InterruptCallback, this); - uv_async_send(&data_written_); + uv_async_send(data_written_); } void AgentImpl::OnInspectorConnectionIO(inspector_socket_t* socket) { @@ -544,23 +706,26 @@ void AgentImpl::DispatchMessages() { for (const MessageQueue::value_type& pair : tasks) { const String16& message = pair.second; if (message == TAG_CONNECT) { - CHECK_EQ(false, connected_); + CHECK_EQ(State::kAccepting, state_); backend_session_id_++; - connected_ = true; + state_ = State::kConnected; fprintf(stderr, "Debugger attached.\n"); - inspector_->connectFrontend(new ChannelImpl(this)); + inspector_->connectFrontend(); } else if (message == TAG_DISCONNECT) { - CHECK(connected_); - connected_ = false; - if (!shutting_down_) + CHECK_EQ(State::kConnected, state_); + if (shutting_down_) { + state_ = State::kDone; + } else { PrintDebuggerReadyMessage(port_); + state_ = State::kAccepting; + } inspector_->quitMessageLoopOnPause(); inspector_->disconnectFrontend(); } else { inspector_->dispatchMessageFromFrontend(message); } } - uv_async_send(&data_written_); + uv_async_send(data_written_); dispatching_messages_ = false; } @@ -577,8 +742,8 @@ Agent::~Agent() { delete impl; } -void Agent::Start(v8::Platform* platform, int port, bool wait) { - impl->Start(platform, port, wait); +bool Agent::Start(v8::Platform* platform, int port, bool wait) { + return impl->Start(platform, port, wait); } void Agent::Stop() { @@ -597,5 +762,11 @@ void Agent::WaitForDisconnect() { impl->WaitForDisconnect(); } +void Agent::FatalException(v8::Local error, + v8::Local message) { + impl->FatalException(error, message); +} + + } // namespace inspector } // namespace node diff --git a/src/inspector_agent.h b/src/inspector_agent.h index 863f1c30c33..43433fdc6e6 100644 --- a/src/inspector_agent.h +++ b/src/inspector_agent.h @@ -12,6 +12,10 @@ class Environment; namespace v8 { class Platform; +template +class Local; +class Value; +class Message; } // namespace v8 namespace node { @@ -25,13 +29,16 @@ class Agent { ~Agent(); // Start the inspector agent thread - void Start(v8::Platform* platform, int port, bool wait); + bool Start(v8::Platform* platform, int port, bool wait); // Stop the inspector agent void Stop(); bool IsStarted(); bool IsConnected(); void WaitForDisconnect(); + + void FatalException(v8::Local error, + v8::Local message); private: AgentImpl* impl; }; diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc index d3a8d8efffc..c360ef0db95 100644 --- a/src/inspector_socket.cc +++ b/src/inspector_socket.cc @@ -18,25 +18,6 @@ static const char CLOSE_FRAME[] = {'\x88', '\x00'}; -struct http_parsing_state_s { - http_parser parser; - http_parser_settings parser_settings; - handshake_cb callback; - bool done; - bool parsing_value; - char* ws_key; - char* path; - char* current_header; -}; - -struct ws_state_s { - uv_alloc_cb alloc_cb; - uv_read_cb read_cb; - inspector_cb close_cb; - bool close_sent; - bool received_close; -}; - enum ws_decode_result { FRAME_OK, FRAME_INCOMPLETE, FRAME_CLOSE, FRAME_ERROR }; @@ -72,11 +53,9 @@ static void dispose_inspector(uv_handle_t* handle) { reinterpret_cast(handle->data); inspector_cb close = inspector->ws_mode ? inspector->ws_state->close_cb : nullptr; - free(inspector->buffer); - free(inspector->ws_state); + inspector->buffer.clear(); + delete inspector->ws_state; inspector->ws_state = nullptr; - inspector->buffer = nullptr; - inspector->buffer_size = 0; inspector->data_len = 0; inspector->last_read_end = 0; if (close) { @@ -92,11 +71,25 @@ static void close_connection(inspector_socket_t* inspector) { } } +struct WriteRequest { + WriteRequest(inspector_socket_t* inspector, const char* data, size_t size) + : inspector(inspector) + , storage(data, data + size) + , buf(uv_buf_init(&storage[0], storage.size())) {} + + static WriteRequest* from_write_req(uv_write_t* req) { + return node::ContainerOf(&WriteRequest::req, req); + } + + inspector_socket_t* const inspector; + std::vector storage; + uv_write_t req; + uv_buf_t buf; +}; + // Cleanup static void write_request_cleanup(uv_write_t* req, int status) { - free((reinterpret_cast(req->data))->base); - free(req->data); - free(req); + delete WriteRequest::from_write_req(req); } static int write_to_client(inspector_socket_t* inspector, @@ -109,21 +102,9 @@ static int write_to_client(inspector_socket_t* inspector, #endif // Freed in write_request_cleanup - uv_buf_t* buf = reinterpret_cast(malloc(sizeof(uv_buf_t))); - uv_write_t* req = reinterpret_cast(malloc(sizeof(uv_write_t))); - CHECK_NE(buf, nullptr); - CHECK_NE(req, nullptr); - memset(req, 0, sizeof(*req)); - buf->base = reinterpret_cast(malloc(len)); - - CHECK_NE(buf->base, nullptr); - - memcpy(buf->base, msg, len); - buf->len = len; - req->data = buf; - + WriteRequest* wr = new WriteRequest(inspector, msg, len); uv_stream_t* stream = reinterpret_cast(&inspector->client); - return uv_write(req, stream, buf, 1, write_cb) < 0; + return uv_write(&wr->req, stream, &wr->buf, 1, write_cb) < 0; } // Constants for hybi-10 frame format. @@ -278,10 +259,10 @@ static void shutdown_complete(inspector_socket_t* inspector) { close_connection(inspector); } -static void on_close_frame_written(uv_write_t* write, int status) { - inspector_socket_t* inspector = - reinterpret_cast(write->handle->data); - write_request_cleanup(write, status); +static void on_close_frame_written(uv_write_t* req, int status) { + WriteRequest* wr = WriteRequest::from_write_req(req); + inspector_socket_t* inspector = wr->inspector; + delete wr; inspector->ws_state->close_sent = true; if (inspector->ws_state->received_close) { shutdown_complete(inspector); @@ -304,7 +285,7 @@ static int parse_ws_frames(inspector_socket_t* inspector, size_t len) { std::vector output; bool compressed = false; - ws_decode_result r = decode_frame_hybi17(inspector->buffer, + ws_decode_result r = decode_frame_hybi17(&inspector->buffer[0], len, true /* client_frame */, &bytes_consumed, &output, &compressed); @@ -334,16 +315,13 @@ static void prepare_buffer(uv_handle_t* stream, size_t len, uv_buf_t* buf) { inspector_socket_t* inspector = reinterpret_cast(stream->data); - if (len > (inspector->buffer_size - inspector->data_len)) { + if (len > (inspector->buffer.size() - inspector->data_len)) { int new_size = (inspector->data_len + len + BUFFER_GROWTH_CHUNK_SIZE - 1) / BUFFER_GROWTH_CHUNK_SIZE * BUFFER_GROWTH_CHUNK_SIZE; - inspector->buffer_size = new_size; - inspector->buffer = reinterpret_cast(realloc(inspector->buffer, - inspector->buffer_size)); - ASSERT_NE(inspector->buffer, nullptr); + inspector->buffer.resize(new_size); } - buf->base = inspector->buffer + inspector->data_len; + buf->base = &inspector->buffer[inspector->data_len]; buf->len = len; inspector->data_len += len; } @@ -366,10 +344,10 @@ static void websockets_data_cb(uv_stream_t* stream, ssize_t nread, #endif // 1. Move read bytes to continue the buffer // Should be same as this is supposedly last buffer - ASSERT_EQ(buf->base + buf->len, inspector->buffer + inspector->data_len); + ASSERT_EQ(buf->base + buf->len, &inspector->buffer[inspector->data_len]); // Should be noop... - memmove(inspector->buffer + inspector->last_read_end, buf->base, nread); + memmove(&inspector->buffer[inspector->last_read_end], buf->base, nread); inspector->last_read_end += nread; // 2. Parse. @@ -378,8 +356,8 @@ static void websockets_data_cb(uv_stream_t* stream, ssize_t nread, processed = parse_ws_frames(inspector, inspector->last_read_end); // 3. Fix the buffer size & length if (processed > 0) { - memmove(inspector->buffer, inspector->buffer + processed, - inspector->last_read_end - processed); + memmove(&inspector->buffer[0], &inspector->buffer[processed], + inspector->last_read_end - processed); inspector->last_read_end -= processed; inspector->data_len = inspector->last_read_end; } @@ -410,73 +388,53 @@ void inspector_read_stop(inspector_socket_t* inspector) { inspector->ws_state->read_cb = nullptr; } -static void generate_accept_string(const char* client_key, char* buffer) { +static void generate_accept_string(const std::string& client_key, + char (*buffer)[ACCEPT_KEY_LENGTH]) { // Magic string from websockets spec. - const char ws_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - size_t key_len = strlen(client_key); - size_t magic_len = sizeof(ws_magic) - 1; - - char* buf = reinterpret_cast(malloc(key_len + magic_len)); - CHECK_NE(buf, nullptr); - memcpy(buf, client_key, key_len); - memcpy(buf + key_len, ws_magic, magic_len); - char hash[20]; - SHA1((unsigned char*) buf, key_len + magic_len, (unsigned char*) hash); - free(buf); - node::base64_encode(hash, 20, buffer, ACCEPT_KEY_LENGTH); - buffer[ACCEPT_KEY_LENGTH] = '\0'; -} - -static void append(char** value, const char* string, size_t length) { - const size_t INCREMENT = 500; // There should never be more then 1 chunk... - - int current_len = *value ? strlen(*value) : 0; - int new_len = current_len + length; - int adjusted = (new_len / INCREMENT + 1) * INCREMENT; - *value = reinterpret_cast(realloc(*value, adjusted)); - memcpy(*value + current_len, string, length); - (*value)[new_len] = '\0'; + static const char ws_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + std::string input(client_key + ws_magic); + char hash[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(&input[0]), input.size(), + reinterpret_cast(hash)); + node::base64_encode(hash, sizeof(hash), *buffer, sizeof(*buffer)); } static int header_value_cb(http_parser* parser, const char* at, size_t length) { - char SEC_WEBSOCKET_KEY_HEADER[] = "Sec-WebSocket-Key"; - struct http_parsing_state_s* state = (struct http_parsing_state_s*) - (reinterpret_cast(parser->data))->http_parsing_state; + static const char SEC_WEBSOCKET_KEY_HEADER[] = "Sec-WebSocket-Key"; + auto inspector = static_cast(parser->data); + auto state = inspector->http_parsing_state; state->parsing_value = true; - if (state->current_header && - node::StringEqualNoCaseN(state->current_header, + if (state->current_header.size() == sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1 && + node::StringEqualNoCaseN(state->current_header.data(), SEC_WEBSOCKET_KEY_HEADER, - sizeof(SEC_WEBSOCKET_KEY_HEADER))) { - append(&state->ws_key, at, length); + sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1)) { + state->ws_key.append(at, length); } return 0; } static int header_field_cb(http_parser* parser, const char* at, size_t length) { - struct http_parsing_state_s* state = (struct http_parsing_state_s*) - (reinterpret_cast(parser->data))->http_parsing_state; + auto inspector = static_cast(parser->data); + auto state = inspector->http_parsing_state; if (state->parsing_value) { state->parsing_value = false; - if (state->current_header) - state->current_header[0] = '\0'; + state->current_header.clear(); } - append(&state->current_header, at, length); + state->current_header.append(at, length); return 0; } static int path_cb(http_parser* parser, const char* at, size_t length) { - struct http_parsing_state_s* state = (struct http_parsing_state_s*) - (reinterpret_cast(parser->data))->http_parsing_state; - append(&state->path, at, length); + auto inspector = static_cast(parser->data); + auto state = inspector->http_parsing_state; + state->path.append(at, length); return 0; } static void handshake_complete(inspector_socket_t* inspector) { uv_read_stop(reinterpret_cast(&inspector->client)); handshake_cb callback = inspector->http_parsing_state->callback; - inspector->ws_state = (struct ws_state_s*) malloc(sizeof(struct ws_state_s)); - ASSERT_NE(nullptr, inspector->ws_state); - memset(inspector->ws_state, 0, sizeof(struct ws_state_s)); + inspector->ws_state = new ws_state_s(); inspector->last_read_end = 0; inspector->ws_mode = true; callback(inspector, kInspectorHandshakeUpgraded, @@ -484,11 +442,7 @@ static void handshake_complete(inspector_socket_t* inspector) { } static void cleanup_http_parsing_state(inspector_socket_t* inspector) { - struct http_parsing_state_s* state = inspector->http_parsing_state; - free(state->current_header); - free(state->path); - free(state->ws_key); - free(state); + delete inspector->http_parsing_state; inspector->http_parsing_state = nullptr; } @@ -498,7 +452,7 @@ static void report_handshake_failure_cb(uv_handle_t* handle) { static_cast(handle->data); handshake_cb cb = inspector->http_parsing_state->callback; cleanup_http_parsing_state(inspector); - cb(inspector, kInspectorHandshakeFailed, nullptr); + cb(inspector, kInspectorHandshakeFailed, std::string()); } static void close_and_report_handshake_failure(inspector_socket_t* inspector) { @@ -537,29 +491,21 @@ static int message_complete_cb(http_parser* parser) { } else { handshake_failed(inspector); } - } else if (!state->ws_key) { + } else if (state->ws_key.empty()) { handshake_failed(inspector); } else if (state->callback(inspector, kInspectorHandshakeUpgrading, state->path)) { - char accept_string[ACCEPT_KEY_LENGTH + 1]; - generate_accept_string(state->ws_key, accept_string); - + char accept_string[ACCEPT_KEY_LENGTH]; + generate_accept_string(state->ws_key, &accept_string); const char accept_ws_prefix[] = "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: "; const char accept_ws_suffix[] = "\r\n\r\n"; - // Format has two chars (%s) that are replaced with actual key - char accept_response[sizeof(accept_ws_prefix) - 1 + - sizeof(accept_ws_suffix) - 1 + - ACCEPT_KEY_LENGTH]; - memcpy(accept_response, accept_ws_prefix, sizeof(accept_ws_prefix) - 1); - memcpy(accept_response + sizeof(accept_ws_prefix) - 1, - accept_string, ACCEPT_KEY_LENGTH); - memcpy(accept_response + sizeof(accept_ws_prefix) - 1 + ACCEPT_KEY_LENGTH, - accept_ws_suffix, sizeof(accept_ws_suffix) - 1); - int len = sizeof(accept_response); - if (write_to_client(inspector, accept_response, len) >= 0) { + std::string reply(accept_ws_prefix, sizeof(accept_ws_prefix) - 1); + reply.append(accept_string, sizeof(accept_string)); + reply.append(accept_ws_suffix, sizeof(accept_ws_suffix) - 1); + if (write_to_client(inspector, &reply[0], reply.size()) >= 0) { handshake_complete(inspector); inspector->http_parsing_state->done = true; } else { @@ -588,7 +534,7 @@ static void data_received_cb(uv_stream_s* client, ssize_t nread, } else { http_parsing_state_s* state = inspector->http_parsing_state; http_parser* parser = &state->parser; - http_parser_execute(parser, &state->parser_settings, inspector->buffer, + http_parser_execute(parser, &state->parser_settings, &inspector->buffer[0], nread); if (parser->http_errno != HPE_OK) { handshake_failed(inspector); @@ -603,15 +549,9 @@ static void data_received_cb(uv_stream_s* client, ssize_t nread, static void init_handshake(inspector_socket_t* inspector) { http_parsing_state_s* state = inspector->http_parsing_state; CHECK_NE(state, nullptr); - if (state->current_header) { - state->current_header[0] = '\0'; - } - if (state->ws_key) { - state->ws_key[0] = '\0'; - } - if (state->path) { - state->path[0] = '\0'; - } + state->current_header.clear(); + state->ws_key.clear(); + state->path.clear(); state->done = false; http_parser_init(&state->parser, HTTP_REQUEST); state->parser.data = inspector; @@ -626,15 +566,8 @@ static void init_handshake(inspector_socket_t* inspector) { int inspector_accept(uv_stream_t* server, inspector_socket_t* inspector, handshake_cb callback) { ASSERT_NE(callback, nullptr); - // The only field that users should care about. - void* data = inspector->data; - memset(inspector, 0, sizeof(*inspector)); - inspector->data = data; - - inspector->http_parsing_state = (struct http_parsing_state_s*) - malloc(sizeof(struct http_parsing_state_s)); - ASSERT_NE(nullptr, inspector->http_parsing_state); - memset(inspector->http_parsing_state, 0, sizeof(struct http_parsing_state_s)); + CHECK_EQ(inspector->http_parsing_state, nullptr); + inspector->http_parsing_state = new http_parsing_state_s(); uv_stream_t* client = reinterpret_cast(&inspector->client); CHECK_NE(client, nullptr); int err = uv_tcp_init(server->loop, &inspector->client); diff --git a/src/inspector_socket.h b/src/inspector_socket.h index 3e52762e715..5d3477b98c1 100644 --- a/src/inspector_socket.h +++ b/src/inspector_socket.h @@ -4,6 +4,9 @@ #include "http_parser.h" #include "uv.h" +#include +#include + enum inspector_handshake_event { kInspectorHandshakeUpgrading, kInspectorHandshakeUpgraded, @@ -19,17 +22,32 @@ typedef void (*inspector_cb)(struct inspector_socket_s*, int); // the connection. inspector_write can be used from the callback. typedef bool (*handshake_cb)(struct inspector_socket_s*, enum inspector_handshake_event state, - const char* path); + const std::string& path); + +struct http_parsing_state_s { + http_parser parser; + http_parser_settings parser_settings; + handshake_cb callback; + bool done; + bool parsing_value; + std::string ws_key; + std::string path; + std::string current_header; +}; -struct http_parsing_state_s; -struct ws_state_s; +struct ws_state_s { + uv_alloc_cb alloc_cb; + uv_read_cb read_cb; + inspector_cb close_cb; + bool close_sent; + bool received_close; +}; struct inspector_socket_s { void* data; struct http_parsing_state_s* http_parsing_state; struct ws_state_s* ws_state; - char* buffer; - size_t buffer_size; + std::vector buffer; size_t data_len; size_t last_read_end; uv_tcp_t client; diff --git a/src/node.cc b/src/node.cc index 9c5981c0b52..34edf592016 100644 --- a/src/node.cc +++ b/src/node.cc @@ -125,7 +125,6 @@ using v8::ScriptOrigin; using v8::SealHandleScope; using v8::String; using v8::TryCatch; -using v8::Uint32; using v8::Uint32Array; using v8::V8; using v8::Value; @@ -208,9 +207,11 @@ static struct { platform_ = nullptr; } - void StartInspector(Environment *env, int port, bool wait) { + bool StartInspector(Environment *env, int port, bool wait) { #if HAVE_INSPECTOR - env->inspector_agent()->Start(platform_, port, wait); + return env->inspector_agent()->Start(platform_, port, wait); +#else + return true; #endif // HAVE_INSPECTOR } @@ -219,8 +220,9 @@ static struct { void Initialize(int thread_pool_size) {} void PumpMessageLoop(Isolate* isolate) {} void Dispose() {} - void StartInspector(Environment *env, int port, bool wait) { + bool StartInspector(Environment *env, int port, bool wait) { env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0"); + return false; // make compiler happy } #endif // !NODE_USE_V8_PLATFORM } v8_platform; @@ -2463,31 +2465,43 @@ void FatalException(Isolate* isolate, Local fatal_exception_function = process_object->Get(fatal_exception_string).As(); + int exit_code = 0; if (!fatal_exception_function->IsFunction()) { // failed before the process._fatalException function was added! // this is probably pretty bad. Nothing to do but report and exit. ReportException(env, error, message); - exit(6); + exit_code = 6; } - TryCatch fatal_try_catch(isolate); + if (exit_code == 0) { + TryCatch fatal_try_catch(isolate); - // Do not call FatalException when _fatalException handler throws - fatal_try_catch.SetVerbose(false); + // Do not call FatalException when _fatalException handler throws + fatal_try_catch.SetVerbose(false); - // this will return true if the JS layer handled it, false otherwise - Local caught = - fatal_exception_function->Call(process_object, 1, &error); + // this will return true if the JS layer handled it, false otherwise + Local caught = + fatal_exception_function->Call(process_object, 1, &error); + + if (fatal_try_catch.HasCaught()) { + // the fatal exception function threw, so we must exit + ReportException(env, fatal_try_catch); + exit_code = 7; + } - if (fatal_try_catch.HasCaught()) { - // the fatal exception function threw, so we must exit - ReportException(env, fatal_try_catch); - exit(7); + if (exit_code == 0 && false == caught->BooleanValue()) { + ReportException(env, error, message); + exit_code = 1; + } } - if (false == caught->BooleanValue()) { - ReportException(env, error, message); - exit(1); + if (exit_code) { +#if HAVE_INSPECTOR + if (use_inspector) { + env->inspector_agent()->FatalException(error, message); + } +#endif + exit(exit_code); } } @@ -2718,23 +2732,18 @@ static void EnvQuery(Local property, static void EnvDeleter(Local property, const PropertyCallbackInfo& info) { - bool rc = true; #ifdef __POSIX__ node::Utf8Value key(info.GetIsolate(), property); - rc = getenv(*key) != nullptr; - if (rc) - unsetenv(*key); + unsetenv(*key); #else String::Value key(property); WCHAR* key_ptr = reinterpret_cast(*key); - if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, nullptr)) { - // Deletion failed. Return true if the key wasn't there in the first place, - // false if it is still there. - rc = GetEnvironmentVariableW(key_ptr, nullptr, 0) == 0 && - GetLastError() != ERROR_SUCCESS; - } + SetEnvironmentVariableW(key_ptr, nullptr); #endif - info.GetReturnValue().Set(rc); + + // process.env never has non-configurable properties, so always + // return true like the tc39 delete operator. + info.GetReturnValue().Set(true); } @@ -3761,8 +3770,7 @@ static void DispatchMessagesDebugAgentCallback(Environment* env) { static void StartDebug(Environment* env, bool wait) { CHECK(!debugger_running); if (use_inspector) { - v8_platform.StartInspector(env, inspector_port, wait); - debugger_running = true; + debugger_running = v8_platform.StartInspector(env, inspector_port, wait); } else { env->debugger_agent()->set_dispatch_handler( DispatchMessagesDebugAgentCallback); @@ -4401,8 +4409,12 @@ static void StartNodeInstance(void* arg) { ShouldAbortOnUncaughtException); // Start debug agent when argv has --debug - if (instance_data->use_debug_agent()) + if (instance_data->use_debug_agent()) { StartDebug(&env, debug_wait_connect); + if (use_inspector && !debugger_running) { + exit(12); + } + } { Environment::AsyncCallbackScope callback_scope(&env); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index d86968ebabf..388ee6b5692 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -95,19 +95,15 @@ using v8::ArrayBuffer; using v8::ArrayBufferCreationMode; using v8::Context; using v8::EscapableHandleScope; -using v8::Function; using v8::FunctionCallbackInfo; -using v8::HandleScope; using v8::Integer; using v8::Isolate; using v8::Local; using v8::Maybe; using v8::MaybeLocal; -using v8::Number; using v8::Object; using v8::Persistent; using v8::String; -using v8::Uint32; using v8::Uint32Array; using v8::Uint8Array; using v8::Value; diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 7ec03c10f77..091b2a5ee3f 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -23,7 +23,6 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; using v8::Integer; -using v8::Isolate; using v8::Local; using v8::Maybe; using v8::MaybeLocal; @@ -41,7 +40,6 @@ using v8::String; using v8::TryCatch; using v8::Uint8Array; using v8::UnboundScript; -using v8::V8; using v8::Value; using v8::WeakCallbackInfo; @@ -380,7 +378,19 @@ class ContextifyContext { if (ctx->context_.IsEmpty()) return; - ctx->sandbox()->Set(property, value); + bool is_declared = + ctx->global_proxy()->HasRealNamedProperty(ctx->context(), + property).FromJust(); + bool is_contextual_store = ctx->global_proxy() != args.This(); + + bool set_property_will_throw = + args.ShouldThrowOnError() && + !is_declared && + is_contextual_store; + + if (!set_property_will_throw) { + ctx->sandbox()->Set(property, value); + } } diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 2b85d1a6098..9cf216f2d60 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -83,7 +83,6 @@ using v8::PropertyAttribute; using v8::PropertyCallbackInfo; using v8::ReadOnly; using v8::String; -using v8::V8; using v8::Value; diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index 378d8f6b7db..e42c20877df 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -32,7 +32,6 @@ namespace node { using v8::FunctionCallbackInfo; -using v8::FunctionTemplate; using v8::GCCallbackFlags; using v8::GCType; using v8::HandleScope; diff --git a/src/node_file.cc b/src/node_file.cc index a51bcabba37..77d11756a2d 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -34,7 +34,6 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; using v8::Integer; -using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; @@ -49,11 +48,6 @@ using v8::Value; #define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1) -static int SanitizeFD(Local fd) { - CHECK(fd->IsUint32() && "file descriptor must be a unsigned 32-bit integer"); - return fd->Uint32Value(); -} - class FSReqWrap: public ReqWrap { public: enum Ownership { COPY, MOVE }; @@ -411,8 +405,10 @@ static void Close(const FunctionCallbackInfo& args) { if (args.Length() < 1) return TYPE_ERROR("fd is required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be a file descriptor"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { ASYNC_CALL(close, args[1], UTF8, fd) @@ -644,8 +640,10 @@ static void FStat(const FunctionCallbackInfo& args) { if (args.Length() < 1) return TYPE_ERROR("fd is required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be a file descriptor"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { ASYNC_CALL(fstat, args[1], UTF8, fd) @@ -773,10 +771,21 @@ static void FTruncate(const FunctionCallbackInfo& args) { if (args.Length() < 2) return TYPE_ERROR("fd and length are required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be a file descriptor"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); + // FIXME(bnoordhuis) It's questionable to reject non-ints here but still + // allow implicit coercion from null or undefined to zero. Probably best + // handled in lib/fs.js. Local len_v(args[1]); + if (!len_v->IsUndefined() && + !len_v->IsNull() && + !IsInt64(len_v->NumberValue())) { + return env->ThrowTypeError("Not an integer"); + } + const int64_t len = len_v->IntegerValue(); if (args[2]->IsObject()) { @@ -791,8 +800,10 @@ static void Fdatasync(const FunctionCallbackInfo& args) { if (args.Length() < 1) return TYPE_ERROR("fd is required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be a file descriptor"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { ASYNC_CALL(fdatasync, args[1], UTF8, fd) @@ -806,8 +817,10 @@ static void Fsync(const FunctionCallbackInfo& args) { if (args.Length() < 1) return TYPE_ERROR("fd is required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be a file descriptor"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); if (args[1]->IsObject()) { ASYNC_CALL(fsync, args[1], UTF8, fd) @@ -1010,8 +1023,12 @@ static void Open(const FunctionCallbackInfo& args) { static void WriteBuffer(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + if (!args[0]->IsInt32()) + return env->ThrowTypeError("First argument must be file descriptor"); + CHECK(Buffer::HasInstance(args[1])); - int fd = SanitizeFD(args[0]); + + int fd = args[0]->Int32Value(); Local obj = args[1].As(); const char* buf = Buffer::Data(obj); size_t buffer_length = Buffer::Length(obj); @@ -1053,8 +1070,10 @@ static void WriteBuffer(const FunctionCallbackInfo& args) { static void WriteBuffers(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + CHECK(args[0]->IsInt32()); CHECK(args[1]->IsArray()); - int fd = SanitizeFD(args[0]); + + int fd = args[0]->Int32Value(); Local chunks = args[1].As(); int64_t pos = GET_OFFSET(args[2]); Local req = args[3]; @@ -1091,9 +1110,12 @@ static void WriteBuffers(const FunctionCallbackInfo& args) { static void WriteString(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); + if (!args[0]->IsInt32()) + return env->ThrowTypeError("First argument must be file descriptor"); + Local req; Local string = args[1]; - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); char* buf = nullptr; int64_t pos; size_t len; @@ -1168,10 +1190,12 @@ static void Read(const FunctionCallbackInfo& args) { if (args.Length() < 2) return TYPE_ERROR("fd and buffer are required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be a file descriptor"); if (!Buffer::HasInstance(args[1])) return TYPE_ERROR("Second argument needs to be a buffer"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); Local req; @@ -1242,10 +1266,12 @@ static void FChmod(const FunctionCallbackInfo& args) { if (args.Length() < 2) return TYPE_ERROR("fd and mode are required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be a file descriptor"); if (!args[1]->IsInt32()) return TYPE_ERROR("mode must be an integer"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); int mode = static_cast(args[1]->Int32Value()); if (args[2]->IsObject()) { @@ -1301,12 +1327,14 @@ static void FChown(const FunctionCallbackInfo& args) { return TYPE_ERROR("uid required"); if (len < 3) return TYPE_ERROR("gid required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be an int"); if (!args[1]->IsUint32()) return TYPE_ERROR("uid must be an unsigned int"); if (!args[2]->IsUint32()) return TYPE_ERROR("gid must be an unsigned int"); - int fd = SanitizeFD(args[0]); + int fd = args[0]->Int32Value(); uv_uid_t uid = static_cast(args[1]->Uint32Value()); uv_gid_t gid = static_cast(args[2]->Uint32Value()); @@ -1356,12 +1384,14 @@ static void FUTimes(const FunctionCallbackInfo& args) { return TYPE_ERROR("atime required"); if (len < 3) return TYPE_ERROR("mtime required"); + if (!args[0]->IsInt32()) + return TYPE_ERROR("fd must be an int"); if (!args[1]->IsNumber()) return TYPE_ERROR("atime must be a number"); if (!args[2]->IsNumber()) return TYPE_ERROR("mtime must be a number"); - const int fd = SanitizeFD(args[0]); + const int fd = args[0]->Int32Value(); const double atime = static_cast(args[1]->NumberValue()); const double mtime = static_cast(args[2]->NumberValue()); diff --git a/src/node_util.cc b/src/node_util.cc index e60af803268..92eed3a9aec 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -113,6 +113,13 @@ void StopSigintWatchdog(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(had_pending_signals); } + +void WatchdogHasPendingSigint(const FunctionCallbackInfo& args) { + bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal(); + args.GetReturnValue().Set(ret); +} + + void Initialize(Local target, Local unused, Local context) { @@ -138,6 +145,7 @@ void Initialize(Local target, env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog); env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog); + env->SetMethod(target, "watchdogHasPendingSigint", WatchdogHasPendingSigint); } } // namespace util diff --git a/src/node_v8.cc b/src/node_v8.cc index 04da61677dc..43dd86c7574 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -10,7 +10,6 @@ namespace node { using v8::Array; using v8::ArrayBuffer; using v8::Context; -using v8::Function; using v8::FunctionCallbackInfo; using v8::HeapSpaceStatistics; using v8::HeapStatistics; diff --git a/src/node_watchdog.cc b/src/node_watchdog.cc index 9c776973a2d..756ba64696a 100644 --- a/src/node_watchdog.cc +++ b/src/node_watchdog.cc @@ -160,7 +160,7 @@ BOOL WINAPI SigintWatchdogHelper::WinCtrlCHandlerRoutine(DWORD dwCtrlType) { bool SigintWatchdogHelper::InformWatchdogsAboutSignal() { - uv_mutex_lock(&instance.list_mutex_); + Mutex::ScopedLock list_lock(instance.list_mutex_); bool is_stopping = false; #ifdef __POSIX__ @@ -176,17 +176,15 @@ bool SigintWatchdogHelper::InformWatchdogsAboutSignal() { for (auto it : instance.watchdogs_) it->HandleSigint(); - uv_mutex_unlock(&instance.list_mutex_); return is_stopping; } int SigintWatchdogHelper::Start() { - int ret = 0; - uv_mutex_lock(&mutex_); + Mutex::ScopedLock lock(mutex_); if (start_stop_count_++ > 0) { - goto dont_start; + return 0; } #ifdef __POSIX__ @@ -197,10 +195,10 @@ int SigintWatchdogHelper::Start() { sigset_t sigmask; sigfillset(&sigmask); CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask)); - ret = pthread_create(&thread_, nullptr, RunSigintWatchdog, nullptr); + int ret = pthread_create(&thread_, nullptr, RunSigintWatchdog, nullptr); CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr)); if (ret != 0) { - goto dont_start; + return ret; } has_running_thread_ = true; @@ -209,34 +207,36 @@ int SigintWatchdogHelper::Start() { SetConsoleCtrlHandler(WinCtrlCHandlerRoutine, TRUE); #endif - dont_start: - uv_mutex_unlock(&mutex_); - return ret; + return 0; } bool SigintWatchdogHelper::Stop() { - uv_mutex_lock(&mutex_); - uv_mutex_lock(&list_mutex_); + bool had_pending_signal; + Mutex::ScopedLock lock(mutex_); - bool had_pending_signal = has_pending_signal_; + { + Mutex::ScopedLock list_lock(list_mutex_); - if (--start_stop_count_ > 0) { - uv_mutex_unlock(&list_mutex_); - goto dont_stop; - } + had_pending_signal = has_pending_signal_; + + if (--start_stop_count_ > 0) { + has_pending_signal_ = false; + return had_pending_signal; + } #ifdef __POSIX__ - // Set stopping now because it's only protected by list_mutex_. - stopping_ = true; + // Set stopping now because it's only protected by list_mutex_. + stopping_ = true; #endif - watchdogs_.clear(); - uv_mutex_unlock(&list_mutex_); + watchdogs_.clear(); + } #ifdef __POSIX__ if (!has_running_thread_) { - goto dont_stop; + has_pending_signal_ = false; + return had_pending_signal; } // Wake up the helper thread. @@ -252,32 +252,33 @@ bool SigintWatchdogHelper::Stop() { #endif had_pending_signal = has_pending_signal_; - dont_stop: - uv_mutex_unlock(&mutex_); - has_pending_signal_ = false; + return had_pending_signal; } +bool SigintWatchdogHelper::HasPendingSignal() { + Mutex::ScopedLock lock(list_mutex_); + + return has_pending_signal_; +} + + void SigintWatchdogHelper::Register(SigintWatchdog* wd) { - uv_mutex_lock(&list_mutex_); + Mutex::ScopedLock lock(list_mutex_); watchdogs_.push_back(wd); - - uv_mutex_unlock(&list_mutex_); } void SigintWatchdogHelper::Unregister(SigintWatchdog* wd) { - uv_mutex_lock(&list_mutex_); + Mutex::ScopedLock lock(list_mutex_); auto it = std::find(watchdogs_.begin(), watchdogs_.end(), wd); CHECK_NE(it, watchdogs_.end()); watchdogs_.erase(it); - - uv_mutex_unlock(&list_mutex_); } @@ -289,9 +290,6 @@ SigintWatchdogHelper::SigintWatchdogHelper() stopping_ = false; CHECK_EQ(0, uv_sem_init(&sem_, 0)); #endif - - CHECK_EQ(0, uv_mutex_init(&mutex_)); - CHECK_EQ(0, uv_mutex_init(&list_mutex_)); } @@ -303,9 +301,6 @@ SigintWatchdogHelper::~SigintWatchdogHelper() { CHECK_EQ(has_running_thread_, false); uv_sem_destroy(&sem_); #endif - - uv_mutex_destroy(&mutex_); - uv_mutex_destroy(&list_mutex_); } SigintWatchdogHelper SigintWatchdogHelper::instance; diff --git a/src/node_watchdog.h b/src/node_watchdog.h index d56b7624de9..dd97e4e735c 100644 --- a/src/node_watchdog.h +++ b/src/node_watchdog.h @@ -5,6 +5,7 @@ #include "v8.h" #include "uv.h" +#include "node_mutex.h" #include #ifdef __POSIX__ @@ -62,6 +63,7 @@ class SigintWatchdogHelper { static SigintWatchdogHelper* GetInstance() { return &instance; } void Register(SigintWatchdog* watchdog); void Unregister(SigintWatchdog* watchdog); + bool HasPendingSignal(); int Start(); bool Stop(); @@ -75,8 +77,8 @@ class SigintWatchdogHelper { int start_stop_count_; - uv_mutex_t mutex_; - uv_mutex_t list_mutex_; + Mutex mutex_; + Mutex list_mutex_; std::vector watchdogs_; bool has_pending_signal_; diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 2c583298d99..09910e79eb3 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -27,7 +27,6 @@ using v8::Integer; using v8::Local; using v8::Number; using v8::Object; -using v8::String; using v8::Value; enum node_zlib_mode { @@ -54,7 +53,6 @@ class ZCtx : public AsyncWrap { public: ZCtx(Environment* env, Local wrap, node_zlib_mode mode) : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB), - chunk_size_(0), dictionary_(nullptr), dictionary_len_(0), err_(0), @@ -179,9 +177,6 @@ class ZCtx : public AsyncWrap { ctx->strm_.next_out = out; ctx->flush_ = flush; - // set this so that later on, I can easily tell how much was written. - ctx->chunk_size_ = out_len; - if (!async) { // sync version ctx->env()->PrintSyncTrace(); @@ -625,7 +620,6 @@ class ZCtx : public AsyncWrap { static const int kDeflateContextSize = 16384; // approximate static const int kInflateContextSize = 10240; // approximate - int chunk_size_; Bytef* dictionary_; size_t dictionary_len_; int err_; diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 8baf04ba7ce..8590a0dc9e0 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -8,8 +8,7 @@ #include "node.h" #include "node_buffer.h" #include "node_wrap.h" -#include "req-wrap.h" -#include "req-wrap-inl.h" +#include "connect_wrap.h" #include "stream_wrap.h" #include "util-inl.h" #include "util.h" @@ -27,30 +26,9 @@ using v8::HandleScope; using v8::Integer; using v8::Local; using v8::Object; -using v8::String; using v8::Value; -// TODO(bnoordhuis) share with TCPWrap? -class PipeConnectWrap : public ReqWrap { - public: - PipeConnectWrap(Environment* env, Local req_wrap_obj); - - size_t self_size() const override { return sizeof(*this); } -}; - - -PipeConnectWrap::PipeConnectWrap(Environment* env, Local req_wrap_obj) - : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP) { - Wrap(req_wrap_obj, this); -} - - -static void NewPipeConnectWrap(const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); -} - - Local PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) { EscapableHandleScope handle_scope(env->isolate()); CHECK_EQ(false, env->pipe_constructor_template().IsEmpty()); @@ -92,8 +70,10 @@ void PipeWrap::Initialize(Local target, env->set_pipe_constructor_template(t); // Create FunctionTemplate for PipeConnectWrap. - Local cwt = - FunctionTemplate::New(env->isolate(), NewPipeConnectWrap); + auto constructor = [](const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + }; + auto cwt = FunctionTemplate::New(env->isolate(), constructor); cwt->InstanceTemplate()->SetInternalFieldCount(1); cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap")); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"), @@ -163,7 +143,7 @@ void PipeWrap::Listen(const FunctionCallbackInfo& args) { // TODO(bnoordhuis) Maybe share this with TCPWrap? void PipeWrap::AfterConnect(uv_connect_t* req, int status) { - PipeConnectWrap* req_wrap = static_cast(req->data); + ConnectWrap* req_wrap = static_cast(req->data); PipeWrap* wrap = static_cast(req->handle->data); CHECK_EQ(req_wrap->env(), wrap->env()); Environment* env = wrap->env(); @@ -226,7 +206,8 @@ void PipeWrap::Connect(const FunctionCallbackInfo& args) { Local req_wrap_obj = args[0].As(); node::Utf8Value name(env->isolate(), args[1]); - PipeConnectWrap* req_wrap = new PipeConnectWrap(env, req_wrap_obj); + ConnectWrap* req_wrap = + new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP); uv_pipe_connect(&req_wrap->req_, &wrap->handle_, *name, diff --git a/src/process_wrap.cc b/src/process_wrap.cc index d574bf22965..3dcde0962af 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -12,7 +12,6 @@ namespace node { using v8::Array; using v8::Context; -using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc index 280c9e3eb91..582d1a9ecfd 100644 --- a/src/signal_wrap.cc +++ b/src/signal_wrap.cc @@ -10,7 +10,6 @@ namespace node { using v8::Context; -using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index f3f1d3bfdf6..17278ff83aa 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -30,7 +30,6 @@ using v8::HandleScope; using v8::Integer; using v8::Local; using v8::Object; -using v8::True; using v8::Value; diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 674c0592541..92037d0d683 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -6,8 +6,7 @@ #include "handle_wrap.h" #include "node_buffer.h" #include "node_wrap.h" -#include "req-wrap.h" -#include "req-wrap-inl.h" +#include "connect_wrap.h" #include "stream_wrap.h" #include "util.h" #include "util-inl.h" @@ -32,24 +31,6 @@ using v8::String; using v8::Value; -class TCPConnectWrap : public ReqWrap { - public: - TCPConnectWrap(Environment* env, Local req_wrap_obj); - size_t self_size() const override { return sizeof(*this); } -}; - - -TCPConnectWrap::TCPConnectWrap(Environment* env, Local req_wrap_obj) - : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP) { - Wrap(req_wrap_obj, this); -} - - -static void NewTCPConnectWrap(const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); -} - - Local TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) { EscapableHandleScope handle_scope(env->isolate()); CHECK_EQ(env->tcp_constructor_template().IsEmpty(), false); @@ -112,8 +93,10 @@ void TCPWrap::Initialize(Local target, env->set_tcp_constructor_template(t); // Create FunctionTemplate for TCPConnectWrap. - Local cwt = - FunctionTemplate::New(env->isolate(), NewTCPConnectWrap); + auto constructor = [](const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + }; + auto cwt = FunctionTemplate::New(env->isolate(), constructor); cwt->InstanceTemplate()->SetInternalFieldCount(1); cwt->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap")); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"), @@ -253,7 +236,7 @@ void TCPWrap::Listen(const FunctionCallbackInfo& args) { void TCPWrap::AfterConnect(uv_connect_t* req, int status) { - TCPConnectWrap* req_wrap = static_cast(req->data); + ConnectWrap* req_wrap = static_cast(req->data); TCPWrap* wrap = static_cast(req->handle->data); CHECK_EQ(req_wrap->env(), wrap->env()); Environment* env = wrap->env(); @@ -300,7 +283,8 @@ void TCPWrap::Connect(const FunctionCallbackInfo& args) { int err = uv_ip4_addr(*ip_address, port, &addr); if (err == 0) { - TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj); + ConnectWrap* req_wrap = + new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP); err = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, reinterpret_cast(&addr), @@ -334,7 +318,8 @@ void TCPWrap::Connect6(const FunctionCallbackInfo& args) { int err = uv_ip6_addr(*ip_address, port, &addr); if (err == 0) { - TCPConnectWrap* req_wrap = new TCPConnectWrap(env, req_wrap_obj); + ConnectWrap* req_wrap = + new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP); err = uv_tcp_connect(&req_wrap->req_, &wrap->handle_, reinterpret_cast(&addr), diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index 7f6c0029bf3..843fde4673b 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -11,7 +11,6 @@ namespace node { using v8::Context; -using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; @@ -75,8 +74,7 @@ class TimerWrap : public HandleWrap { CHECK(HandleWrap::IsAlive(wrap)); int64_t timeout = args[0]->IntegerValue(); - int64_t repeat = args[1]->IntegerValue(); - int err = uv_timer_start(&wrap->handle_, OnTimeout, timeout, repeat); + int err = uv_timer_start(&wrap->handle_, OnTimeout, timeout, 0); args.GetReturnValue().Set(err); } diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index ceb3536cd25..7c5df1105a6 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -17,7 +17,6 @@ namespace node { using crypto::SecureContext; using crypto::SSLWrap; -using v8::Boolean; using v8::Context; using v8::EscapableHandleScope; using v8::Exception; diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 319a74fd368..26f061b99b3 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -15,13 +15,11 @@ namespace node { using v8::Array; using v8::Context; -using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Integer; using v8::Local; using v8::Object; -using v8::String; using v8::Value; diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index a0d8b1f7613..1cf9678cb18 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -17,7 +17,6 @@ using v8::Array; using v8::Context; using v8::EscapableHandleScope; using v8::External; -using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; @@ -27,7 +26,6 @@ using v8::Object; using v8::PropertyAttribute; using v8::PropertyCallbackInfo; using v8::String; -using v8::Uint32; using v8::Undefined; using v8::Value; diff --git a/src/uv.cc b/src/uv.cc index 21520f5cb87..c0e742bf159 100644 --- a/src/uv.cc +++ b/src/uv.cc @@ -8,11 +8,9 @@ namespace uv { using v8::Context; using v8::FunctionCallbackInfo; -using v8::FunctionTemplate; using v8::Integer; using v8::Local; using v8::Object; -using v8::String; using v8::Value; diff --git a/test/addons/openssl-binding/binding.cc b/test/addons/openssl-binding/binding.cc index 59819cd33d2..582a94478d2 100644 --- a/test/addons/openssl-binding/binding.cc +++ b/test/addons/openssl-binding/binding.cc @@ -1,7 +1,4 @@ -#include "node.h" -#include "../../../src/util.h" -#include "../../../src/util-inl.h" - +#include #include #include diff --git a/test/addons/parse-encoding/binding.cc b/test/addons/parse-encoding/binding.cc index 062e9cb275f..0a31569e039 100644 --- a/test/addons/parse-encoding/binding.cc +++ b/test/addons/parse-encoding/binding.cc @@ -1,5 +1,5 @@ -#include "node.h" -#include "v8.h" +#include +#include namespace { diff --git a/test/cctest/test_inspector_socket.cc b/test/cctest/test_inspector_socket.cc index 7290a6e975b..6f8cd25486a 100644 --- a/test/cctest/test_inspector_socket.cc +++ b/test/cctest/test_inspector_socket.cc @@ -26,9 +26,10 @@ static enum inspector_handshake_event last_event = kInspectorHandshakeHttpGet; static uv_loop_t loop; static uv_tcp_t server, client_socket; static inspector_socket_t inspector; -static char last_path[100]; +static std::string last_path; static void (*handshake_delegate)(enum inspector_handshake_event state, - const char* path, bool* should_continue); + const std::string& path, + bool* should_continue); struct read_expects { const char* expected; @@ -50,19 +51,19 @@ static void set_timeout_flag(uv_timer_t* timer) { } static void stop_if_stop_path(enum inspector_handshake_event state, - const char* path, bool* cont) { - *cont = path == nullptr || strcmp(path, "/close") != 0; + const std::string& path, bool* cont) { + *cont = path.empty() || path != "/close"; } static bool connected_cb(inspector_socket_t* socket, enum inspector_handshake_event state, - const char* path) { + const std::string& path) { inspector_ready = state == kInspectorHandshakeUpgraded; last_event = state; - if (!path) { - strcpy(last_path, "@@@ Nothing Recieved @@@"); + if (path.empty()) { + last_path = "@@@ Nothing received @@@"; } else { - strncpy(last_path, path, sizeof(last_path) - 1); + last_path = path; } handshake_events++; bool should_continue = true; @@ -92,7 +93,7 @@ static void do_write(const char* data, int len) { } static void buffer_alloc_cb(uv_handle_t* stream, size_t len, uv_buf_t* buf) { - buf->base = static_cast(malloc(len)); + buf->base = new char[len]; buf->len = len; } @@ -113,7 +114,7 @@ static void check_data_cb(read_expects* expectation, ssize_t nread, } } GTEST_ASSERT_EQ(i, nread); - free(buf->base); + delete[] buf->base; if (expectation->pos == expectation->expected_len) { expectation->read_expected = true; *retval = true; @@ -169,7 +170,7 @@ static void expect_on_client(const char* data, size_t len) { } struct expectations { - char* actual_data; + std::string actual_data; size_t actual_offset; size_t actual_end; int err_code; @@ -181,9 +182,8 @@ static void grow_expects_buffer(uv_handle_t* stream, size_t size, uv_buf_t* b) { size_t end = expects->actual_end; // Grow the buffer in chunks of 64k. size_t new_length = (end + size + 65535) & ~((size_t) 0xFFFF); - expects->actual_data = - static_cast(realloc(expects->actual_data, new_length)); - *b = uv_buf_init(expects->actual_data + end, new_length - end); + expects->actual_data.resize(new_length); + *b = uv_buf_init(&expects->actual_data[end], new_length - end); } // static void dump_hex(const char* buf, size_t len) { @@ -224,8 +224,7 @@ static void setup_inspector_expecting() { if (inspector.data) { return; } - expectations* expects = static_cast(malloc(sizeof(*expects))); - memset(expects, 0, sizeof(*expects)); + expectations* expects = new expectations(); inspector.data = expects; inspector_read_start(&inspector, grow_expects_buffer, save_read_data); } @@ -246,8 +245,8 @@ static void expect_on_server(const char* data, size_t len) { } expects->actual_end -= expects->actual_offset; if (!expects->actual_end) { - memmove(expects->actual_data, - expects->actual_data + expects->actual_offset, + memmove(&expects->actual_data[0], + &expects->actual_data[expects->actual_offset], expects->actual_end); } expects->actual_offset = 0; @@ -288,10 +287,10 @@ static bool waiting_to_close = true; void handle_closed(uv_handle_t* handle) { waiting_to_close = false; } -static void really_close(uv_tcp_t* socket) { +static void really_close(uv_handle_t* handle) { waiting_to_close = true; - if (!uv_is_closing(reinterpret_cast(socket))) { - uv_close(reinterpret_cast(socket), handle_closed); + if (!uv_is_closing(handle)) { + uv_close(handle, handle_closed); SPIN_WHILE(waiting_to_close); } } @@ -300,10 +299,12 @@ static void really_close(uv_tcp_t* socket) { static void manual_inspector_socket_cleanup() { EXPECT_EQ(0, uv_is_active( reinterpret_cast(&inspector.client))); - free(inspector.ws_state); - free(inspector.http_parsing_state); - free(inspector.buffer); - inspector.buffer = nullptr; + really_close(reinterpret_cast(&inspector.client)); + delete inspector.ws_state; + inspector.ws_state = nullptr; + delete inspector.http_parsing_state; + inspector.http_parsing_state = nullptr; + inspector.buffer.clear(); } static void on_connection(uv_connect_t* connect, int status) { @@ -320,9 +321,9 @@ class InspectorSocketTest : public ::testing::Test { inspector_ready = false; last_event = kInspectorHandshakeHttpGet; uv_loop_init(&loop); - memset(&inspector, 0, sizeof(inspector)); - memset(&server, 0, sizeof(server)); - memset(&client_socket, 0, sizeof(client_socket)); + inspector = inspector_socket_t(); + server = uv_tcp_t(); + client_socket = uv_tcp_t(); server.data = &inspector; sockaddr_in addr; uv_timer_init(&loop, &timeout_timer); @@ -339,30 +340,24 @@ class InspectorSocketTest : public ::testing::Test { reinterpret_cast(&addr), on_connection); uv_tcp_nodelay(&client_socket, 1); // The buffering messes up the test SPIN_WHILE(!connect.data || !connected); - really_close(&server); - uv_unref(reinterpret_cast(&server)); + really_close(reinterpret_cast(&server)); } virtual void TearDown() { - really_close(&client_socket); - for (int i = 0; i < MAX_LOOP_ITERATIONS; i++) - uv_run(&loop, UV_RUN_NOWAIT); - EXPECT_EQ(nullptr, inspector.buffer); - uv_stop(&loop); - int err = uv_run(&loop, UV_RUN_ONCE); - if (err != 0) { - uv_print_active_handles(&loop, stderr); - } - EXPECT_EQ(0, err); + really_close(reinterpret_cast(&client_socket)); + really_close(reinterpret_cast(&timeout_timer)); + EXPECT_TRUE(inspector.buffer.empty()); expectations* expects = static_cast(inspector.data); if (expects != nullptr) { GTEST_ASSERT_EQ(expects->actual_end, expects->actual_offset); - free(expects->actual_data); - expects->actual_data = nullptr; - free(expects); + delete expects; inspector.data = nullptr; } - uv_loop_close(&loop); + const int err = uv_loop_close(&loop); + if (err != 0) { + uv_print_all_handles(&loop, stderr); + } + EXPECT_EQ(0, err); } }; @@ -611,10 +606,10 @@ static void send_in_chunks(const char* data, size_t len) { static const char TEST_SUCCESS[] = "Test Success\n\n"; static void ReportsHttpGet_handshake(enum inspector_handshake_event state, - const char* path, bool* cont) { + const std::string& path, bool* cont) { *cont = true; enum inspector_handshake_event expected_state = kInspectorHandshakeHttpGet; - const char* expected_path; + std::string expected_path; switch (handshake_events) { case 1: expected_path = "/some/path"; @@ -628,18 +623,16 @@ static void ReportsHttpGet_handshake(enum inspector_handshake_event state, break; case 5: expected_state = kInspectorHandshakeFailed; - expected_path = nullptr; break; case 4: expected_path = "/close"; *cont = false; break; default: - expected_path = nullptr; ASSERT_TRUE(false); } EXPECT_EQ(expected_state, state); - EXPECT_STREQ(expected_path, path); + EXPECT_EQ(expected_path, path); } TEST_F(InspectorSocketTest, ReportsHttpGet) { @@ -675,15 +668,15 @@ TEST_F(InspectorSocketTest, ReportsHttpGet) { static void HandshakeCanBeCanceled_handshake(enum inspector_handshake_event state, - const char* path, bool* cont) { + const std::string& path, bool* cont) { switch (handshake_events - 1) { case 0: EXPECT_EQ(kInspectorHandshakeUpgrading, state); - EXPECT_STREQ("/ws/path", path); + EXPECT_EQ("/ws/path", path); break; case 1: EXPECT_EQ(kInspectorHandshakeFailed, state); - EXPECT_STREQ(nullptr, path); + EXPECT_TRUE(path.empty()); break; default: EXPECT_TRUE(false); @@ -702,9 +695,9 @@ TEST_F(InspectorSocketTest, HandshakeCanBeCanceled) { } static void GetThenHandshake_handshake(enum inspector_handshake_event state, - const char* path, bool* cont) { + const std::string& path, bool* cont) { *cont = true; - const char* expected_path = "/ws/path"; + std::string expected_path = "/ws/path"; switch (handshake_events - 1) { case 0: EXPECT_EQ(kInspectorHandshakeHttpGet, state); @@ -721,7 +714,7 @@ static void GetThenHandshake_handshake(enum inspector_handshake_event state, EXPECT_TRUE(false); break; } - EXPECT_STREQ(expected_path, path); + EXPECT_EQ(expected_path, path); } TEST_F(InspectorSocketTest, GetThenHandshake) { @@ -738,8 +731,11 @@ TEST_F(InspectorSocketTest, GetThenHandshake) { manual_inspector_socket_cleanup(); } -static void WriteBeforeHandshake_close_cb(uv_handle_t* handle) { - *(static_cast(handle->data)) = true; +static void WriteBeforeHandshake_inspector_delegate(inspector_handshake_event e, + const std::string& path, + bool* cont) { + if (e == kInspectorHandshakeFailed) + inspector_closed = 1; } TEST_F(InspectorSocketTest, WriteBeforeHandshake) { @@ -750,11 +746,10 @@ TEST_F(InspectorSocketTest, WriteBeforeHandshake) { inspector_write(&inspector, MESSAGE1, sizeof(MESSAGE1) - 1); inspector_write(&inspector, MESSAGE2, sizeof(MESSAGE2) - 1); expect_on_client(EXPECTED, sizeof(EXPECTED) - 1); - bool flag = false; - client_socket.data = &flag; - uv_close(reinterpret_cast(&client_socket), - WriteBeforeHandshake_close_cb); - SPIN_WHILE(!flag); + inspector_closed = 0; + handshake_delegate = WriteBeforeHandshake_inspector_delegate; + really_close(reinterpret_cast(&client_socket)); + SPIN_WHILE(inspector_closed == 0); } static void CleanupSocketAfterEOF_close_cb(inspector_socket_t* inspector, @@ -796,19 +791,17 @@ TEST_F(InspectorSocketTest, EOFBeforeHandshake) { SPIN_WHILE(last_event != kInspectorHandshakeFailed); } -static void fill_message(char* buffer, size_t len) { - buffer[len - 1] = '\0'; - for (size_t i = 0; i < len - 1; i++) { - buffer[i] = 'a' + (i % ('z' - 'a')); +static void fill_message(std::string* buffer) { + for (size_t i = 0; i < buffer->size(); i += 1) { + (*buffer)[i] = 'a' + (i % ('z' - 'a')); } } -static void mask_message(const char* message, +static void mask_message(const std::string& message, char* buffer, const char mask[]) { const size_t mask_len = 4; - int i = 0; - while (*message != '\0') { - *buffer++ = *message++ ^ mask[i++ % mask_len]; + for (size_t i = 0; i < message.size(); i += 1) { + buffer[i] = message[i] ^ mask[i % mask_len]; } } @@ -819,25 +812,20 @@ TEST_F(InspectorSocketTest, Send1Mb) { SPIN_WHILE(!inspector_ready); expect_handshake(); - const size_t message_len = 1000000; - // 2. Brief exchange - char* message = static_cast(malloc(message_len + 1)); - fill_message(message, message_len + 1); + std::string message(1000000, '\0'); + fill_message(&message); // 1000000 is 0xF4240 hex const char EXPECTED_FRAME_HEADER[] = { '\x81', '\x7f', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0F', '\x42', '\x40' }; - char* expected = - static_cast(malloc(sizeof(EXPECTED_FRAME_HEADER) + message_len)); - - memcpy(expected, EXPECTED_FRAME_HEADER, sizeof(EXPECTED_FRAME_HEADER)); - memcpy(expected + sizeof(EXPECTED_FRAME_HEADER), message, message_len); + std::string expected(EXPECTED_FRAME_HEADER, sizeof(EXPECTED_FRAME_HEADER)); + expected.append(message); - inspector_write(&inspector, message, message_len); - expect_on_client(expected, sizeof(EXPECTED_FRAME_HEADER) + message_len); + inspector_write(&inspector, &message[0], message.size()); + expect_on_client(&expected[0], expected.size()); char MASK[4] = {'W', 'h', 'O', 'a'}; @@ -846,14 +834,13 @@ TEST_F(InspectorSocketTest, Send1Mb) { '\x42', '\x40', MASK[0], MASK[1], MASK[2], MASK[3] }; - const size_t outgoing_len = sizeof(FRAME_TO_SERVER_HEADER) + message_len; - char* outgoing = static_cast(malloc(outgoing_len)); - memcpy(outgoing, FRAME_TO_SERVER_HEADER, sizeof(FRAME_TO_SERVER_HEADER)); - mask_message(message, outgoing + sizeof(FRAME_TO_SERVER_HEADER), MASK); + std::string outgoing(FRAME_TO_SERVER_HEADER, sizeof(FRAME_TO_SERVER_HEADER)); + outgoing.resize(outgoing.size() + message.size()); + mask_message(message, &outgoing[sizeof(FRAME_TO_SERVER_HEADER)], MASK); setup_inspector_expecting(); // Buffer on the client side. - do_write(outgoing, outgoing_len); - expect_on_server(message, message_len); + do_write(&outgoing[0], outgoing.size()); + expect_on_server(&message[0], message.size()); // 3. Close const char CLIENT_CLOSE_FRAME[] = {'\x88', '\x80', '\x2D', @@ -863,9 +850,6 @@ TEST_F(InspectorSocketTest, Send1Mb) { expect_on_client(SERVER_CLOSE_FRAME, sizeof(SERVER_CLOSE_FRAME)); GTEST_ASSERT_EQ(0, uv_is_active( reinterpret_cast(&client_socket))); - free(outgoing); - free(expected); - free(message); } static ssize_t err; diff --git a/test/common.js b/test/common.js index 4748950cf61..dbbeae92978 100644 --- a/test/common.js +++ b/test/common.js @@ -9,10 +9,10 @@ const stream = require('stream'); const util = require('util'); const Timer = process.binding('timer_wrap').Timer; -const testRoot = path.resolve(process.env.NODE_TEST_DIR || - path.dirname(__filename)); +const testRoot = process.env.NODE_TEST_DIR ? + path.resolve(process.env.NODE_TEST_DIR) : __dirname; -exports.testDir = path.dirname(__filename); +exports.testDir = __dirname; exports.fixturesDir = path.join(exports.testDir, 'fixtures'); exports.libDir = path.join(exports.testDir, '../lib'); exports.tmpDirName = 'tmp'; @@ -20,7 +20,7 @@ exports.PORT = +process.env.NODE_COMMON_PORT || 12346; exports.isWindows = process.platform === 'win32'; exports.isChakraEngine = process.jsEngine === 'chakracore'; exports.isWOW64 = exports.isWindows && - (process.env['PROCESSOR_ARCHITEW6432'] !== undefined); + (process.env.PROCESSOR_ARCHITEW6432 !== undefined); exports.isAix = process.platform === 'aix'; exports.isLinuxPPCBE = (process.platform === 'linux') && (process.arch === 'ppc64') && @@ -346,6 +346,11 @@ if (global.Symbol) { knownGlobals.push(Symbol); } +function allowGlobals(...whitelist) { + knownGlobals = knownGlobals.concat(whitelist); +} +exports.allowGlobals = allowGlobals; + function leakedGlobals() { var leaked = []; diff --git a/test/fixtures/deprecated-userland-class.js b/test/fixtures/deprecated-userland-class.js new file mode 100644 index 00000000000..867bbbf2aee --- /dev/null +++ b/test/fixtures/deprecated-userland-class.js @@ -0,0 +1,12 @@ +const util = require('util'); +const assert = require('assert'); + +class deprecatedClass { +} + +const deprecated = util.deprecate(deprecatedClass, 'deprecatedClass is deprecated.'); + +const instance = new deprecated(); + +assert(instance instanceof deprecated); +assert(instance instanceof deprecatedClass); diff --git a/test/fixtures/deprecated-userland-subclass.js b/test/fixtures/deprecated-userland-subclass.js new file mode 100644 index 00000000000..2df374ad7d1 --- /dev/null +++ b/test/fixtures/deprecated-userland-subclass.js @@ -0,0 +1,19 @@ +const util = require('util'); +const assert = require('assert'); + +class deprecatedClass { +} + +const deprecated = util.deprecate(deprecatedClass, 'deprecatedClass is deprecated.'); + +class subclass extends deprecated { + constructor() { + super(); + } +} + +const instance = new subclass(); + +assert(instance instanceof subclass); +assert(instance instanceof deprecated); +assert(instance instanceof deprecatedClass); diff --git a/test/fixtures/test-fs-readfile-error.js b/test/fixtures/test-fs-readfile-error.js new file mode 100644 index 00000000000..0638d01ac76 --- /dev/null +++ b/test/fixtures/test-fs-readfile-error.js @@ -0,0 +1 @@ +require('fs').readFile('/'); // throws EISDIR diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index 88d0cb94653..80b70ecee3c 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -26,3 +26,15 @@ test-debug-signal-cluster : PASS,FLAKY [$system==aix] test-fs-watch-enoent : FAIL, PASS test-fs-watch-encoding : FAIL, PASS + +# being worked under https://github.com/nodejs/node/pull/7564 +test-async-wrap-post-did-throw : PASS, FLAKY +test-async-wrap-throw-from-callback : PASS, FLAKY +test-crypto-random : PASS, FLAKY + +#being worked under https://github.com/nodejs/node/issues/7973 +test-stdio-closed : PASS, FLAKY + +#covered by https://github.com/nodejs/node/issues/3796 +# but more frequent on AIX ? +test-debug-signal-cluster : PASS, FLAKY diff --git a/test/parallel/test-assert-typedarray-deepequal.js b/test/parallel/test-assert-typedarray-deepequal.js index a078e96f8f1..24acd81d6aa 100644 --- a/test/parallel/test-assert-typedarray-deepequal.js +++ b/test/parallel/test-assert-typedarray-deepequal.js @@ -26,7 +26,10 @@ const equalArrayPairs = [ [new Int16Array([256]), new Uint16Array([256])], [new Float32Array([+0.0]), new Float32Array([-0.0])], [new Float64Array([+0.0]), new Float32Array([-0.0])], - [new Float64Array([+0.0]), new Float64Array([-0.0])] + [new Float64Array([+0.0]), new Float64Array([-0.0])], + [new Uint8Array([1, 2, 3, 4]).subarray(1), new Uint8Array([2, 3, 4])], + [new Uint16Array([1, 2, 3, 4]).subarray(1), new Uint16Array([2, 3, 4])], + [new Uint32Array([1, 2, 3, 4]).subarray(1, 3), new Uint32Array([2, 3])] ]; const notEqualArrayPairs = [ diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index a5909934627..de1bc3d6376 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -984,7 +984,6 @@ Buffer.alloc(common.engineSpecificMessage({ v8: 3.3, chakracore: Math.trunc(3.3)})) // new Uint8Array(3.3) throws .fill().toString(); -assert.equal(Buffer.allocUnsafe(-1).length, 0); if (!common.isChakraEngine) { // Skip on chakra, new Uint8Array(NaN) throws assert.equal(Buffer.allocUnsafe(NaN).length, 0); } @@ -1484,3 +1483,21 @@ assert.equal(ubuf.buffer.byteLength, 10); assert.doesNotThrow(() => { Buffer.from(new ArrayBuffer()); }); + +assert.throws(() => Buffer.alloc(-Buffer.poolSize), + '"size" argument must not be negative'); +assert.throws(() => Buffer.alloc(-100), + '"size" argument must not be negative'); +assert.throws(() => Buffer.allocUnsafe(-Buffer.poolSize), + '"size" argument must not be negative'); +assert.throws(() => Buffer.allocUnsafe(-100), + '"size" argument must not be negative'); +assert.throws(() => Buffer.allocUnsafeSlow(-Buffer.poolSize), + '"size" argument must not be negative'); +assert.throws(() => Buffer.allocUnsafeSlow(-100), + '"size" argument must not be negative'); + +assert.throws(() => Buffer.alloc({ valueOf: () => 1 }), + /"size" argument must be a number/); +assert.throws(() => Buffer.alloc({ valueOf: () => -1 }), + /"size" argument must be a number/); diff --git a/test/parallel/test-buffer-includes.js b/test/parallel/test-buffer-includes.js index fe8f4fa69aa..22ba1e6b7e1 100644 --- a/test/parallel/test-buffer-includes.js +++ b/test/parallel/test-buffer-includes.js @@ -79,44 +79,64 @@ assert(!b.includes(Buffer.from('f'), 6)); assert(!Buffer.from('ff').includes(Buffer.from('f'), 1, 'ucs2')); // test hex encoding -assert( - Buffer.from(b.toString('hex'), 'hex') - .includes('64', 0, 'hex')); -assert( - Buffer.from(b.toString('hex'), 'hex') - .includes(Buffer.from('64', 'hex'), 0, 'hex')); +assert.strictEqual( + Buffer.from(b.toString('hex'), 'hex') + .includes('64', 0, 'hex'), + true +); +assert.strictEqual( + Buffer.from(b.toString('hex'), 'hex') + .includes(Buffer.from('64', 'hex'), 0, 'hex'), + true +); // test base64 encoding -assert( - Buffer.from(b.toString('base64'), 'base64') - .includes('ZA==', 0, 'base64')); -assert( - Buffer.from(b.toString('base64'), 'base64') - .includes(Buffer.from('ZA==', 'base64'), 0, 'base64')); +assert.strictEqual( + Buffer.from(b.toString('base64'), 'base64') + .includes('ZA==', 0, 'base64'), + true +); +assert.strictEqual( + Buffer.from(b.toString('base64'), 'base64') + .includes(Buffer.from('ZA==', 'base64'), 0, 'base64'), + true +); // test ascii encoding -assert( - Buffer.from(b.toString('ascii'), 'ascii') - .includes('d', 0, 'ascii')); -assert( - Buffer.from(b.toString('ascii'), 'ascii') - .includes(Buffer.from('d', 'ascii'), 0, 'ascii')); +assert.strictEqual( + Buffer.from(b.toString('ascii'), 'ascii') + .includes('d', 0, 'ascii'), + true +); +assert.strictEqual( + Buffer.from(b.toString('ascii'), 'ascii') + .includes(Buffer.from('d', 'ascii'), 0, 'ascii'), + true +); // test latin1 encoding -assert( - Buffer.from(b.toString('latin1'), 'latin1') - .includes('d', 0, 'latin1')); -assert( - Buffer.from(b.toString('latin1'), 'latin1') - .includes(Buffer.from('d', 'latin1'), 0, 'latin1')); +assert.strictEqual( + Buffer.from(b.toString('latin1'), 'latin1') + .includes('d', 0, 'latin1'), + true +); +assert.strictEqual( + Buffer.from(b.toString('latin1'), 'latin1') + .includes(Buffer.from('d', 'latin1'), 0, 'latin1'), + true +); // test binary encoding -assert( - Buffer.from(b.toString('binary'), 'binary') - .includes('d', 0, 'binary')); -assert( - Buffer.from(b.toString('binary'), 'binary') - .includes(Buffer.from('d', 'binary'), 0, 'binary')); +assert.strictEqual( + Buffer.from(b.toString('binary'), 'binary') + .includes('d', 0, 'binary'), + true +); +assert.strictEqual( + Buffer.from(b.toString('binary'), 'binary') + .includes(Buffer.from('d', 'binary'), 0, 'binary'), + true +); // test usc2 encoding diff --git a/test/parallel/test-buffer-indexof.js b/test/parallel/test-buffer-indexof.js index 59e969c315e..d7598d8b75c 100644 --- a/test/parallel/test-buffer-indexof.js +++ b/test/parallel/test-buffer-indexof.js @@ -79,62 +79,94 @@ assert.equal(b.indexOf(Buffer.from('f'), 6), -1); assert.equal(Buffer.from('ff').indexOf(Buffer.from('f'), 1, 'ucs2'), -1); // test hex encoding -assert.equal( - Buffer.from(b.toString('hex'), 'hex') - .indexOf('64', 0, 'hex'), 3); -assert.equal( - Buffer.from(b.toString('hex'), 'hex') - .indexOf(Buffer.from('64', 'hex'), 0, 'hex'), 3); +assert.strictEqual( + Buffer.from(b.toString('hex'), 'hex') + .indexOf('64', 0, 'hex'), + 3 +); +assert.strictEqual( + Buffer.from(b.toString('hex'), 'hex') + .indexOf(Buffer.from('64', 'hex'), 0, 'hex'), + 3 +); // test base64 encoding -assert.equal( - Buffer.from(b.toString('base64'), 'base64') - .indexOf('ZA==', 0, 'base64'), 3); -assert.equal( - Buffer.from(b.toString('base64'), 'base64') - .indexOf(Buffer.from('ZA==', 'base64'), 0, 'base64'), 3); +assert.strictEqual( + Buffer.from(b.toString('base64'), 'base64') + .indexOf('ZA==', 0, 'base64'), + 3 +); +assert.strictEqual( + Buffer.from(b.toString('base64'), 'base64') + .indexOf(Buffer.from('ZA==', 'base64'), 0, 'base64'), + 3 +); // test ascii encoding -assert.equal( - Buffer.from(b.toString('ascii'), 'ascii') - .indexOf('d', 0, 'ascii'), 3); -assert.equal( - Buffer.from(b.toString('ascii'), 'ascii') - .indexOf(Buffer.from('d', 'ascii'), 0, 'ascii'), 3); +assert.strictEqual( + Buffer.from(b.toString('ascii'), 'ascii') + .indexOf('d', 0, 'ascii'), + 3 +); +assert.strictEqual( + Buffer.from(b.toString('ascii'), 'ascii') + .indexOf(Buffer.from('d', 'ascii'), 0, 'ascii'), + 3 +); // test latin1 encoding -assert.equal( - Buffer.from(b.toString('latin1'), 'latin1') - .indexOf('d', 0, 'latin1'), 3); -assert.equal( - Buffer.from(b.toString('latin1'), 'latin1') - .indexOf(Buffer.from('d', 'latin1'), 0, 'latin1'), 3); -assert.equal( - Buffer.from('aa\u00e8aa', 'latin1') - .indexOf('\u00e8', 'latin1'), 2); -assert.equal( - Buffer.from('\u00e8', 'latin1') - .indexOf('\u00e8', 'latin1'), 0); -assert.equal( - Buffer.from('\u00e8', 'latin1') - .indexOf(Buffer.from('\u00e8', 'latin1'), 'latin1'), 0); +assert.strictEqual( + Buffer.from(b.toString('latin1'), 'latin1') + .indexOf('d', 0, 'latin1'), + 3 +); +assert.strictEqual( + Buffer.from(b.toString('latin1'), 'latin1') + .indexOf(Buffer.from('d', 'latin1'), 0, 'latin1'), + 3 +); +assert.strictEqual( + Buffer.from('aa\u00e8aa', 'latin1') + .indexOf('\u00e8', 'latin1'), + 2 +); +assert.strictEqual( + Buffer.from('\u00e8', 'latin1') + .indexOf('\u00e8', 'latin1'), + 0 +); +assert.strictEqual( + Buffer.from('\u00e8', 'latin1') + .indexOf(Buffer.from('\u00e8', 'latin1'), 'latin1'), + 0 +); // test binary encoding -assert.equal( - Buffer.from(b.toString('binary'), 'binary') - .indexOf('d', 0, 'binary'), 3); -assert.equal( - Buffer.from(b.toString('binary'), 'binary') - .indexOf(Buffer.from('d', 'binary'), 0, 'binary'), 3); -assert.equal( - Buffer.from('aa\u00e8aa', 'binary') - .indexOf('\u00e8', 'binary'), 2); -assert.equal( - Buffer.from('\u00e8', 'binary') - .indexOf('\u00e8', 'binary'), 0); -assert.equal( - Buffer.from('\u00e8', 'binary') - .indexOf(Buffer.from('\u00e8', 'binary'), 'binary'), 0); +assert.strictEqual( + Buffer.from(b.toString('binary'), 'binary') + .indexOf('d', 0, 'binary'), + 3 +); +assert.strictEqual( + Buffer.from(b.toString('binary'), 'binary') + .indexOf(Buffer.from('d', 'binary'), 0, 'binary'), + 3 +); +assert.strictEqual( + Buffer.from('aa\u00e8aa', 'binary') + .indexOf('\u00e8', 'binary'), + 2 +); +assert.strictEqual( + Buffer.from('\u00e8', 'binary') + .indexOf('\u00e8', 'binary'), + 0 +); +assert.strictEqual( + Buffer.from('\u00e8', 'binary') + .indexOf(Buffer.from('\u00e8', 'binary'), 'binary'), + 0 +); // test optional offset with passed encoding diff --git a/test/parallel/test-buffer.js b/test/parallel/test-buffer.js index 243ef89d513..e227ef5fad2 100644 --- a/test/parallel/test-buffer.js +++ b/test/parallel/test-buffer.js @@ -1005,7 +1005,6 @@ assert.equal(0, Buffer('hello').slice(0, 0).length); // Call .fill() first, stops valgrind warning about uninitialized memory reads. Buffer(3.3).fill().toString(); // throws bad argument error in commit 43cb4ec -assert.equal(Buffer(-1).length, 0); if (!common.isChakraEngine) { // Skip on chakra, new Uint8Array(NaN) throws assert.equal(Buffer(NaN).length, 0); } @@ -1493,10 +1492,10 @@ assert.equal(SlowBuffer.prototype.offset, undefined); { // Test that large negative Buffer length inputs don't affect the pool offset. - assert.deepStrictEqual(Buffer(-Buffer.poolSize), Buffer.from('')); - assert.deepStrictEqual(Buffer(-100), Buffer.from('')); - assert.deepStrictEqual(Buffer.allocUnsafe(-Buffer.poolSize), Buffer.from('')); - assert.deepStrictEqual(Buffer.allocUnsafe(-100), Buffer.from('')); + // Use the fromArrayLike() variant here because it's more lenient + // about its input and passes the length directly to allocate(). + assert.deepStrictEqual(Buffer({ length: -Buffer.poolSize }), Buffer.from('')); + assert.deepStrictEqual(Buffer({ length: -100 }), Buffer.from('')); // Check pool offset after that by trying to write string into the pool. assert.doesNotThrow(() => Buffer.from('abc')); @@ -1524,3 +1523,11 @@ assert.equal(SlowBuffer.prototype.offset, undefined); } } } + +// Test that large negative Buffer length inputs throw errors. +assert.throws(() => Buffer(-Buffer.poolSize), + '"size" argument must not be negative'); +assert.throws(() => Buffer(-100), + '"size" argument must not be negative'); +assert.throws(() => Buffer(-1), + '"size" argument must not be negative'); diff --git a/test/parallel/test-child-process-spawn-argv0.js b/test/parallel/test-child-process-spawn-argv0.js new file mode 100644 index 00000000000..593ba9e48ce --- /dev/null +++ b/test/parallel/test-child-process-spawn-argv0.js @@ -0,0 +1,18 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const cp = require('child_process'); + +// This test spawns itself with an argument to indicate when it is a child to +// easily and portably print the value of argv[0] +if (process.argv[2] === 'child') { + console.log(process.argv0); + return; +} + +const noArgv0 = cp.spawnSync(process.execPath, [__filename, 'child']); +assert.strictEqual(noArgv0.stdout.toString().trim(), process.execPath); + +const withArgv0 = cp.spawnSync(process.execPath, [__filename, 'child'], + {argv0: 'withArgv0'}); +assert.strictEqual(withArgv0.stdout.toString().trim(), 'withArgv0'); diff --git a/test/parallel/test-cluster-fork-stdio.js b/test/parallel/test-cluster-fork-stdio.js new file mode 100644 index 00000000000..1d00e0768e5 --- /dev/null +++ b/test/parallel/test-cluster-fork-stdio.js @@ -0,0 +1,40 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const cluster = require('cluster'); +const net = require('net'); + +if (cluster.isMaster) { + const buf = Buffer.from('foobar'); + + cluster.setupMaster({ + stdio: ['pipe', 'pipe', 'pipe', 'ipc', 'pipe'] + }); + + const worker = cluster.fork(); + const channel = worker.process.stdio[4]; + let response = ''; + + worker.on('exit', common.mustCall((code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + })); + + channel.setEncoding('utf8'); + channel.on('data', (data) => { + response += data; + + if (response === buf.toString()) { + worker.disconnect(); + } + }); + channel.write(buf); +} else { + const pipe = new net.Socket({ fd: 4 }); + + pipe.unref(); + pipe.on('data', (data) => { + assert.ok(data instanceof Buffer); + pipe.write(data); + }); +} diff --git a/test/parallel/test-cluster-worker-forced-exit.js b/test/parallel/test-cluster-worker-forced-exit.js index 0592cbfd01a..3e1f7905ee5 100644 --- a/test/parallel/test-cluster-worker-forced-exit.js +++ b/test/parallel/test-cluster-worker-forced-exit.js @@ -29,20 +29,16 @@ checkForced(); function checkUnforced() { cluster.fork() - .on('online', function() { - this.disconnect(); - }) - .on('exit', common.mustCall(function(status) { - assert.equal(status, SENTINEL); - })); + .on('online', function() { this.disconnect(); }) + .on('exit', common.mustCall(function(status) { + assert.strictEqual(status, SENTINEL); + })); } function checkForced() { cluster.fork() - .on('online', function() { - this.process.disconnect(); - }) - .on('exit', common.mustCall(function(status) { - assert.equal(status, 0); - })); + .on('online', function() { this.process.disconnect(); }) + .on('exit', common.mustCall(function(status) { + assert.strictEqual(status, 0); + })); } diff --git a/test/parallel/test-console-instance.js b/test/parallel/test-console-instance.js index 2a8a6e3678f..b8d98808655 100644 --- a/test/parallel/test-console-instance.js +++ b/test/parallel/test-console-instance.js @@ -64,3 +64,8 @@ out.write = function(d) { }; [1, 2, 3].forEach(c.log); assert.equal(3, called); + +// Console() detects if it is called without `new` keyword +assert.doesNotThrow(function() { + Console(out, err); +}); diff --git a/test/parallel/test-crypto-binary-default.js b/test/parallel/test-crypto-binary-default.js index e163c9e4cd6..3b360315778 100644 --- a/test/parallel/test-crypto-binary-default.js +++ b/test/parallel/test-crypto-binary-default.js @@ -324,19 +324,23 @@ var rfc2202_sha1 = [ for (let i = 0, l = rfc2202_md5.length; i < l; i++) { if (!common.hasFipsCrypto) { - assert.equal(rfc2202_md5[i]['hmac'], - crypto.createHmac('md5', rfc2202_md5[i]['key']) - .update(rfc2202_md5[i]['data']) - .digest('hex'), - 'Test HMAC-MD5 : Test case ' + (i + 1) + ' rfc 2202'); + assert.strictEqual( + rfc2202_md5[i]['hmac'], + crypto.createHmac('md5', rfc2202_md5[i]['key']) + .update(rfc2202_md5[i]['data']) + .digest('hex'), + 'Test HMAC-MD5 : Test case ' + (i + 1) + ' rfc 2202' + ); } } for (let i = 0, l = rfc2202_sha1.length; i < l; i++) { - assert.equal(rfc2202_sha1[i]['hmac'], - crypto.createHmac('sha1', rfc2202_sha1[i]['key']) - .update(rfc2202_sha1[i]['data']) - .digest('hex'), - 'Test HMAC-SHA1 : Test case ' + (i + 1) + ' rfc 2202'); + assert.strictEqual( + rfc2202_sha1[i]['hmac'], + crypto.createHmac('sha1', rfc2202_sha1[i]['key']) + .update(rfc2202_sha1[i]['data']) + .digest('hex'), + 'Test HMAC-SHA1 : Test case ' + (i + 1) + ' rfc 2202' + ); } // Test hashing diff --git a/test/parallel/test-crypto-deprecated.js b/test/parallel/test-crypto-deprecated.js index c702e9129ac..a471b192e1f 100644 --- a/test/parallel/test-crypto-deprecated.js +++ b/test/parallel/test-crypto-deprecated.js @@ -9,6 +9,11 @@ if (!common.hasCrypto) { const crypto = require('crypto'); const tls = require('tls'); +const expected = [ + 'crypto.Credentials is deprecated. Use tls.SecureContext instead.', + 'crypto.createCredentials is deprecated. Use tls.createSecureContext instead.' +]; + process.on('warning', common.mustCall((warning) => { assert.strictEqual(warning.name, 'DeprecationWarning'); assert.notStrictEqual(expected.indexOf(warning.message), -1, @@ -16,12 +21,7 @@ process.on('warning', common.mustCall((warning) => { // Remove a warning message after it is seen so that we guarantee that we get // each message only once. expected.splice(expected.indexOf(warning.message), 1); -}, 2)); - -var expected = [ - 'crypto.Credentials is deprecated. Use tls.SecureContext instead.', - 'crypto.createCredentials is deprecated. Use tls.createSecureContext instead.' -]; +}, expected.length)); // Accessing the deprecated function is enough to trigger the warning event. // It does not need to be called. So the assert serves the purpose of both diff --git a/test/parallel/test-crypto-hmac.js b/test/parallel/test-crypto-hmac.js index f377d91fd88..8c2236e6b2a 100644 --- a/test/parallel/test-crypto-hmac.js +++ b/test/parallel/test-crypto-hmac.js @@ -351,17 +351,21 @@ var rfc2202_sha1 = [ if (!common.hasFipsCrypto) { for (let i = 0, l = rfc2202_md5.length; i < l; i++) { - assert.equal(rfc2202_md5[i]['hmac'], - crypto.createHmac('md5', rfc2202_md5[i]['key']) - .update(rfc2202_md5[i]['data']) - .digest('hex'), - 'Test HMAC-MD5 : Test case ' + (i + 1) + ' rfc 2202'); + assert.strictEqual( + rfc2202_md5[i]['hmac'], + crypto.createHmac('md5', rfc2202_md5[i]['key']) + .update(rfc2202_md5[i]['data']) + .digest('hex'), + 'Test HMAC-MD5 : Test case ' + (i + 1) + ' rfc 2202' + ); } } for (let i = 0, l = rfc2202_sha1.length; i < l; i++) { - assert.equal(rfc2202_sha1[i]['hmac'], - crypto.createHmac('sha1', rfc2202_sha1[i]['key']) - .update(rfc2202_sha1[i]['data']) - .digest('hex'), - 'Test HMAC-SHA1 : Test case ' + (i + 1) + ' rfc 2202'); + assert.strictEqual( + rfc2202_sha1[i]['hmac'], + crypto.createHmac('sha1', rfc2202_sha1[i]['key']) + .update(rfc2202_sha1[i]['data']) + .digest('hex'), + 'Test HMAC-SHA1 : Test case ' + (i + 1) + ' rfc 2202' + ); } diff --git a/test/parallel/test-debug-usage.js b/test/parallel/test-debug-usage.js new file mode 100644 index 00000000000..5406a82cc8d --- /dev/null +++ b/test/parallel/test-debug-usage.js @@ -0,0 +1,21 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const spawn = require('child_process').spawn; + +const child = spawn(process.execPath, ['debug']); +child.stderr.setEncoding('utf8'); + +const expectedUsageMessage = `Usage: node debug script.js + node debug : + node debug -p +`; +var actualUsageMessage = ''; +child.stderr.on('data', function(data) { + actualUsageMessage += data.toString(); +}); + +child.on('exit', common.mustCall(function(code) { + assert.strictEqual(code, 1); + assert.strictEqual(actualUsageMessage, expectedUsageMessage); +})); diff --git a/test/parallel/test-event-emitter-listeners.js b/test/parallel/test-event-emitter-listeners.js index dfd66287b19..cfb2dafb121 100644 --- a/test/parallel/test-event-emitter-listeners.js +++ b/test/parallel/test-event-emitter-listeners.js @@ -36,3 +36,16 @@ function listener2() {} assert.deepStrictEqual(ee.listeners('foo'), [listener, listener2]); assert.deepStrictEqual(eeListenersCopy, [listener]); } + +{ + const ee = new events.EventEmitter(); + ee.once('foo', listener); + assert.deepStrictEqual(ee.listeners('foo'), [listener]); +} + +{ + const ee = new events.EventEmitter(); + ee.on('foo', listener); + ee.once('foo', listener2); + assert.deepStrictEqual(ee.listeners('foo'), [listener, listener2]); +} diff --git a/test/parallel/test-fs-chmod.js b/test/parallel/test-fs-chmod.js index 1564734ec64..954916cbdbb 100644 --- a/test/parallel/test-fs-chmod.js +++ b/test/parallel/test-fs-chmod.js @@ -101,7 +101,7 @@ fs.open(file2, 'a', function(err, fd) { assert.equal(mode_sync, fs.fstatSync(fd).mode & 0o777); } success_count++; - fs.closeSync(fd); + fs.close(fd); } }); }); diff --git a/test/parallel/test-fs-link.js b/test/parallel/test-fs-link.js index 89d4c25d5bb..2cba47bfec8 100644 --- a/test/parallel/test-fs-link.js +++ b/test/parallel/test-fs-link.js @@ -23,14 +23,14 @@ fs.link(srcPath, dstPath, common.mustCall(callback)); assert.throws( function() { - fs.link(undefined, undefined, () => {}); + fs.link(); }, /src must be a string or Buffer/ ); assert.throws( function() { - fs.link('abc', undefined, () => {}); + fs.link('abc'); }, /dest must be a string or Buffer/ ); diff --git a/test/parallel/test-fs-make-callback.js b/test/parallel/test-fs-make-callback.js index 8ded34e2b08..4fbe64437ea 100644 --- a/test/parallel/test-fs-make-callback.js +++ b/test/parallel/test-fs-make-callback.js @@ -13,6 +13,9 @@ function test(cb) { // Verify the case where a callback function is provided assert.doesNotThrow(test(function() {})); +// Passing undefined calls rethrow() internally, which is fine +assert.doesNotThrow(test(undefined)); + // Anything else should throw assert.throws(test(null)); assert.throws(test(true)); diff --git a/test/parallel/test-fs-mkdtemp.js b/test/parallel/test-fs-mkdtemp.js index 60d1196c5a5..dd4ab75c22c 100644 --- a/test/parallel/test-fs-mkdtemp.js +++ b/test/parallel/test-fs-mkdtemp.js @@ -29,3 +29,8 @@ fs.mkdtemp(path.join(common.tmpDir, 'bar.'), common.mustCall(handler)); // Same test as above, but making sure that passing an options object doesn't // affect the way the callback function is handled. fs.mkdtemp(path.join(common.tmpDir, 'bar.'), {}, common.mustCall(handler)); + +// Making sure that not passing a callback doesn't crash, as a default function +// is passed internally. +assert.doesNotThrow(() => fs.mkdtemp(path.join(common.tmpDir, 'bar-'))); +assert.doesNotThrow(() => fs.mkdtemp(path.join(common.tmpDir, 'bar-'), {})); diff --git a/test/parallel/test-fs-no-callback-errors.js b/test/parallel/test-fs-no-callback-errors.js deleted file mode 100644 index 0b2bc0d2e3f..00000000000 --- a/test/parallel/test-fs-no-callback-errors.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -require('../common'); -const fs = require('fs'); -const assert = require('assert'); - -Object.getOwnPropertyNames(fs).filter( - (d) => !d.endsWith('Stream') && // ignore stream creation functions - !d.endsWith('Sync') && // ignore synchronous functions - typeof fs[d] === 'function' && // ignore anything other than functions - d.indexOf('_') === -1 && // ignore internal use functions - !/^[A-Z]/.test(d) && // ignore conventional constructors - d !== 'watch' && // watch's callback is optional - d !== 'unwatchFile' // unwatchFile's callback is optional -).forEach( - (d) => assert.throws(() => fs[d](), /"callback" argument must be a function/) -); diff --git a/test/parallel/test-fs-read-stream.js b/test/parallel/test-fs-read-stream.js index 98a316e60e4..7b133022511 100644 --- a/test/parallel/test-fs-read-stream.js +++ b/test/parallel/test-fs-read-stream.js @@ -10,13 +10,18 @@ var rangeFile = path.join(common.fixturesDir, 'x.txt'); var callbacks = { open: 0, end: 0, close: 0 }; var paused = false; +var bytesRead = 0; var file = fs.ReadStream(fn); +var fileSize = fs.statSync(fn).size; + +assert.strictEqual(file.bytesRead, 0); file.on('open', function(fd) { file.length = 0; callbacks.open++; assert.equal('number', typeof fd); + assert.strictEqual(file.bytesRead, 0); assert.ok(file.readable); // GH-535 @@ -31,6 +36,9 @@ file.on('data', function(data) { assert.ok(!paused); file.length += data.length; + bytesRead += data.length; + assert.strictEqual(file.bytesRead, bytesRead); + paused = true; file.pause(); @@ -42,11 +50,15 @@ file.on('data', function(data) { file.on('end', function(chunk) { + assert.strictEqual(bytesRead, fileSize); + assert.strictEqual(file.bytesRead, fileSize); callbacks.end++; }); file.on('close', function() { + assert.strictEqual(bytesRead, fileSize); + assert.strictEqual(file.bytesRead, fileSize); callbacks.close++; //assert.equal(fs.readFileSync(fn), fileContent); diff --git a/test/parallel/test-fs-readfile-error.js b/test/parallel/test-fs-readfile-error.js new file mode 100644 index 00000000000..86a2be4e1bc --- /dev/null +++ b/test/parallel/test-fs-readfile-error.js @@ -0,0 +1,34 @@ +'use strict'; +var common = require('../common'); +var assert = require('assert'); +var exec = require('child_process').exec; +var path = require('path'); + +// `fs.readFile('/')` does not fail on FreeBSD, because you can open and read +// the directory there. +if (process.platform === 'freebsd') { + common.skip('platform not supported.'); + return; +} + +function test(env, cb) { + var filename = path.join(common.fixturesDir, 'test-fs-readfile-error.js'); + var execPath = '"' + process.execPath + '" "' + filename + '"'; + var options = { env: Object.assign(process.env, env) }; + exec(execPath, options, function(err, stdout, stderr) { + assert(err); + assert.equal(stdout, ''); + assert.notEqual(stderr, ''); + cb('' + stderr); + }); +} + +test({ NODE_DEBUG: '' }, common.mustCall(function(data) { + assert(/EISDIR/.test(data)); + assert(!/test-fs-readfile-error/.test(data)); +})); + +test({ NODE_DEBUG: 'fs' }, common.mustCall(function(data) { + assert(/EISDIR/.test(data)); + assert(/test-fs-readfile-error/.test(data)); +})); diff --git a/test/parallel/test-fs-realpath-buffer-encoding.js b/test/parallel/test-fs-realpath-buffer-encoding.js new file mode 100644 index 00000000000..78ec02549bb --- /dev/null +++ b/test/parallel/test-fs-realpath-buffer-encoding.js @@ -0,0 +1,88 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); + +const string_dir = fs.realpathSync(common.fixturesDir); +const buffer_dir = Buffer.from(string_dir); + +const encodings = ['ascii', 'utf8', 'utf16le', 'ucs2', + 'base64', 'binary', 'hex']; +var expected = {}; +encodings.forEach((encoding) => { + expected[encoding] = buffer_dir.toString(encoding); +}); + + +// test sync version +for (var encoding in expected) { + const expected_value = expected[encoding]; + let result; + + result = fs.realpathSync(string_dir, {encoding: encoding}); + assert.strictEqual(result, expected_value); + + result = fs.realpathSync(string_dir, encoding); + assert.strictEqual(result, expected_value); + + result = fs.realpathSync(buffer_dir, {encoding: encoding}); + assert.strictEqual(result, expected_value); + + result = fs.realpathSync(buffer_dir, encoding); + assert.strictEqual(result, expected_value); +} + +let buffer_result; +buffer_result = fs.realpathSync(string_dir, {encoding: 'buffer'}); +assert.deepStrictEqual(buffer_result, buffer_dir); + +buffer_result = fs.realpathSync(string_dir, 'buffer'); +assert.deepStrictEqual(buffer_result, buffer_dir); + +buffer_result = fs.realpathSync(buffer_dir, {encoding: 'buffer'}); +assert.deepStrictEqual(buffer_result, buffer_dir); + +buffer_result = fs.realpathSync(buffer_dir, 'buffer'); +assert.deepStrictEqual(buffer_result, buffer_dir); + +// test async version +for (encoding in expected) { + const expected_value = expected[encoding]; + + fs.realpath(string_dir, {encoding: encoding}, common.mustCall((err, res) => { + assert(!err); + assert.strictEqual(res, expected_value); + })); + fs.realpath(string_dir, encoding, common.mustCall((err, res) => { + assert(!err); + assert.strictEqual(res, expected_value); + })); + fs.realpath(buffer_dir, {encoding: encoding}, common.mustCall((err, res) => { + assert(!err); + assert.strictEqual(res, expected_value); + })); + fs.realpath(buffer_dir, encoding, common.mustCall((err, res) => { + assert(!err); + assert.strictEqual(res, expected_value); + })); +} + +fs.realpath(string_dir, {encoding: 'buffer'}, common.mustCall((err, res) => { + assert(!err); + assert.deepStrictEqual(res, buffer_dir); +})); + +fs.realpath(string_dir, 'buffer', common.mustCall((err, res) => { + assert(!err); + assert.deepStrictEqual(res, buffer_dir); +})); + +fs.realpath(buffer_dir, {encoding: 'buffer'}, common.mustCall((err, res) => { + assert(!err); + assert.deepStrictEqual(res, buffer_dir); +})); + +fs.realpath(buffer_dir, 'buffer', common.mustCall((err, res) => { + assert(!err); + assert.deepStrictEqual(res, buffer_dir); +})); diff --git a/test/parallel/test-fs-realpath-on-substed-drive.js b/test/parallel/test-fs-realpath-on-substed-drive.js new file mode 100644 index 00000000000..c9109362691 --- /dev/null +++ b/test/parallel/test-fs-realpath-on-substed-drive.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const spawnSync = require('child_process').spawnSync; + +if (!common.isWindows) { + common.skip('Test for Windows only'); + return; +} +let result; + +// create a subst drive +const driveLetters = 'ABCDEFGHIJKLMNOPQRSTUWXYZ'; +let drive; +for (var i = 0; i < driveLetters.length; ++i) { + drive = `${driveLetters[i]}:`; + result = spawnSync('subst', [drive, common.fixturesDir]); + if (result.status === 0) + break; +} +if (i === driveLetters.length) { + common.skip('Cannot create subst drive'); + return; +} + +// schedule cleanup (and check if all callbacks where called) +process.on('exit', function() { + spawnSync('subst', ['/d', drive]); +}); + +// test: +const filename = `${drive}\\empty.js`; +const filenameBuffer = Buffer.from(filename); + +result = fs.realpathSync(filename); +assert.strictEqual(result, filename); + +result = fs.realpathSync(filename, 'buffer'); +assert(Buffer.isBuffer(result)); +assert(result.equals(filenameBuffer)); + +fs.realpath(filename, common.mustCall(function(err, result) { + assert(!err); + assert.strictEqual(result, filename); +})); + +fs.realpath(filename, 'buffer', common.mustCall(function(err, result) { + assert(!err); + assert(Buffer.isBuffer(result)); + assert(result.equals(filenameBuffer)); +})); diff --git a/test/parallel/test-fs-stat.js b/test/parallel/test-fs-stat.js index 081ace714be..ac68a9ae42c 100644 --- a/test/parallel/test-fs-stat.js +++ b/test/parallel/test-fs-stat.js @@ -28,7 +28,7 @@ fs.open('.', 'r', undefined, common.mustCall(function(err, fd) { fs.fstat(fd, common.mustCall(function(err, stats) { assert.ifError(err); assert.ok(stats.mtime instanceof Date); - fs.closeSync(fd); + fs.close(fd); assert(this === global); })); @@ -47,7 +47,7 @@ fs.open('.', 'r', undefined, common.mustCall(function(err, fd) { console.dir(stats); assert.ok(stats.mtime instanceof Date); } - fs.closeSync(fd); + fs.close(fd); })); console.log(`stating: ${__filename}`); diff --git a/test/parallel/test-fs-truncate-fd.js b/test/parallel/test-fs-truncate-fd.js index 29b03284a22..2514b80f098 100644 --- a/test/parallel/test-fs-truncate-fd.js +++ b/test/parallel/test-fs-truncate-fd.js @@ -1,71 +1,21 @@ 'use strict'; -const common = require('../common'); -const assert = require('assert'); -const fs = require('fs'); -const path = require('path'); - +var common = require('../common'); +var assert = require('assert'); +var path = require('path'); +var fs = require('fs'); +var tmp = common.tmpDir; common.refreshTmpDir(); -const fds = []; +var filename = path.resolve(tmp, 'truncate-file.txt'); -const filename = path.resolve(common.tmpDir, 'truncate-file.txt'); fs.writeFileSync(filename, 'hello world', 'utf8'); -const fd = fs.openSync(filename, 'r+'); -fds.push(fd); +var fd = fs.openSync(filename, 'r+'); fs.truncate(fd, 5, common.mustCall(function(err) { - assert.ifError(err); + assert.ok(!err); assert.equal(fs.readFileSync(filename, 'utf8'), 'hello'); })); -{ - // test partial truncation of a file - const fileName = path.resolve(common.tmpDir, 'truncate-file-1.txt'); - console.log(fileName); - fs.writeFileSync(fileName, 'hello world', 'utf8'); - const fd = fs.openSync(fileName, 'r+'); - fds.push(fd); - - fs.truncate(fd, 5, common.mustCall(function(err) { - assert.ifError(err); - assert.strictEqual(fs.readFileSync(fileName, 'utf8'), 'hello'); - })); -} - -{ - // make sure numbers as strings are not treated as fds with sync version - const fileName = path.resolve(common.tmpDir, 'truncate-file-2.txt'); - console.log(fileName); - fs.writeFileSync(fileName, 'One'); - const fd = fs.openSync(fileName, 'r'); - fds.push(fd); - - const fdFileName = path.resolve(common.tmpDir, '' + fd); - fs.writeFileSync(fdFileName, 'Two'); - assert.strictEqual(fs.readFileSync(fileName).toString(), 'One'); - assert.strictEqual(fs.readFileSync(fdFileName).toString(), 'Two'); - - fs.truncateSync(fdFileName); - assert.strictEqual(fs.readFileSync(fileName).toString(), 'One'); - assert.strictEqual(fs.readFileSync(fdFileName).toString(), ''); -} - -{ - // make sure numbers as strings are not treated as fds with async version - const fileName = path.resolve(common.tmpDir, 'truncate-file-3.txt'); - console.log(fileName); - fs.writeFileSync(fileName, 'One'); - const fd = fs.openSync(fileName, 'r'); - fds.push(fd); - - const fdFileName = path.resolve(common.tmpDir, '' + fd); - fs.writeFileSync(fdFileName, 'Two'); - assert.strictEqual(fs.readFileSync(fileName).toString(), 'One'); - assert.strictEqual(fs.readFileSync(fdFileName).toString(), 'Two'); - - fs.truncate(fdFileName, common.mustCall(function(err) { - assert.ifError(err); - assert.strictEqual(fs.readFileSync(fileName).toString(), 'One'); - assert.strictEqual(fs.readFileSync(fdFileName).toString(), ''); - })); -} - -process.on('exit', () => fds.forEach((fd) => fs.closeSync(fd))); +process.on('exit', function() { + fs.closeSync(fd); + fs.unlinkSync(filename); + console.log('ok'); +}); diff --git a/test/parallel/test-fs-truncate.js b/test/parallel/test-fs-truncate.js index be986937b31..ab0148a2461 100644 --- a/test/parallel/test-fs-truncate.js +++ b/test/parallel/test-fs-truncate.js @@ -24,55 +24,6 @@ fs.truncateSync(filename); stat = fs.statSync(filename); assert.equal(stat.size, 0); -// path must be a string -assert.throws(function() { - fs.truncateSync({}); -}, /path must be a string/); - -assert.throws(function() { - fs.truncateSync([]); -}, /path must be a string/); - -// Even invalid file descriptors are not allowed -assert.throws(function() { - fs.truncateSync(-1); -}, /path must be a string/); - -assert.throws(function() { - fs.truncateSync(NaN); -}, /path must be a string/); - -assert.throws(function() { - fs.truncateSync(Infinity); -}, /path must be a string/); - -// Invalid lengths will also fail -assert.throws(function() { - fs.truncateSync('', ''); -}, /length must be a positive integer/); - -assert.throws(function() { - fs.truncateSync('', -1); -}, /length must be a positive integer/); - -assert.throws(function() { - fs.truncateSync('', NaN); -}, /length must be a positive integer/); - -assert.throws(function() { - fs.truncateSync('', Infinity); -}, /length must be a positive integer/); - -// null is a special case which will also be treated as zero length -fs.writeFileSync(filename, data); - -stat = fs.statSync(filename); -assert.equal(stat.size, 1024 * 16); - -fs.truncateSync(filename, null); -stat = fs.statSync(filename); -assert.equal(stat.size, 0); - // ftruncateSync fs.writeFileSync(filename, data); var fd = fs.openSync(filename, 'r+'); @@ -90,51 +41,6 @@ assert.equal(stat.size, 0); fs.closeSync(fd); -// file descriptor must be a unsigned 32-bit integer -assert.throws(function() { - fs.ftruncateSync({}); -}, /file descriptor must be a unsigned 32-bit integer/); - -// Even invalid file descriptors are not allowed -assert.throws(function() { - fs.ftruncateSync(-1); -}, /file descriptor must be a unsigned 32-bit integer/); - -assert.throws(function() { - fs.ftruncateSync(NaN); -}, /file descriptor must be a unsigned 32-bit integer/); - -assert.throws(function() { - fs.ftruncateSync(Infinity); -}, /file descriptor must be a unsigned 32-bit integer/); - -// Invalid lengths will also fail -assert.throws(function() { - fs.ftruncateSync(1, ''); -}, /length must be a positive integer/); - -assert.throws(function() { - fs.ftruncateSync(1, -1); -}, /length must be a positive integer/); - -assert.throws(function() { - fs.ftruncateSync(1, NaN); -}, /length must be a positive integer/); - -assert.throws(function() { - fs.ftruncateSync(1, Infinity); -}, /length must be a positive integer/); - -// null is a special case which will also be treated as zero length -fs.writeFileSync(filename, data); -fd = fs.openSync(filename, 'r+'); - -fs.ftruncateSync(fd, null); -stat = fs.statSync(filename); -assert.equal(stat.size, 0); - -fs.closeSync(fd); - // async tests testTruncate(common.mustCall(function(er) { if (er) throw er; diff --git a/test/parallel/test-fs-utimes.js b/test/parallel/test-fs-utimes.js index eecc56ee4d4..f245a7962da 100644 --- a/test/parallel/test-fs-utimes.js +++ b/test/parallel/test-fs-utimes.js @@ -76,6 +76,15 @@ function runTest(atime, mtime, callback) { } expect_errno('utimesSync', 'foobarbaz', err, 'ENOENT'); tests_run++; + + err = undefined; + try { + fs.futimesSync(-1, atime, mtime); + } catch (ex) { + err = ex; + } + expect_errno('futimesSync', -1, err, 'EBADF'); + tests_run++; } // @@ -96,8 +105,13 @@ function runTest(atime, mtime, callback) { fs.futimes(fd, atime, mtime, function(err) { expect_ok('futimes', fd, err, atime, mtime); - syncTests(); - callback(); + + fs.futimes(-1, atime, mtime, function(err) { + expect_errno('futimes', -1, err, 'EBADF'); + syncTests(); + callback(); + }); + tests_run++; }); tests_run++; }); @@ -123,56 +137,6 @@ runTest(new Date('1982-09-10 13:37'), new Date('1982-09-10 13:37'), function() { }); }); -// validate if the file descriptors are in the valid range -assert.throws(() => fs.futimes(-1, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(-1), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes('-1', () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync('-1'), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes(0xFFFFFFFF + 1, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(0xFFFFFFFF + 1), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes('0x100000000', () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync('0x100000000'), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -// invalid file descriptors also should throw -assert.throws(() => fs.futimes(null, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(null), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes(undefined, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(undefined), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes(NaN, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(NaN), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes({}, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync({}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes([], () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync([]), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes(() => true, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(() => true), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes(() => /RegEx/, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(() => /RegEx/), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimes(() => 3.14, () => {}), - /TypeError: file descriptor must be a unsigned 32-bit integer/); -assert.throws(() => fs.futimesSync(() => 3.14), - /TypeError: file descriptor must be a unsigned 32-bit integer/); process.on('exit', function() { console.log('Tests run / ok:', tests_run, '/', tests_ok); diff --git a/test/parallel/test-fs-watchfile.js b/test/parallel/test-fs-watchfile.js index 270bf270d7f..d30261859c3 100644 --- a/test/parallel/test-fs-watchfile.js +++ b/test/parallel/test-fs-watchfile.js @@ -8,11 +8,11 @@ const assert = require('assert'); // Basic usage tests. assert.throws(function() { fs.watchFile('./some-file'); -}, /"callback" argument must be a function/); +}, /"watchFile\(\)" requires a listener function/); assert.throws(function() { fs.watchFile('./another-file', {}, 'bad listener'); -}, /"callback" argument must be a function/); +}, /"watchFile\(\)" requires a listener function/); assert.throws(function() { fs.watchFile(new Object(), function() {}); diff --git a/test/parallel/test-fs-write-no-fd.js b/test/parallel/test-fs-write-no-fd.js index eb59e46a833..0aaec4b7333 100644 --- a/test/parallel/test-fs-write-no-fd.js +++ b/test/parallel/test-fs-write-no-fd.js @@ -1,13 +1,12 @@ 'use strict'; - require('../common'); const fs = require('fs'); const assert = require('assert'); assert.throws(function() { - fs.write(null, Buffer.allocUnsafe(1), 0, 1, () => {}); -}, /TypeError: file descriptor must be a unsigned 32-bit integer/); + fs.write(null, Buffer.allocUnsafe(1), 0, 1); +}, /TypeError/); assert.throws(function() { - fs.write(undefined, '1', 0, 1, () => {}); -}, /TypeError: file descriptor must be a unsigned 32-bit integer/); + fs.write(null, '1', 0, 1); +}, /TypeError/); diff --git a/test/parallel/test-http-outgoing-proto.js b/test/parallel/test-http-outgoing-proto.js new file mode 100644 index 00000000000..738e1d2c8cf --- /dev/null +++ b/test/parallel/test-http-outgoing-proto.js @@ -0,0 +1,14 @@ +'use strict'; +require('../common'); +const assert = require('assert'); + +const http = require('http'); +const OutgoingMessage = http.OutgoingMessage; +const ClientRequest = http.ClientRequest; +const ServerResponse = http.ServerResponse; + +assert.throws(OutgoingMessage.prototype._implicitHeader); +assert.strictEqual( + typeof ClientRequest.prototype._implicitHeader, 'function'); +assert.strictEqual( + typeof ServerResponse.prototype._implicitHeader, 'function'); diff --git a/test/parallel/test-module-nodemodulepaths.js b/test/parallel/test-module-nodemodulepaths.js index 0c70de9f285..02ea79b49e1 100644 --- a/test/parallel/test-module-nodemodulepaths.js +++ b/test/parallel/test-module-nodemodulepaths.js @@ -1,20 +1,105 @@ 'use strict'; -var common = require('../common'); -var assert = require('assert'); -var module = require('module'); +const common = require('../common'); +const assert = require('assert'); +const _module = require('module'); -var file, delimiter, paths; +const cases = { + 'WIN': [{ + file: 'C:\\Users\\hefangshi\\AppData\\Roaming\ +\\npm\\node_modules\\npm\\node_modules\\minimatch', + expect: [ + 'C:\\Users\\hefangshi\\AppData\\Roaming\ +\\npm\\node_modules\\npm\\node_modules\\minimatch\\node_modules', + 'C:\\Users\\hefangshi\\AppData\\Roaming\ +\\npm\\node_modules\\npm\\node_modules', + 'C:\\Users\\hefangshi\\AppData\\Roaming\\npm\\node_modules', + 'C:\\Users\\hefangshi\\AppData\\Roaming\\node_modules', + 'C:\\Users\\hefangshi\\AppData\\node_modules', + 'C:\\Users\\hefangshi\\node_modules', + 'C:\\Users\\node_modules', + 'C:\\node_modules' + ] + }, { + file: 'C:\\Users\\Rocko Artischocko\\node_stuff\\foo', + expect: [ + 'C:\\Users\\Rocko Artischocko\\node_stuff\\foo\\node_modules', + 'C:\\Users\\Rocko Artischocko\\node_stuff\\node_modules', + 'C:\\Users\\Rocko Artischocko\\node_modules', + 'C:\\Users\\node_modules', + 'C:\\node_modules' + ] + }, { + file: 'C:\\Users\\Rocko Artischocko\\node_stuff\\foo_node_modules', + expect: [ + 'C:\\Users\\Rocko \ +Artischocko\\node_stuff\\foo_node_modules\\node_modules', + 'C:\\Users\\Rocko Artischocko\\node_stuff\\node_modules', + 'C:\\Users\\Rocko Artischocko\\node_modules', + 'C:\\Users\\node_modules', + 'C:\\node_modules' + ] + }, { + file: 'C:\\node_modules', + expect: [ + 'C:\\node_modules' + ] + }, { + file: 'C:\\', + expect: [ + 'C:\\node_modules' + ] + }], + 'POSIX': [{ + file: '/usr/lib/node_modules/npm/node_modules/\ +node-gyp/node_modules/glob/node_modules/minimatch', + expect: [ + '/usr/lib/node_modules/npm/node_modules/\ +node-gyp/node_modules/glob/node_modules/minimatch/node_modules', + '/usr/lib/node_modules/npm/node_modules/\ +node-gyp/node_modules/glob/node_modules', + '/usr/lib/node_modules/npm/node_modules/node-gyp/node_modules', + '/usr/lib/node_modules/npm/node_modules', + '/usr/lib/node_modules', + '/usr/node_modules', + '/node_modules' + ] + }, { + file: '/usr/test/lib/node_modules/npm/foo', + expect: [ + '/usr/test/lib/node_modules/npm/foo/node_modules', + '/usr/test/lib/node_modules/npm/node_modules', + '/usr/test/lib/node_modules', + '/usr/test/node_modules', + '/usr/node_modules', + '/node_modules' + ] + }, { + file: '/usr/test/lib/node_modules/npm/foo_node_modules', + expect: [ + '/usr/test/lib/node_modules/npm/foo_node_modules/node_modules', + '/usr/test/lib/node_modules/npm/node_modules', + '/usr/test/lib/node_modules', + '/usr/test/node_modules', + '/usr/node_modules', + '/node_modules' + ] + }, { + file: '/node_modules', + expect: [ + '/node_modules' + ] + }, { + file: '/', + expect: [ + '/node_modules' + ] + }] +}; -if (common.isWindows) { - file = 'C:\\Users\\Rocko Artischocko\\node_stuff\\foo'; - delimiter = '\\'; -} else { - file = '/usr/test/lib/node_modules/npm/foo'; - delimiter = '/'; -} - -paths = module._nodeModulePaths(file); - -assert.ok(paths.indexOf(file + delimiter + 'node_modules') !== -1); -assert.ok(Array.isArray(paths)); +const platformCases = common.isWindows ? cases.WIN : cases.POSIX; +platformCases.forEach((c) => { + const paths = _module._nodeModulePaths(c.file); + assert.deepStrictEqual(c.expect, paths, 'case ' + c.file + + ' failed, actual paths is ' + JSON.stringify(paths)); +}); diff --git a/test/parallel/test-net-reconnect-error.js b/test/parallel/test-net-reconnect-error.js index ed889829ec8..4e322bd09d2 100644 --- a/test/parallel/test-net-reconnect-error.js +++ b/test/parallel/test-net-reconnect-error.js @@ -2,7 +2,7 @@ var common = require('../common'); var net = require('net'); var assert = require('assert'); -var N = 50; +var N = 20; var client_error_count = 0; var disconnect_count = 0; diff --git a/test/parallel/test-net-server-max-connections-close-makes-more-available.js b/test/parallel/test-net-server-max-connections-close-makes-more-available.js index 2f8bee1a8d6..fb9831d05b3 100644 --- a/test/parallel/test-net-server-max-connections-close-makes-more-available.js +++ b/test/parallel/test-net-server-max-connections-close-makes-more-available.js @@ -69,12 +69,12 @@ server.maxConnections = 1; server.listen(0, function() { createConnection(0) - .then(createConnection.bind(null, 1)) - .then(closeConnection.bind(null, 0)) - .then(createConnection.bind(null, 2)) - .then(createConnection.bind(null, 3)) - .then(server.close.bind(server)) - .then(closeConnection.bind(null, 2)); + .then(createConnection.bind(null, 1)) + .then(closeConnection.bind(null, 0)) + .then(createConnection.bind(null, 2)) + .then(createConnection.bind(null, 3)) + .then(server.close.bind(server)) + .then(closeConnection.bind(null, 2)); }); process.on('exit', function() { diff --git a/test/parallel/test-preload.js b/test/parallel/test-preload.js index b30494cd92b..386cdd79abb 100644 --- a/test/parallel/test-preload.js +++ b/test/parallel/test-preload.js @@ -129,7 +129,7 @@ const interactive = childProcess.exec(nodeBinary + ' ' + '-i', common.mustCall(function(err, stdout, stderr) { assert.ifError(err); - assert.strictEqual(stdout, `> 'test'\n> `); + assert.strictEqual(stdout, `> 'test'\r\n> `); })); interactive.stdin.write('a\n'); diff --git a/test/parallel/test-process-env.js b/test/parallel/test-process-env.js index 33a1d9674ea..52f6de9278f 100644 --- a/test/parallel/test-process-env.js +++ b/test/parallel/test-process-env.js @@ -2,11 +2,8 @@ /* eslint-disable max-len */ require('../common'); -// first things first, set the timezone; see tzset(3) -process.env.TZ = 'Europe/Amsterdam'; - -var assert = require('assert'); -var spawn = require('child_process').spawn; +const assert = require('assert'); +const spawn = require('child_process').spawn; /* For the moment we are not going to support setting the timezone via the * environment variables. The problem is that various V8 platform backends @@ -16,6 +13,8 @@ var spawn = require('child_process').spawn; https://github.com/joyent/node/blob/08782931205bc4f6d28102ebc29fd806e8ccdf1f/deps/v8/src/platform-linux.cc#L339-345 https://github.com/joyent/node/blob/08782931205bc4f6d28102ebc29fd806e8ccdf1f/deps/v8/src/platform-win32.cc#L590-596 +// first things first, set the timezone; see tzset(3) +process.env.TZ = 'Europe/Amsterdam'; // time difference between Greenwich and Amsterdam is +2 hours in the summer date = new Date('Fri, 10 Sep 1982 03:15:00 GMT'); @@ -27,28 +26,28 @@ assert.equal(5, date.getHours()); // changes in environment should be visible to child processes if (process.argv[2] == 'you-are-the-child') { // failed assertion results in process exiting with status code 1 - assert.equal(false, 'NODE_PROCESS_ENV_DELETED' in process.env); - assert.equal(42, process.env.NODE_PROCESS_ENV); - assert.equal('asdf', process.env.hasOwnProperty); + assert.strictEqual(false, 'NODE_PROCESS_ENV_DELETED' in process.env); + assert.strictEqual('42', process.env.NODE_PROCESS_ENV); + assert.strictEqual('asdf', process.env.hasOwnProperty); var hasOwnProperty = Object.prototype.hasOwnProperty; const has = hasOwnProperty.call(process.env, 'hasOwnProperty'); - assert.equal(true, has); + assert.strictEqual(true, has); process.exit(0); } else { - assert.equal(Object.prototype.hasOwnProperty, process.env.hasOwnProperty); + assert.strictEqual(Object.prototype.hasOwnProperty, process.env.hasOwnProperty); const has = process.env.hasOwnProperty('hasOwnProperty'); - assert.equal(false, has); + assert.strictEqual(false, has); process.env.hasOwnProperty = 'asdf'; process.env.NODE_PROCESS_ENV = 42; - assert.equal(42, process.env.NODE_PROCESS_ENV); + assert.strictEqual('42', process.env.NODE_PROCESS_ENV); process.env.NODE_PROCESS_ENV_DELETED = 42; - assert.equal(true, 'NODE_PROCESS_ENV_DELETED' in process.env); + assert.strictEqual(true, 'NODE_PROCESS_ENV_DELETED' in process.env); delete process.env.NODE_PROCESS_ENV_DELETED; - assert.equal(false, 'NODE_PROCESS_ENV_DELETED' in process.env); + assert.strictEqual(false, 'NODE_PROCESS_ENV_DELETED' in process.env); var child = spawn(process.argv[0], [process.argv[1], 'you-are-the-child']); child.stdout.on('data', function(data) { console.log(data.toString()); }); @@ -59,3 +58,8 @@ if (process.argv[2] == 'you-are-the-child') { } }); } + +// delete should return true except for non-configurable properties +// https://github.com/nodejs/node/issues/7960 +delete process.env.NON_EXISTING_VARIABLE; +assert.strictEqual(true, delete process.env.NON_EXISTING_VARIABLE); diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index b09870b0dd7..4a4b2f89696 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -346,14 +346,22 @@ function isWarned(emitter) { assert.equal(internalReadline.getStringWidth('A\ud83c\ude00BC'), 5); // check if vt control chars are stripped - assert.equal(internalReadline - .stripVTControlCharacters('\u001b[31m> \u001b[39m'), '> '); - assert.equal(internalReadline - .stripVTControlCharacters('\u001b[31m> \u001b[39m> '), '> > '); - assert.equal(internalReadline - .stripVTControlCharacters('\u001b[31m\u001b[39m'), ''); - assert.equal(internalReadline - .stripVTControlCharacters('> '), '> '); + assert.strictEqual( + internalReadline.stripVTControlCharacters('\u001b[31m> \u001b[39m'), + '> ' + ); + assert.strictEqual( + internalReadline.stripVTControlCharacters('\u001b[31m> \u001b[39m> '), + '> > ' + ); + assert.strictEqual( + internalReadline.stripVTControlCharacters('\u001b[31m\u001b[39m'), + '' + ); + assert.strictEqual( + internalReadline.stripVTControlCharacters('> '), + '> ' + ); assert.equal(internalReadline.getStringWidth('\u001b[31m> \u001b[39m'), 2); assert.equal(internalReadline.getStringWidth('\u001b[31m> \u001b[39m> '), 4); assert.equal(internalReadline.getStringWidth('\u001b[31m\u001b[39m'), 0); diff --git a/test/parallel/test-readline-undefined-columns.js b/test/parallel/test-readline-undefined-columns.js index f3197ff59a9..5f8a1c02d3a 100644 --- a/test/parallel/test-readline-undefined-columns.js +++ b/test/parallel/test-readline-undefined-columns.js @@ -1,6 +1,6 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const PassThrough = require('stream').PassThrough; const readline = require('readline'); @@ -26,12 +26,17 @@ oStream.on('data', function(data) { output += data; }); -oStream.on('end', function() { +oStream.on('end', common.mustCall(() => { const expect = 'process.stdout\r\n' + 'process.stdin\r\n' + 'process.stderr'; assert(new RegExp(expect).test(output)); -}); +})); + +iStream.write('process.s\t'); + +assert(/process.std\b/.test(output)); // Completion works. +assert(!/stdout/.test(output)); // Completion doesn’t show all results yet. -iStream.write('process.std\t'); +iStream.write('\t'); oStream.end(); diff --git a/test/parallel/test-repl-.editor.js b/test/parallel/test-repl-.editor.js new file mode 100644 index 00000000000..15765ad517d --- /dev/null +++ b/test/parallel/test-repl-.editor.js @@ -0,0 +1,55 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const repl = require('repl'); + +// \u001b[1G - Moves the cursor to 1st column +// \u001b[0J - Clear screen +// \u001b[3G - Moves the cursor to 3rd column +const terminalCode = '\u001b[1G\u001b[0J> \u001b[3G'; + +function run(input, output, event) { + const stream = new common.ArrayStream(); + let found = ''; + + stream.write = (msg) => found += msg.replace('\r', ''); + + const expected = `${terminalCode}.editor\n` + + '// Entering editor mode (^D to finish, ^C to cancel)\n' + + `${input}${output}\n${terminalCode}`; + + const replServer = repl.start({ + prompt: '> ', + terminal: true, + input: stream, + output: stream, + useColors: false + }); + + stream.emit('data', '.editor\n'); + stream.emit('data', input); + replServer.write('', event); + replServer.close(); + assert.strictEqual(found, expected); +} + +const tests = [ + { + input: '', + output: '\n(To exit, press ^C again or type .exit)', + event: {ctrl: true, name: 'c'} + }, + { + input: 'var i = 1;', + output: '', + event: {ctrl: true, name: 'c'} + }, + { + input: 'var i = 1;\ni + 3', + output: '\n4', + event: {ctrl: true, name: 'd'} + } +]; + +tests.forEach(({input, output, event}) => run(input, output, event)); diff --git a/test/parallel/test-repl-.save.load.js b/test/parallel/test-repl-.save.load.js index b9c5bc88afa..1d2526d4050 100644 --- a/test/parallel/test-repl-.save.load.js +++ b/test/parallel/test-repl-.save.load.js @@ -27,7 +27,8 @@ putIn.run(testFile); putIn.run(['.save ' + saveFileName]); // the file should have what I wrote -assert.equal(fs.readFileSync(saveFileName, 'utf8'), testFile.join('\n') + '\n'); +assert.equal(fs.readFileSync(saveFileName, 'utf8'), testFile.join('\r\n') + + '\r\n'); // make sure that the REPL data is "correct" // so when I load it back I know I'm good @@ -54,7 +55,7 @@ var loadFile = join(common.tmpDir, 'file.does.not.exist'); // should not break putIn.write = function(data) { // make sure I get a failed to load message and not some crazy error - assert.equal(data, 'Failed to load:' + loadFile + '\n'); + assert.equal(data, 'Failed to load:' + loadFile + '\r\n'); // eat me to avoid work putIn.write = function() {}; }; @@ -63,7 +64,7 @@ putIn.run(['.load ' + loadFile]); // throw error on loading directory loadFile = common.tmpDir; putIn.write = function(data) { - assert.equal(data, 'Failed to load:' + loadFile + ' is not a valid file\n'); + assert.equal(data, 'Failed to load:' + loadFile + ' is not a valid file\r\n'); putIn.write = function() {}; }; putIn.run(['.load ' + loadFile]); @@ -78,7 +79,7 @@ const invalidFileName = join(common.tmpDir, '\0\0\0\0\0'); // should not break putIn.write = function(data) { // make sure I get a failed to save message and not some other error - assert.equal(data, 'Failed to save:' + invalidFileName + '\n'); + assert.equal(data, 'Failed to save:' + invalidFileName + '\r\n'); // reset to no-op putIn.write = function() {}; }; diff --git a/test/parallel/test-repl-autolibs.js b/test/parallel/test-repl-autolibs.js index 15f779d3b12..1be2c33d28f 100644 --- a/test/parallel/test-repl-autolibs.js +++ b/test/parallel/test-repl-autolibs.js @@ -19,7 +19,7 @@ function test1() { if (data.length) { // inspect output matches repl output - assert.equal(data, util.inspect(require('fs'), null, 2, false) + '\n'); + assert.equal(data, util.inspect(require('fs'), null, 2, false) + '\r\n'); // globally added lib matches required lib assert.equal(global.fs, require('fs')); test2(); @@ -36,7 +36,7 @@ function test2() { gotWrite = true; if (data.length) { // repl response error message - assert.equal(data, '{}\n'); + assert.equal(data, '{}\r\n'); // original value wasn't overwritten assert.equal(val, global.url); } diff --git a/test/parallel/test-repl-definecommand.js b/test/parallel/test-repl-definecommand.js index c0e1b3269a3..d6a6fee192a 100644 --- a/test/parallel/test-repl-definecommand.js +++ b/test/parallel/test-repl-definecommand.js @@ -34,10 +34,10 @@ r.defineCommand('say2', function() { this.displayPrompt(); }); -inputStream.write('.help\n'); -assert(/\nsay1\thelp for say1\n/.test(output), 'help for say1 not present'); -assert(/\nsay2\t\n/.test(output), 'help for say2 not present'); -inputStream.write('.say1 node developer\n'); +inputStream.write('.help\r\n'); +assert(/\r\nsay1\thelp for say1\r\n/.test(output), 'help for say1 not present'); +assert(/\r\nsay2\t\r\n/.test(output), 'help for say2 not present'); +inputStream.write('.say1 node developer\r\n'); assert(/> hello node developer/.test(output), 'say1 outputted incorrectly'); -inputStream.write('.say2 node developer\n'); +inputStream.write('.say2 node developer\r\n'); assert(/> hello from say2/.test(output), 'say2 outputted incorrectly'); diff --git a/test/parallel/test-repl-deprecated.js b/test/parallel/test-repl-deprecated.js new file mode 100644 index 00000000000..eabc313f475 --- /dev/null +++ b/test/parallel/test-repl-deprecated.js @@ -0,0 +1,28 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const repl = require('repl'); + +const expected = [ + 'replServer.convertToContext() is deprecated' +]; + +process.on('warning', common.mustCall((warning) => { + assert.strictEqual(warning.name, 'DeprecationWarning'); + assert.notStrictEqual(expected.indexOf(warning.message), -1, + `unexpected error message: "${warning.message}"`); + // Remove a warning message after it is seen so that we guarantee that we get + // each message only once. + expected.splice(expected.indexOf(warning.message), 1); +}, expected.length)); + +// Create a dummy stream that does nothing +const stream = new common.ArrayStream(); + +const replServer = repl.start({ + input: stream, + output: stream +}); + +const cmd = replServer.convertToContext('var name = "nodejs"'); +assert.strictEqual(cmd, 'self.context.name = "nodejs"'); diff --git a/test/parallel/test-repl-envvars.js b/test/parallel/test-repl-envvars.js index 759b4e15a12..b08f6cbaf62 100644 --- a/test/parallel/test-repl-envvars.js +++ b/test/parallel/test-repl-envvars.js @@ -2,7 +2,7 @@ // Flags: --expose-internals -require('../common'); +const common = require('../common'); const stream = require('stream'); const REPL = require('internal/repl'); const assert = require('assert'); @@ -46,6 +46,10 @@ function run(test) { REPL.createInternalRepl(env, opts, function(err, repl) { if (err) throw err; + + // The REPL registers 'module' and 'require' globals + common.allowGlobals(repl.context.module, repl.context.require); + assert.equal(expected.terminal, repl.terminal, 'Expected ' + inspect(expected) + ' with ' + inspect(env)); assert.equal(expected.useColors, repl.useColors, diff --git a/test/parallel/test-repl-history-perm.js b/test/parallel/test-repl-history-perm.js index c7d2852539a..4a374cb0ab1 100644 --- a/test/parallel/test-repl-history-perm.js +++ b/test/parallel/test-repl-history-perm.js @@ -35,6 +35,10 @@ const replHistoryPath = path.join(common.tmpDir, '.node_repl_history'); const checkResults = common.mustCall(function(err, r) { if (err) throw err; + + // The REPL registers 'module' and 'require' globals + common.allowGlobals(r.context.module, r.context.require); + r.input.end(); const stat = fs.statSync(replHistoryPath); assert.strictEqual( diff --git a/test/parallel/test-repl-mode.js b/test/parallel/test-repl-mode.js index 08b296c2c34..d5d9f12100f 100644 --- a/test/parallel/test-repl-mode.js +++ b/test/parallel/test-repl-mode.js @@ -21,14 +21,14 @@ function testSloppyMode() { cli.input.emit('data', ` x = 3 - `.trim() + '\n'); - assert.equal(cli.output.accumulator.join(''), '> 3\n> '); + `.trim() + '\r\n'); + assert.equal(cli.output.accumulator.join(''), '> 3\r\n> '); cli.output.accumulator.length = 0; cli.input.emit('data', ` let y = 3 - `.trim() + '\n'); - assert.equal(cli.output.accumulator.join(''), 'undefined\n> '); + `.trim() + '\r\n'); + assert.equal(cli.output.accumulator.join(''), 'undefined\r\n> '); } function testStrictMode() { @@ -36,15 +36,15 @@ function testStrictMode() { cli.input.emit('data', ` x = 3 - `.trim() + '\n'); + `.trim() + '\r\n'); assert.ok(/ReferenceError: x is not defined/.test( cli.output.accumulator.join(''))); cli.output.accumulator.length = 0; cli.input.emit('data', ` let y = 3 - `.trim() + '\n'); - assert.equal(cli.output.accumulator.join(''), 'undefined\n> '); + `.trim() + '\r\n'); + assert.equal(cli.output.accumulator.join(''), 'undefined\r\n> '); } function testAutoMode() { @@ -52,14 +52,14 @@ function testAutoMode() { cli.input.emit('data', ` x = 3 - `.trim() + '\n'); - assert.equal(cli.output.accumulator.join(''), '> 3\n> '); + `.trim() + '\r\n'); + assert.equal(cli.output.accumulator.join(''), '> 3\r\n> '); cli.output.accumulator.length = 0; cli.input.emit('data', ` let y = 3 - `.trim() + '\n'); - assert.equal(cli.output.accumulator.join(''), 'undefined\n> '); + `.trim() + '\r\n'); + assert.equal(cli.output.accumulator.join(''), 'undefined\r\n> '); } function initRepl(mode) { diff --git a/test/parallel/test-repl-persistent-history.js b/test/parallel/test-repl-persistent-history.js index 70d6a51c81b..40951fd5ed3 100644 --- a/test/parallel/test-repl-persistent-history.js +++ b/test/parallel/test-repl-persistent-history.js @@ -37,7 +37,7 @@ class ActionStream extends stream.Stream { if (typeof action === 'object') { self.emit('keypress', '', action); } else { - self.emit('data', action + '\n'); + self.emit('data', action + '\r\n'); } setImmediate(doAction); } @@ -138,7 +138,7 @@ const tests = [ env: { NODE_REPL_HISTORY_FILE: oldHistoryPath }, test: [UP, CLEAR, '\'42\'', ENTER], expected: [prompt, convertMsg, prompt, prompt + '\'=^.^=\'', prompt, '\'', - '4', '2', '\'', '\'42\'\n', prompt, prompt], + '4', '2', '\'', '\'42\'\r\n', prompt, prompt], after: function ensureHistoryFixture() { // XXX(Fishrock123) Make sure nothing weird happened to our fixture // or it's temporary copy. @@ -154,7 +154,7 @@ const tests = [ { // Requires the above testcase env: {}, test: [UP, UP, ENTER], - expected: [prompt, prompt + '\'42\'', prompt + '\'=^.^=\'', '\'=^.^=\'\n', + expected: [prompt, prompt + '\'42\'', prompt + '\'=^.^=\'', '\'=^.^=\'\r\n', prompt] }, { @@ -262,6 +262,9 @@ function runTest(assertCleaned) { throw err; } + // The REPL registers 'module' and 'require' globals + common.allowGlobals(repl.context.module, repl.context.require); + repl.once('close', () => { if (repl._flushing) { repl.once('flushHistory', onClose); diff --git a/test/parallel/test-repl-recoverable.js b/test/parallel/test-repl-recoverable.js index 6788d845950..bec1badd240 100644 --- a/test/parallel/test-repl-recoverable.js +++ b/test/parallel/test-repl-recoverable.js @@ -21,7 +21,7 @@ putIn.write = function(msg) { recovered = true; } - if (msg === 'true\n') { + if (msg === 'true\r\n') { rendered = true; } }; @@ -30,8 +30,8 @@ repl.start('', putIn, customEval); // https://github.com/nodejs/node/issues/2939 // Expose recoverable errors to the consumer. -putIn.emit('data', '1\n'); -putIn.emit('data', '2\n'); +putIn.emit('data', '1\r\n'); +putIn.emit('data', '2\r\n'); process.on('exit', function() { assert(recovered, 'REPL never recovered'); diff --git a/test/parallel/test-repl-require.js b/test/parallel/test-repl-require.js index 9dc3b51de7a..2c8ac4ecd25 100644 --- a/test/parallel/test-repl-require.js +++ b/test/parallel/test-repl-require.js @@ -24,11 +24,11 @@ server.listen(options, function() { const conn = net.connect(options); conn.setEncoding('utf8'); conn.on('data', (data) => answer += data); - conn.write('require("baz")\nrequire("./baz")\n.exit\n'); + conn.write('require("baz")\r\nrequire("./baz")\r\n.exit\r\n'); }); process.on('exit', function() { assert.strictEqual(false, /Cannot find module/.test(answer)); assert.strictEqual(false, /Error/.test(answer)); - assert.strictEqual(answer, '\'eye catcher\'\n\'perhaps I work\'\n'); + assert.strictEqual(answer, '\'eye catcher\'\r\n\'perhaps I work\'\r\n'); }); diff --git a/test/parallel/test-repl-sigint.js b/test/parallel/test-repl-sigint.js index 5ee974aaea3..303973194fe 100644 --- a/test/parallel/test-repl-sigint.js +++ b/test/parallel/test-repl-sigint.js @@ -34,17 +34,18 @@ child.stdout.once('data', common.mustCall(() => { process.kill(child.pid, 'SIGINT'); child.stdout.once('data', common.mustCall(() => { // Make sure state from before the interruption is still available. - child.stdin.end('a*2*3*7\n'); + child.stdin.end('a*2*3*7\r\n'); })); })); child.stdin.write('a = 1001;' + 'process.kill(+process.env.REPL_TEST_PPID, "SIGUSR2");' + - 'while(true){}\n'); + 'while(true){}\r\n'); })); child.on('close', function(code) { assert.strictEqual(code, 0); - assert.notStrictEqual(stdout.indexOf('Script execution interrupted.\n'), -1); - assert.notStrictEqual(stdout.indexOf('42042\n'), -1); + assert.notStrictEqual(stdout.indexOf('Script execution interrupted.' + + '\r\n'), -1); + assert.notStrictEqual(stdout.indexOf('42042\r\n'), -1); }); diff --git a/test/parallel/test-repl-tab-complete.js b/test/parallel/test-repl-tab-complete.js index 73a3fd148bf..4ff4371875c 100644 --- a/test/parallel/test-repl-tab-complete.js +++ b/test/parallel/test-repl-tab-complete.js @@ -348,3 +348,25 @@ testCustomCompleterAsyncMode.complete('a', common.mustCall((error, data) => { 'a' ]); })); + +// tab completion in editor mode +const editorStream = new common.ArrayStream(); +const editor = repl.start({ + stream: editorStream, + terminal: true, + useColors: false +}); + +editorStream.run(['.clear']); +editorStream.run(['.editor']); + +editor.completer('co', common.mustCall((error, data) => { + assert.deepStrictEqual(data, [['con'], 'co']); +})); + +editorStream.run(['.clear']); +editorStream.run(['.editor']); + +editor.completer('var log = console.l', common.mustCall((error, data) => { + assert.deepStrictEqual(data, [['console.log'], 'console.l']); +})); diff --git a/test/parallel/test-repl-underscore.js b/test/parallel/test-repl-underscore.js index 97fc508ad9e..bdcf4e82ecb 100644 --- a/test/parallel/test-repl-underscore.js +++ b/test/parallel/test-repl-underscore.js @@ -151,6 +151,6 @@ function initRepl(mode) { } function assertOutput(output, expected) { - const lines = output.accum.trim().split('\n'); + const lines = output.accum.trim().split('\r\n'); assert.deepStrictEqual(lines, expected); } diff --git a/test/parallel/test-repl-unexpected-token-recoverable.js b/test/parallel/test-repl-unexpected-token-recoverable.js index 84668c8657c..96c8cbedf4d 100644 --- a/test/parallel/test-repl-unexpected-token-recoverable.js +++ b/test/parallel/test-repl-unexpected-token-recoverable.js @@ -10,9 +10,9 @@ var spawn = require('child_process').spawn; var args = [ '-i' ]; var child = spawn(process.execPath, args); -var input = 'var foo = "bar\\\nbaz"'; +var input = 'var foo = "bar\\\r\nbaz"'; // Match '...' as well since it marks a multi-line statement -var expectOut = /^> ... undefined\n/; +var expectOut = /^> ... undefined\r\n/; child.stderr.setEncoding('utf8'); child.stderr.on('data', function(c) { diff --git a/test/parallel/test-repl-use-global.js b/test/parallel/test-repl-use-global.js index 86c646cc767..7ac60886791 100644 --- a/test/parallel/test-repl-use-global.js +++ b/test/parallel/test-repl-use-global.js @@ -7,8 +7,6 @@ const stream = require('stream'); const repl = require('internal/repl'); const assert = require('assert'); -common.globalCheck = false; - // Array of [useGlobal, expectedResult] pairs const globalTestCases = [ [false, 'undefined'], @@ -20,10 +18,13 @@ const globalTest = (useGlobal, cb, output) => (err, repl) => { if (err) return cb(err); + // The REPL registers 'module' and 'require' globals + common.allowGlobals(repl.context.module, repl.context.require); + let str = ''; output.on('data', (data) => (str += data)); global.lunch = 'tacos'; - repl.write('global.lunch;\n'); + repl.write('global.lunch;\r\n'); repl.close(); delete global.lunch; cb(null, str.trim()); @@ -53,8 +54,8 @@ const processTest = (useGlobal, cb, output) => (err, repl) => { output.on('data', (data) => (str += data)); // if useGlobal is false, then `let process` should work - repl.write('let process;\n'); - repl.write('21 * 2;\n'); + repl.write('let process;\r\n'); + repl.write('21 * 2;\r\n'); repl.close(); cb(null, str.trim()); }; @@ -62,7 +63,7 @@ const processTest = (useGlobal, cb, output) => (err, repl) => { for (const option of processTestCases) { runRepl(option, processTest, common.mustCall((err, output) => { assert.ifError(err); - assert.strictEqual(output, 'undefined\n42'); + assert.strictEqual(output, 'undefined\r\n42'); })); } diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index 4411f59588a..f1b2c5a68b5 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -12,8 +12,8 @@ const prompt_unix = 'node via Unix socket> '; const prompt_tcp = 'node via TCP socket> '; const prompt_multiline = '... '; const prompt_npm = 'npm should be run outside of the ' + - 'node repl, in your normal shell.\n' + - '(Press Control-D to exit.)\n'; + 'node repl, in your normal shell.\r\n' + + '(Press Control-D to exit.)\r\n'; const expect_npm = prompt_npm + prompt_unix; var server_tcp, server_unix, client_tcp, client_unix, replServer; @@ -36,7 +36,7 @@ function send_expect(list) { cur.client.expect = cur.expect; cur.client.list = list; if (cur.send.length > 0) { - cur.client.write(cur.send + '\n'); + cur.client.write(cur.send + '\r\n'); } } } @@ -101,7 +101,7 @@ function error_test() { run_strict_test = false; strict_mode_error_test(); } else { - console.error('End of Error test, running TCP test.\n'); + console.error('End of Error test, running TCP test.\r\n'); tcp_test(); } @@ -111,6 +111,11 @@ function error_test() { }); send_expect([ + // Can handle carriage returns + { client: client_unix, send: '(function(){return "JungMinu";})()', + expect: "'JungMinu'\r\n" + prompt_unix }, + { client: client_unix, send: 'const JungMinu="\\r\\nMinwooJung";JungMinu', + expect: 'MinwooJung' }, // Uncaught error throws and prints out { client: client_unix, send: 'throw new Error(\'test error\');', expect: /^Error: test error/ }, @@ -123,7 +128,7 @@ function error_test() { // But passing the same string to eval() should throw { client: client_unix, send: 'eval("function test_func() {")', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Unexpected end of input/, + v8: /\bSyntaxError: Unexpected end of input/, chakracore: /^SyntaxError: Expected '}'/}) }, // Can handle multiline template literals @@ -136,12 +141,12 @@ function error_test() { { client: client_unix, send: '`io.js ${"1.0"', expect: prompt_multiline }, { client: client_unix, send: '+ ".2"}`', - expect: `'io.js 1.0.2'\n${prompt_unix}` }, + expect: `'io.js 1.0.2'\r\n${prompt_unix}` }, // Dot prefix in multiline commands aren't treated as commands { client: client_unix, send: '("a"', expect: prompt_multiline }, { client: client_unix, send: '.charAt(0))', - expect: `'a'\n${prompt_unix}` }, + expect: `'a'\r\n${prompt_unix}` }, // Floating point numbers are not interpreted as REPL commands. { client: client_unix, send: '.1234', expect: '0.1234' }, @@ -155,72 +160,72 @@ function error_test() { // should throw { client: client_unix, send: 'JSON.parse(\'{invalid: \\\'json\\\'}\');', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Unexpected token i/, + v8: /\bSyntaxError: Unexpected token i/, chakracore: /^SyntaxError: Invalid character/}) }, // end of input to JSON.parse error is special case of syntax error, // should throw { client: client_unix, send: 'JSON.parse(\'066\');', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Unexpected number/, + v8: /\bSyntaxError: Unexpected number/, chakracore: /^SyntaxError: Invalid number/}) }, // should throw { client: client_unix, send: 'JSON.parse(\'{\');', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Unexpected end of JSON input/, + v8: /\bSyntaxError: Unexpected end of JSON input/, chakracore: /^SyntaxError: Syntax error/}) }, // invalid RegExps are a special case of syntax error, // should throw { client: client_unix, send: '/(/;', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Invalid regular expression\:/, + v8: /\bSyntaxError: Invalid regular expression\:/, chakracore: /^SyntaxError: Expected '\)' in regular expression/}) }, // invalid RegExp modifiers are a special case of syntax error, // should throw (GH-4012) { client: client_unix, send: 'new RegExp("foo", "wrong modifier");', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Invalid flags supplied to RegExp constructor/, + v8: /\bSyntaxError: Invalid flags supplied to RegExp constructor/, chakracore: /^SyntaxError: Syntax error in regular expression/}) }, // strict mode syntax errors should be caught (GH-5178) { client: client_unix, send: '(function() { "use strict"; return 0755; })()', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Octal literals are not allowed in strict mode/, + v8: /\bSyntaxError: Octal literals are not allowed in strict mode/, chakracore: /^SyntaxError: Octal numeric literals and escape characters not allowed in strict mode/}) }, { client: client_unix, send: '(function(a, a, b) { "use strict"; return a + b + c; })()', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Duplicate parameter name not allowed in this context/, + v8: /\bSyntaxError: Duplicate parameter name not allowed in this context/, chakracore: /^SyntaxError: Duplicate formal parameter names not allowed in strict mode/}) }, { client: client_unix, send: '(function() { "use strict"; with (this) {} })()', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Strict mode code may not include a with statement/, + v8: /\bSyntaxError: Strict mode code may not include a with statement/, chakracore: /^SyntaxError: 'with' statements are not allowed in strict mode/}) }, { client: client_unix, send: '(function() { "use strict"; var x; delete x; })()', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Delete of an unqualified identifier in strict mode/, + v8: /\bSyntaxError: Delete of an unqualified identifier in strict mode/, chakracore: /^SyntaxError: Calling delete on expression not allowed in strict mode/}) }, { client: client_unix, send: '(function() { "use strict"; eval = 17; })()', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Unexpected eval or arguments in strict mode/, + v8: /\bSyntaxError: Unexpected eval or arguments in strict mode/, chakracore: /^SyntaxError: Invalid usage of 'eval' in strict mode/}) }, { client: client_unix, send: '(function() { "use strict"; if (true) function f() { } })()', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: In strict mode code, functions can only be declared at top level or inside a block./, + v8: /\bSyntaxError: In strict mode code, functions can only be declared at top level or inside a block./, chakracore: /^SyntaxError: Syntax error/}) }, // Named functions can be used: { client: client_unix, send: 'function blah() { return 1; }', expect: prompt_unix }, { client: client_unix, send: 'blah()', - expect: '1\n' + prompt_unix }, + expect: '1\r\n' + prompt_unix }, // Functions should not evaluate twice (#2773) { client: client_unix, send: 'var I = [1,2,3,function() {}]; I.pop()', expect: '[Function]' }, @@ -246,14 +251,14 @@ function error_test() { expect: prompt_multiline, chakracore: 'skip' }, { client: client_unix, send: ')', - expect: 'undefined\n' + prompt_unix, + expect: 'undefined\r\n' + prompt_unix, chakracore: 'skip' }, // npm prompt error message { client: client_unix, send: 'npm install foobar', expect: expect_npm }, - { client: client_unix, send: '(function() {\n\nreturn 1;\n})()', + { client: client_unix, send: '(function() {\r\n\r\nreturn 1;\r\n})()', expect: '1' }, - { client: client_unix, send: '{\n\na: 1\n}', + { client: client_unix, send: '{\r\n\r\na: 1\r\n}', expect: '{ a: 1 }' }, { client: client_unix, send: 'url.format("http://google.com")', expect: 'http://google.com/' }, @@ -262,21 +267,21 @@ function error_test() { // this makes sure that we don't print `undefined` when we actually print // the error message { client: client_unix, send: '.invalid_repl_command', - expect: 'Invalid REPL keyword\n' + prompt_unix }, + expect: 'Invalid REPL keyword\r\n' + prompt_unix }, // this makes sure that we don't crash when we use an inherited property as // a REPL command { client: client_unix, send: '.toString', - expect: 'Invalid REPL keyword\n' + prompt_unix }, + expect: 'Invalid REPL keyword\r\n' + prompt_unix }, // fail when we are not inside a String and a line continuation is used { client: client_unix, send: '[] \\', expect: common.engineSpecificMessage({ - v8: /^SyntaxError: Invalid or unexpected token/, + v8: /\bSyntaxError: Invalid or unexpected token/, chakracore: /^SyntaxError: Invalid character/}) }, // do not fail when a String is created with line continuation - { client: client_unix, send: '\'the\\\nfourth\\\neye\'', + { client: client_unix, send: '\'the\\\r\nfourth\\\r\neye\'', expect: prompt_multiline + prompt_multiline + - '\'thefourtheye\'\n' + prompt_unix }, + '\'thefourtheye\'\r\n' + prompt_unix }, // Don't fail when a partial String is created and line continuation is used // with whitespace characters at the end of the string. We are to ignore it. // This test is to make sure that we properly remove the whitespace @@ -284,101 +289,106 @@ function error_test() { { client: client_unix, send: ' \t .break \t ', expect: prompt_unix }, // multiline strings preserve whitespace characters in them - { client: client_unix, send: '\'the \\\n fourth\t\t\\\n eye \'', + { client: client_unix, send: '\'the \\\r\n fourth\t\t\\\r\n eye \'', expect: prompt_multiline + prompt_multiline + - '\'the fourth\\t\\t eye \'\n' + prompt_unix }, + '\'the fourth\\t\\t eye \'\r\n' + prompt_unix }, // more than one multiline strings also should preserve whitespace chars - { client: client_unix, send: '\'the \\\n fourth\' + \'\t\t\\\n eye \'', + { client: client_unix, send: '\'the \\\r\n fourth\' + \'\t\t\\\r\n eye \'', expect: prompt_multiline + prompt_multiline + - '\'the fourth\\t\\t eye \'\n' + prompt_unix }, + '\'the fourth\\t\\t eye \'\r\n' + prompt_unix }, // using REPL commands within a string literal should still work - { client: client_unix, send: '\'\\\n.break', + { client: client_unix, send: '\'\\\r\n.break', expect: prompt_unix }, // using REPL command "help" within a string literal should still work - { client: client_unix, send: '\'thefourth\\\n.help\neye\'', + { client: client_unix, send: '\'thefourth\\\r\n.help\r\neye\'', expect: /'thefourtheye'/ }, // empty lines in the REPL should be allowed - { client: client_unix, send: '\n\r\n\r\n', + { client: client_unix, send: '\r\n\r\r\n\r\r\n', expect: prompt_unix + prompt_unix + prompt_unix }, // empty lines in the string literals should not affect the string - { client: client_unix, send: '\'the\\\n\\\nfourtheye\'\n', + { client: client_unix, send: '\'the\\\r\n\\\r\nfourtheye\'\r\n', expect: prompt_multiline + prompt_multiline + - '\'thefourtheye\'\n' + prompt_unix }, + '\'thefourtheye\'\r\n' + prompt_unix }, // Regression test for https://github.com/nodejs/node/issues/597 { client: client_unix, - send: '/(.)(.)(.)(.)(.)(.)(.)(.)(.)/.test(\'123456789\')\n', - expect: `true\n${prompt_unix}` }, + send: '/(.)(.)(.)(.)(.)(.)(.)(.)(.)/.test(\'123456789\')\r\n', + expect: `true\r\n${prompt_unix}` }, // the following test's result depends on the RegEx's match from the above { client: client_unix, - send: 'RegExp.$1\nRegExp.$2\nRegExp.$3\nRegExp.$4\nRegExp.$5\n' + - 'RegExp.$6\nRegExp.$7\nRegExp.$8\nRegExp.$9\n', - expect: ['\'1\'\n', '\'2\'\n', '\'3\'\n', '\'4\'\n', '\'5\'\n', '\'6\'\n', - '\'7\'\n', '\'8\'\n', '\'9\'\n'].join(`${prompt_unix}`) }, + send: 'RegExp.$1\r\nRegExp.$2\r\nRegExp.$3\r\nRegExp.$4\r\nRegExp.$5\r\n' + + 'RegExp.$6\r\nRegExp.$7\r\nRegExp.$8\r\nRegExp.$9\r\n', + expect: ['\'1\'\r\n', '\'2\'\r\n', '\'3\'\r\n', '\'4\'\r\n', '\'5\'\r\n', '\'6\'\r\n', + '\'7\'\r\n', '\'8\'\r\n', '\'9\'\r\n'].join(`${prompt_unix}`) }, // regression tests for https://github.com/nodejs/node/issues/2749 - { client: client_unix, send: 'function x() {\nreturn \'\\n\';\n }', + { client: client_unix, send: 'function x() {\r\nreturn \'\\r\\n\';\r\n }', expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, - { client: client_unix, send: 'function x() {\nreturn \'\\\\\';\n }', + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: 'function x() {\r\nreturn \'\\\\\';\r\n }', expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, + 'undefined\r\n' + prompt_unix }, // regression tests for https://github.com/nodejs/node/issues/3421 - { client: client_unix, send: 'function x() {\n//\'\n }', + { client: client_unix, send: 'function x() {\r\n//\'\r\n }', expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, - { client: client_unix, send: 'function x() {\n//"\n }', + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: 'function x() {\r\n//"\r\n }', expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, - { client: client_unix, send: 'function x() {//\'\n }', - expect: prompt_multiline + 'undefined\n' + prompt_unix }, - { client: client_unix, send: 'function x() {//"\n }', - expect: prompt_multiline + 'undefined\n' + prompt_unix }, - { client: client_unix, send: 'function x() {\nvar i = "\'";\n }', + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: 'function x() {//\'\r\n }', + expect: prompt_multiline + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: 'function x() {//"\r\n }', + expect: prompt_multiline + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: 'function x() {\r\nvar i = "\'";\r\n }', expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, + 'undefined\r\n' + prompt_unix }, { client: client_unix, send: 'function x(/*optional*/) {}', - expect: 'undefined\n' + prompt_unix }, + expect: 'undefined\r\n' + prompt_unix }, { client: client_unix, send: 'function x(/* // 5 */) {}', - expect: 'undefined\n' + prompt_unix }, + expect: 'undefined\r\n' + prompt_unix }, { client: client_unix, send: '// /* 5 */', - expect: 'undefined\n' + prompt_unix }, + expect: 'undefined\r\n' + prompt_unix }, { client: client_unix, send: '"//"', - expect: '\'//\'\n' + prompt_unix }, + expect: '\'//\'\r\n' + prompt_unix }, { client: client_unix, send: '"data /*with*/ comment"', - expect: '\'data /*with*/ comment\'\n' + prompt_unix }, + expect: '\'data /*with*/ comment\'\r\n' + prompt_unix }, { client: client_unix, send: 'function x(/*fn\'s optional params*/) {}', - expect: 'undefined\n' + prompt_unix }, - { client: client_unix, send: '/* \'\n"\n\'"\'\n*/', - expect: 'undefined\n' + prompt_unix }, + expect: 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: '/* \'\r\n"\r\n\'"\'\r\n*/', + expect: 'undefined\r\n' + prompt_unix }, // REPL should get a normal require() function, not one that allows // access to internal modules without the --expose_internals flag. { client: client_unix, send: 'require("internal/repl")', expect: /^Error: Cannot find module 'internal\/repl'/ }, // REPL should handle quotes within regexp literal in multiline mode - { client: client_unix, send: "function x(s) {\nreturn s.replace(/'/,'');\n}", + { client: client_unix, send: "function x(s) {\r\nreturn s.replace(/'/,'');\r\n}", expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, - { client: client_unix, send: "function x(s) {\nreturn s.replace(/\'/,'');\n}", + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: "function x(s) {\r\nreturn s.replace(/\'/,'');\r\n}", expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, - { client: client_unix, send: 'function x(s) {\nreturn s.replace(/"/,"");\n}', + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: 'function x(s) {\r\nreturn s.replace(/"/,"");\r\n}', expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, - { client: client_unix, send: 'function x(s) {\nreturn s.replace(/.*/,"");\n}', + 'undefined\r\n' + prompt_unix }, + { client: client_unix, send: 'function x(s) {\r\nreturn s.replace(/.*/,"");\r\n}', expect: prompt_multiline + prompt_multiline + - 'undefined\n' + prompt_unix }, + 'undefined\r\n' + prompt_unix }, { client: client_unix, send: '{ var x = 4; }', - expect: 'undefined\n' + prompt_unix }, + expect: 'undefined\r\n' + prompt_unix }, // Illegal token is not recoverable outside string literal, RegExp literal, // or block comment. https://github.com/nodejs/node/issues/3611 { client: client_unix, send: 'a = 3.5e', - expect: /^SyntaxError: Invalid or unexpected token/ }, + expect: /\bSyntaxError: Invalid or unexpected token/ }, // Mitigate https://github.com/nodejs/node/issues/548 { client: client_unix, send: 'function name(){ return "node"; };name()', - expect: "'node'\n" + prompt_unix }, + expect: "'node'\r\n" + prompt_unix }, { client: client_unix, send: 'function name(){ return "nodejs"; };name()', - expect: "'nodejs'\n" + prompt_unix }, - + expect: "'nodejs'\r\n" + prompt_unix }, + // Avoid emitting repl:line-number for SyntaxError + { client: client_unix, send: 'a = 3.5e', + expect: /^(?!repl)/ }, + // Avoid emitting stack trace + { client: client_unix, send: 'a = 3.5e', + expect: /^(?!\s+at\s)/gm }, ].filter((v) => !common.engineSpecificMessage(v))); } @@ -406,12 +416,12 @@ function tcp_test() { { client: client_tcp, send: '', expect: prompt_tcp }, { client: client_tcp, send: 'invoke_me(333)', - expect: ('\'' + 'invoked 333' + '\'\n' + prompt_tcp) }, + expect: ('\'' + 'invoked 333' + '\'\r\n' + prompt_tcp) }, { client: client_tcp, send: 'a += 1', - expect: ('12346' + '\n' + prompt_tcp) }, + expect: ('12346' + '\r\n' + prompt_tcp) }, { client: client_tcp, send: 'require(' + JSON.stringify(moduleFilename) + ').number', - expect: ('42' + '\n' + prompt_tcp) } + expect: ('42' + '\r\n' + prompt_tcp) } ]); }); @@ -426,7 +436,7 @@ function tcp_test() { if (client_tcp.list && client_tcp.list.length > 0) { send_expect(client_tcp.list); } else { - console.error('End of TCP test.\n'); + console.error('End of TCP test.\r\n'); clean_up(); } } else { @@ -475,13 +485,13 @@ function unix_test() { { client: client_unix, send: '', expect: prompt_unix }, { client: client_unix, send: 'message', - expect: ('\'' + message + '\'\n' + prompt_unix) }, + expect: ('\'' + message + '\'\r\n' + prompt_unix) }, { client: client_unix, send: 'invoke_me(987)', - expect: ('\'' + 'invoked 987' + '\'\n' + prompt_unix) }, + expect: ('\'' + 'invoked 987' + '\'\r\n' + prompt_unix) }, { client: client_unix, send: 'a = 12345', - expect: ('12345' + '\n' + prompt_unix) }, + expect: ('12345' + '\r\n' + prompt_unix) }, { client: client_unix, send: '{a:1}', - expect: ('{ a: 1 }' + '\n' + prompt_unix) } + expect: ('{ a: 1 }' + '\r\n' + prompt_unix) } ]); }); @@ -496,7 +506,7 @@ function unix_test() { if (client_unix.list && client_unix.list.length > 0) { send_expect(client_unix.list); } else { - console.error('End of Unix test, running Error test.\n'); + console.error('End of Unix test, running Error test.\r\n'); process.nextTick(error_test); } } else { diff --git a/test/parallel/test-timers-same-timeout-wrong-list-deleted.js b/test/parallel/test-timers-same-timeout-wrong-list-deleted.js new file mode 100644 index 00000000000..05c0233e124 --- /dev/null +++ b/test/parallel/test-timers-same-timeout-wrong-list-deleted.js @@ -0,0 +1,80 @@ +'use strict'; + +/* + * This is a regression test for https://github.com/nodejs/node/issues/7722. + * + * When nested timers have the same timeout, calling clearTimeout on the + * older timer after it has fired causes the list the newer timer is in + * to be deleted. Since the newer timer was not cleared, it still blocks + * the event loop completing for the duration of its timeout, however, since + * no reference exists to it in its list, it cannot be canceled and its + * callback is not called when the timeout elapses. + */ + +const common = require('../common'); +const assert = require('assert'); +const Timer = process.binding('timer_wrap').Timer; + +const TIMEOUT = common.platformTimeout(100); +const start = Timer.now(); + +// This bug also prevents the erroneously dereferenced timer's callback +// from being called, so we can't use it's execution or lack thereof +// to assert that the bug is fixed. +process.on('exit', function() { + const end = Timer.now(); + assert.equal(end - start < TIMEOUT * 2, true, + 'Elapsed time does not include second timer\'s timeout.'); +}); + +const handle1 = setTimeout(common.mustCall(function() { + // Cause the old TIMEOUT list to be deleted + clearTimeout(handle1); + + // Cause a new list with the same key (TIMEOUT) to be created for this timer + const handle2 = setTimeout(function() { + common.fail('Inner callback is not called'); + }, TIMEOUT); + + setTimeout(common.mustCall(function() { + // Attempt to cancel the second timer. Fix for this bug will keep the + // newer timer from being dereferenced by keeping its list from being + // erroneously deleted. If we are able to cancel the timer successfully, + // the bug is fixed. + clearTimeout(handle2); + setImmediate(common.mustCall(function() { + setImmediate(common.mustCall(function() { + const activeHandles = process._getActiveHandles(); + const activeTimers = activeHandles.filter(function(handle) { + return handle instanceof Timer; + }); + + // Make sure our clearTimeout succeeded. One timer finished and + // the other was canceled, so none should be active. + assert.equal(activeTimers.length, 0, 'No Timers remain.'); + })); + })); + }), 10); + + // Make sure our timers got added to the list. + const activeHandles = process._getActiveHandles(); + const activeTimers = activeHandles.filter(function(handle) { + return handle instanceof Timer; + }); + const shortTimer = activeTimers.find(function(handle) { + return handle._list.msecs === 10; + }); + const longTimers = activeTimers.filter(function(handle) { + return handle._list.msecs === TIMEOUT; + }); + + // Make sure our clearTimeout succeeded. One timer finished and + // the other was canceled, so none should be active. + assert.equal(activeTimers.length, 3, 'There are 3 timers in the list.'); + assert(shortTimer instanceof Timer, 'The shorter timer is in the list.'); + assert.equal(longTimers.length, 2, 'Both longer timers are in the list.'); + + // When this callback completes, `listOnTimeout` should now look at the + // correct list and refrain from removing the new TIMEOUT list which + // contains the reference to the newer timer. +}), TIMEOUT); diff --git a/test/parallel/test-tls-wrap-timeout.js b/test/parallel/test-tls-wrap-timeout.js index ab0f307a970..0454242d92e 100644 --- a/test/parallel/test-tls-wrap-timeout.js +++ b/test/parallel/test-tls-wrap-timeout.js @@ -1,42 +1,54 @@ 'use strict'; -var common = require('../common'); -var assert = require('assert'); +const common = require('../common'); if (!common.hasCrypto) { common.skip('missing crypto'); return; } -var tls = require('tls'); +const assert = require('assert'); +const tls = require('tls'); -var net = require('net'); -var fs = require('fs'); +const net = require('net'); +const fs = require('fs'); -var options = { +const options = { key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'), cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem') }; -var server = tls.createServer(options, function(c) { - setTimeout(function() { - c.write('hello'); - setTimeout(function() { - c.destroy(); - server.close(); - }, 150); - }, 150); -}); +const server = tls.createServer(options, common.mustCall((c) => { + setImmediate(() => { + c.write('hello', () => { + setImmediate(() => { + c.destroy(); + server.close(); + }); + }); + }); +})); + +var socket; +var lastIdleStart; -server.listen(0, function() { - var socket = net.connect(this.address().port, function() { - var s = socket.setTimeout(common.platformTimeout(240), function() { +server.listen(0, () => { + socket = net.connect(server.address().port, function() { + const s = socket.setTimeout(Number.MAX_VALUE, function() { throw new Error('timeout'); }); assert.ok(s instanceof net.Socket); - var tsocket = tls.connect({ + assert.notStrictEqual(socket._idleTimeout, -1); + lastIdleStart = socket._idleStart; + + const tsocket = tls.connect({ socket: socket, rejectUnauthorized: false }); tsocket.resume(); }); }); + +process.on('exit', () => { + assert.strictEqual(socket._idleTimeout, -1); + assert(lastIdleStart < socket._idleStart); +}); diff --git a/test/parallel/test-util-format.js b/test/parallel/test-util-format.js index f3702ef2f05..b8977e57b51 100644 --- a/test/parallel/test-util-format.js +++ b/test/parallel/test-util-format.js @@ -7,7 +7,9 @@ const symbol = Symbol('foo'); assert.equal(util.format(), ''); assert.equal(util.format(''), ''); assert.equal(util.format([]), '[]'); +assert.equal(util.format([0]), '[ 0 ]'); assert.equal(util.format({}), '{}'); +assert.equal(util.format({foo: 42}), '{ foo: 42 }'); assert.equal(util.format(null), 'null'); assert.equal(util.format(true), 'true'); assert.equal(util.format(false), 'false'); diff --git a/test/parallel/test-util-inspect-proxy.js b/test/parallel/test-util-inspect-proxy.js index 744bf235266..8fc9087703f 100644 --- a/test/parallel/test-util-inspect-proxy.js +++ b/test/parallel/test-util-inspect-proxy.js @@ -48,11 +48,11 @@ const expected2 = 'Proxy [ Proxy [ {}, {} ], {} ]'; const expected3 = 'Proxy [ Proxy [ Proxy [ {}, {} ], {} ], Proxy [ {}, {} ] ]'; const expected4 = 'Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [ {}, {} ], {} ] ]'; const expected5 = 'Proxy [ Proxy [ Proxy [ Proxy [Object], {} ],' + - ' Proxy [ {}, {} ] ],\n Proxy [ Proxy [ {}, {} ]' + + ' Proxy [ {}, {} ] ],\r\n Proxy [ Proxy [ {}, {} ]' + ', Proxy [ Proxy [Object], {} ] ] ]'; const expected6 = 'Proxy [ Proxy [ Proxy [ Proxy [Object], Proxy [Object]' + - ' ],\n Proxy [ Proxy [Object], Proxy [Object] ] ],\n' + - ' Proxy [ Proxy [ Proxy [Object], Proxy [Object] ],\n' + + ' ],\r\n Proxy [ Proxy [Object], Proxy [Object] ] ],\r\n' + + ' Proxy [ Proxy [ Proxy [Object], Proxy [Object] ],\r\n' + ' Proxy [ Proxy [Object], Proxy [Object] ] ] ]'; assert.strictEqual(util.inspect(proxy1, opts), expected1); assert.strictEqual(util.inspect(proxy2, opts), expected2); diff --git a/test/parallel/test-util-inspect-simd.js b/test/parallel/test-util-inspect-simd.js index 752ea3d0ce6..4c5d79568c4 100644 --- a/test/parallel/test-util-inspect-simd.js +++ b/test/parallel/test-util-inspect-simd.js @@ -17,9 +17,10 @@ assert.strictEqual( assert.strictEqual( inspect(SIMD.Bool8x16()), - 'Bool8x16 [\n false,\n false,\n false,\n false,\n false,\n' + - ' false,\n false,\n false,\n false,\n false,\n false,\n' + - ' false,\n false,\n false,\n false,\n false ]'); + 'Bool8x16 [\r\n false,\r\n false,\r\n false,\r\n false,\r\n' + + ' false,\r\n false,\r\n false,\r\n false,\r\n false,\r\n' + + ' false,\r\n false,\r\n false,\r\n false,\r\n false,\r\n' + + ' false,\r\n false ]'); assert.strictEqual( inspect(SIMD.Bool32x4()), @@ -59,3 +60,12 @@ if (typeof SIMD.Uint8x16 === 'function') { inspect(SIMD.Uint8x16()), 'Uint8x16 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]'); } + +// Tests from test-inspect.js that should not fail with --harmony_simd. +assert.strictEqual(inspect([]), '[]'); +assert.strictEqual(inspect([0]), '[ 0 ]'); +assert.strictEqual(inspect({}), '{}'); +assert.strictEqual(inspect({foo: 42}), '{ foo: 42 }'); +assert.strictEqual(inspect(null), 'null'); +assert.strictEqual(inspect(true), 'true'); +assert.strictEqual(inspect(false), 'false'); diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 26f2f9333b7..862661b3ec5 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -11,12 +11,12 @@ assert.equal(util.inspect('hello'), "'hello'"); assert.equal(util.inspect(function() {}), '[Function]'); assert.equal(util.inspect(undefined), 'undefined'); assert.equal(util.inspect(null), 'null'); -assert.equal(util.inspect(/foo(bar\n)?/gi), '/foo(bar\\n)?/gi'); +assert.equal(util.inspect(/foo(bar\r\n)?/gi), '/foo(bar\\r\\n)?/gi'); assert.strictEqual(util.inspect(new Date('Sun, 14 Feb 2010 11:48:40 GMT')), new Date('2010-02-14T12:48:40+01:00').toISOString()); assert.strictEqual(util.inspect(new Date('')), (new Date('')).toString()); -assert.equal(util.inspect('\n\u0001'), "'\\n\\u0001'"); +assert.equal(util.inspect('\r\n\u0001'), "'\\r\\n\\u0001'"); assert.equal(util.inspect([]), '[]'); assert.equal(util.inspect(Object.create([])), 'Array {}'); @@ -46,30 +46,37 @@ assert.equal(util.inspect(Object.create({}, '{ visible: 1 }' ); +assert(/Object/.test( + util.inspect({a: {a: {a: {a: {}}}}}, undefined, undefined, true) +)); +assert(!/Object/.test( + util.inspect({a: {a: {a: {a: {}}}}}, undefined, null, true) +)); + for (const showHidden of [true, false]) { const ab = new ArrayBuffer(4); const dv = new DataView(ab, 1, 2); assert.equal(util.inspect(ab, showHidden), 'ArrayBuffer { byteLength: 4 }'); assert.equal(util.inspect(new DataView(ab, 1, 2), showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + + 'DataView {\r\n' + + ' byteLength: 2,\r\n' + + ' byteOffset: 1,\r\n' + ' buffer: ArrayBuffer { byteLength: 4 } }'); assert.equal(util.inspect(ab, showHidden), 'ArrayBuffer { byteLength: 4 }'); assert.equal(util.inspect(dv, showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + + 'DataView {\r\n' + + ' byteLength: 2,\r\n' + + ' byteOffset: 1,\r\n' + ' buffer: ArrayBuffer { byteLength: 4 } }'); ab.x = 42; dv.y = 1337; assert.equal(util.inspect(ab, showHidden), 'ArrayBuffer { byteLength: 4, x: 42 }'); assert.equal(util.inspect(dv, showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + - ' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' + + 'DataView {\r\n' + + ' byteLength: 2,\r\n' + + ' byteOffset: 1,\r\n' + + ' buffer: ArrayBuffer { byteLength: 4, x: 42 },\r\n' + ' y: 1337 }'); } @@ -79,25 +86,25 @@ for (const showHidden of [true, false]) { const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab: ab }); assert.equal(util.inspect(ab, showHidden), 'ArrayBuffer { byteLength: 4 }'); assert.equal(util.inspect(new DataView(ab, 1, 2), showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + + 'DataView {\r\n' + + ' byteLength: 2,\r\n' + + ' byteOffset: 1,\r\n' + ' buffer: ArrayBuffer { byteLength: 4 } }'); assert.equal(util.inspect(ab, showHidden), 'ArrayBuffer { byteLength: 4 }'); assert.equal(util.inspect(dv, showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + + 'DataView {\r\n' + + ' byteLength: 2,\r\n' + + ' byteOffset: 1,\r\n' + ' buffer: ArrayBuffer { byteLength: 4 } }'); ab.x = 42; dv.y = 1337; assert.equal(util.inspect(ab, showHidden), 'ArrayBuffer { byteLength: 4, x: 42 }'); assert.equal(util.inspect(dv, showHidden), - 'DataView {\n' + - ' byteLength: 2,\n' + - ' byteOffset: 1,\n' + - ' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' + + 'DataView {\r\n' + + ' byteLength: 2,\r\n' + + ' byteOffset: 1,\r\n' + + ' buffer: ArrayBuffer { byteLength: 4, x: 42 },\r\n' + ' y: 1337 }'); } @@ -117,13 +124,13 @@ for (const showHidden of [true, false]) { array[0] = 65; array[1] = 97; assert.equal(util.inspect(array, true), - `${constructor.name} [\n` + - ` 65,\n` + - ` 97,\n` + - ` [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT},\n` + - ` [length]: ${length},\n` + - ` [byteLength]: ${byteLength},\n` + - ` [byteOffset]: 0,\n` + + `${constructor.name} [\r\n` + + ` 65,\r\n` + + ` 97,\r\n` + + ` [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT}` + + `,\r\n [length]: ${length},\r\n` + + ` [byteLength]: ${byteLength},\r\n` + + ` [byteOffset]: 0,\r\n` + ` [buffer]: ArrayBuffer { byteLength: ${byteLength} } ]`); assert.equal(util.inspect(array, false), `${constructor.name} [ 65, 97 ]`); }); @@ -149,13 +156,13 @@ for (const showHidden of [true, false]) { array[0] = 65; array[1] = 97; assert.equal(util.inspect(array, true), - `${constructor.name} [\n` + - ` 65,\n` + - ` 97,\n` + - ` [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT},\n` + - ` [length]: ${length},\n` + - ` [byteLength]: ${byteLength},\n` + - ` [byteOffset]: 0,\n` + + `${constructor.name} [\r\n` + + ` 65,\r\n` + + ` 97,\r\n` + + ` [BYTES_PER_ELEMENT]: ${constructor.BYTES_PER_ELEMENT}` + + `,\r\n [length]: ${length},\r\n` + + ` [byteLength]: ${byteLength},\r\n` + + ` [byteOffset]: 0,\r\n` + ` [buffer]: ArrayBuffer { byteLength: ${byteLength} } ]`); assert.equal(util.inspect(array, false), `${constructor.name} [ 65, 97 ]`); }); @@ -459,7 +466,7 @@ assert.doesNotThrow(function() { // util.inspect with "colors" option should produce as many lines as without it function test_lines(input) { var count_lines = function(str) { - return (str.match(/\n/g) || []).length; + return (str.match(/\r\n/g) || []).length; }; var without_color = util.inspect(input); @@ -610,7 +617,7 @@ if (!common.isChakraEngine) { // Assumes that the first numeric character is the start of an item. function checkAlignment(container) { - var lines = util.inspect(container).split('\n'); + var lines = util.inspect(container).split('\r\n'); var pos; lines.forEach(function(line) { var npos = line.search(/\d/); @@ -756,5 +763,39 @@ checkAlignment(new Map(big_array.map(function(y) { return [y, null]; }))); assert.strictEqual(oneLine, '{ foo: \'abc\', bar: \'xyz\' }'); assert.strictEqual(oneLine, util.inspect(obj, {breakLength: breakpoint + 1})); - assert.strictEqual(twoLines, '{ foo: \'abc\',\n bar: \'xyz\' }'); + assert.strictEqual(twoLines, '{ foo: \'abc\',\r\n bar: \'xyz\' }'); +} + +// util.inspect.defaultOptions tests +{ + const arr = Array(101); + const obj = {a: {a: {a: {a: 1}}}}; + + const oldOptions = Object.assign({}, util.inspect.defaultOptions); + + // Set single option through property assignment + util.inspect.defaultOptions.maxArrayLength = null; + assert(!/1 more item/.test(util.inspect(arr))); + util.inspect.defaultOptions.maxArrayLength = oldOptions.maxArrayLength; + assert(/1 more item/.test(util.inspect(arr))); + util.inspect.defaultOptions.depth = null; + assert(!/Object/.test(util.inspect(obj))); + util.inspect.defaultOptions.depth = oldOptions.depth; + assert(/Object/.test(util.inspect(obj))); + assert.strictEqual( + JSON.stringify(util.inspect.defaultOptions), + JSON.stringify(oldOptions) + ); + + // Set multiple options through object assignment + util.inspect.defaultOptions = {maxArrayLength: null, depth: null}; + assert(!/1 more item/.test(util.inspect(arr))); + assert(!/Object/.test(util.inspect(obj))); + util.inspect.defaultOptions = oldOptions; + assert(/1 more item/.test(util.inspect(arr))); + assert(/Object/.test(util.inspect(obj))); + assert.strictEqual( + JSON.stringify(util.inspect.defaultOptions), + JSON.stringify(oldOptions) + ); } diff --git a/test/parallel/test-util-sigint-watchdog.js b/test/parallel/test-util-sigint-watchdog.js index f9bb3ecd93d..42e4048bd74 100644 --- a/test/parallel/test-util-sigint-watchdog.js +++ b/test/parallel/test-util-sigint-watchdog.js @@ -20,24 +20,24 @@ if (common.isWindows) { // Test with one call to the watchdog, one signal. binding.startSigintWatchdog(); process.kill(process.pid, 'SIGINT'); - setTimeout(common.mustCall(() => { + waitForPendingSignal(common.mustCall(() => { const hadPendingSignals = binding.stopSigintWatchdog(); assert.strictEqual(hadPendingSignals, true); next(); - }), common.platformTimeout(100)); + })); }, (next) => { // Nested calls are okay. binding.startSigintWatchdog(); binding.startSigintWatchdog(); process.kill(process.pid, 'SIGINT'); - setTimeout(common.mustCall(() => { + waitForPendingSignal(common.mustCall(() => { const hadPendingSignals1 = binding.stopSigintWatchdog(); const hadPendingSignals2 = binding.stopSigintWatchdog(); assert.strictEqual(hadPendingSignals1, true); assert.strictEqual(hadPendingSignals2, false); next(); - }), common.platformTimeout(100)); + })); }, () => { // Signal comes in after first call to stop. @@ -45,9 +45,16 @@ if (common.isWindows) { binding.startSigintWatchdog(); const hadPendingSignals1 = binding.stopSigintWatchdog(); process.kill(process.pid, 'SIGINT'); - setTimeout(common.mustCall(() => { + waitForPendingSignal(common.mustCall(() => { const hadPendingSignals2 = binding.stopSigintWatchdog(); assert.strictEqual(hadPendingSignals1, false); assert.strictEqual(hadPendingSignals2, true); - }), common.platformTimeout(100)); + })); }].reduceRight((a, b) => common.mustCall(b).bind(null, a))(); + +function waitForPendingSignal(cb) { + if (binding.watchdogHasPendingSigint()) + cb(); + else + setTimeout(waitForPendingSignal, 10, cb); +} diff --git a/test/parallel/test-vm-sigint-existing-handler.js b/test/parallel/test-vm-sigint-existing-handler.js index 0f86b53dd28..c0ab1f8d92b 100644 --- a/test/parallel/test-vm-sigint-existing-handler.js +++ b/test/parallel/test-vm-sigint-existing-handler.js @@ -61,16 +61,19 @@ if (process.argv[2] === 'child') { } process.env.REPL_TEST_PPID = process.pid; -const child = spawn(process.execPath, [ __filename, 'child' ], { - stdio: [null, 'inherit', 'inherit'] -}); +// Set the `SIGUSR2` handler before spawning the child process to make sure +// the signal is always handled. process.on('SIGUSR2', common.mustCall(() => { // First kill() breaks the while(true) loop, second one invokes the real // signal handlers. process.kill(child.pid, 'SIGINT'); }, 3)); +const child = spawn(process.execPath, [__filename, 'child'], { + stdio: [null, 'inherit', 'inherit'] +}); + child.on('close', function(code, signal) { assert.strictEqual(signal, null); assert.strictEqual(code, 0); diff --git a/test/parallel/test-vm-sigint.js b/test/parallel/test-vm-sigint.js index 2488b0d1c02..8846338b780 100644 --- a/test/parallel/test-vm-sigint.js +++ b/test/parallel/test-vm-sigint.js @@ -25,14 +25,17 @@ if (process.argv[2] === 'child') { } process.env.REPL_TEST_PPID = process.pid; -const child = spawn(process.execPath, [ __filename, 'child' ], { - stdio: [null, 'pipe', 'inherit'] -}); +// Set the `SIGUSR2` handler before spawning the child process to make sure +// the signal is always handled. process.on('SIGUSR2', common.mustCall(() => { process.kill(child.pid, 'SIGINT'); })); +const child = spawn(process.execPath, [__filename, 'child'], { + stdio: [null, 'pipe', 'inherit'] +}); + child.on('close', common.mustCall((code, signal) => { assert.strictEqual(signal, null); assert.strictEqual(code, 0); diff --git a/test/parallel/test-vm-strict-mode.js b/test/parallel/test-vm-strict-mode.js new file mode 100644 index 00000000000..f3820d8aead --- /dev/null +++ b/test/parallel/test-vm-strict-mode.js @@ -0,0 +1,27 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const vm = require('vm'); +const ctx = vm.createContext(); + +// Test strict mode inside a vm script, i.e., using an undefined variable +// throws a ReferenceError. Also check that variables +// that are not successfully set in the vm, must not be set +// on the sandboxed context. + +vm.runInContext('w = 1;', ctx); +assert.strictEqual(1, ctx.w); + +assert.throws(function() { vm.runInContext('"use strict"; x = 1;', ctx); }, + /ReferenceError: x is not defined/); +assert.strictEqual(undefined, ctx.x); + +vm.runInContext('"use strict"; var y = 1;', ctx); +assert.strictEqual(1, ctx.y); + +vm.runInContext('"use strict"; this.z = 1;', ctx); +assert.strictEqual(1, ctx.z); + +// w has been defined +vm.runInContext('"use strict"; w = 2;', ctx); +assert.strictEqual(2, ctx.w); diff --git a/test/pummel/test-timer-wrap.js b/test/pummel/test-timer-wrap.js index b71a72f4256..659912d1fc2 100644 --- a/test/pummel/test-timer-wrap.js +++ b/test/pummel/test-timer-wrap.js @@ -6,7 +6,7 @@ var kOnTimeout = Timer.kOnTimeout; var t = new Timer(); -t.start(1000, 0); +t.start(1000); t[kOnTimeout] = common.mustCall(function() { console.log('timeout'); diff --git a/test/sequential/test-deprecation-flags.js b/test/sequential/test-deprecation-flags.js index bbb5ecb7002..0858e685858 100644 --- a/test/sequential/test-deprecation-flags.js +++ b/test/sequential/test-deprecation-flags.js @@ -5,8 +5,14 @@ const execFile = require('child_process').execFile; const depmod = require.resolve(common.fixturesDir + '/deprecated.js'); const node = process.execPath; -const depUserland = - require.resolve(common.fixturesDir + '/deprecated-userland-function.js'); +const depUserlandFunction = + require.resolve(common.fixturesDir + '/deprecated-userland-function.js'); + +const depUserlandClass = + require.resolve(common.fixturesDir + '/deprecated-userland-class.js'); + +const depUserlandSubClass = + require.resolve(common.fixturesDir + '/deprecated-userland-subclass.js'); const normal = [depmod]; const noDep = ['--no-deprecation', depmod]; @@ -24,7 +30,7 @@ execFile(node, noDep, function(er, stdout, stderr) { console.error('--no-deprecation: silence deprecations'); assert.equal(er, null); assert.equal(stdout, ''); - assert.equal(stderr, 'DEBUG: This is deprecated\n'); + assert.equal(stderr, 'DEBUG: This is deprecated\r\n'); console.log('silent ok'); }); @@ -32,17 +38,29 @@ execFile(node, traceDep, function(er, stdout, stderr) { console.error('--trace-deprecation: show stack'); assert.equal(er, null); assert.equal(stdout, ''); - var stack = stderr.trim().split('\n'); + var stack = stderr.trim().split('\r\n'); // just check the top and bottom. assert(/util.debug is deprecated. Use console.error instead./.test(stack[1])); assert(/DEBUG: This is deprecated/.test(stack[0])); console.log('trace ok'); }); -execFile(node, [depUserland], function(er, stdout, stderr) { +execFile(node, [depUserlandFunction], function(er, stdout, stderr) { console.error('normal: testing deprecated userland function'); assert.equal(er, null); assert.equal(stdout, ''); assert(/deprecatedFunction is deprecated/.test(stderr)); console.error('normal: ok'); }); + +execFile(node, [depUserlandClass], function(er, stdout, stderr) { + assert.strictEqual(er, null); + assert.strictEqual(stdout, ''); + assert(/deprecatedClass is deprecated/.test(stderr)); +}); + +execFile(node, [depUserlandSubClass], function(er, stdout, stderr) { + assert.strictEqual(er, null); + assert.strictEqual(stdout, ''); + assert(/deprecatedClass is deprecated/.test(stderr)); +}); diff --git a/test/timers/test-timers-reliability.js b/test/timers/test-timers-reliability.js index 6d0676dcd81..0626c458267 100644 --- a/test/timers/test-timers-reliability.js +++ b/test/timers/test-timers-reliability.js @@ -42,7 +42,7 @@ monoTimer[Timer.kOnTimeout] = function() { assert(intervalFired); }; -monoTimer.start(300, 0); +monoTimer.start(300); setTimeout(function() { timerFired = true; diff --git a/tools/doc/README.md b/tools/doc/README.md index 1620d6c25ac..e472c712dc0 100644 --- a/tools/doc/README.md +++ b/tools/doc/README.md @@ -10,7 +10,7 @@ Each type of heading has a description block. added: v0.10.0 --> - Stability: 3 - Stable + > Stability: 3 - Stable description and examples. diff --git a/tools/doc/html.js b/tools/doc/html.js index 769d601e26c..30bc3b5caae 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -118,7 +118,7 @@ function render(opts, cb) { template = template.replace(/__ID__/g, id); template = template.replace(/__FILENAME__/g, filename); - template = template.replace(/__SECTION__/g, section); + template = template.replace(/__SECTION__/g, section || 'Index'); template = template.replace(/__VERSION__/g, nodeVersion); template = template.replace(/__TOC__/g, toc); template = template.replace( @@ -150,15 +150,31 @@ function parseText(lexed) { // lists that come right after a heading are what we're after. function parseLists(input) { var state = null; + var savedState = []; var depth = 0; var output = []; output.links = input.links; input.forEach(function(tok) { - if (tok.type === 'code' && tok.text.match(/Stability:.*/g)) { - tok.text = parseAPIHeader(tok.text); - output.push({ type: 'html', text: tok.text }); + if (tok.type === 'blockquote_start') { + savedState.push(state); + state = 'MAYBE_STABILITY_BQ'; return; } + if (tok.type === 'blockquote_end' && state === 'MAYBE_STABILITY_BQ') { + state = savedState.pop(); + return; + } + if ((tok.type === 'paragraph' && state === 'MAYBE_STABILITY_BQ') || + tok.type === 'code') { + if (tok.text.match(/Stability:.*/g)) { + tok.text = parseAPIHeader(tok.text); + output.push({ type: 'html', text: tok.text }); + return; + } else if (state === 'MAYBE_STABILITY_BQ') { + output.push({ type: 'blockquote_start' }); + state = savedState.pop(); + } + } if (state === null || (state === 'AFTERHEADING' && tok.type === 'heading')) { if (tok.type === 'heading') { diff --git a/tools/doc/json.js b/tools/doc/json.js index 33bde6515b1..f5bce301056 100644 --- a/tools/doc/json.js +++ b/tools/doc/json.js @@ -82,19 +82,19 @@ function doJSON(input, filename, cb) { // Immediately after a heading, we can expect the following // - // { type: 'code', text: 'Stability: ...' }, + // { type: 'blockquote_start' } + // { type: 'paragraph', text: 'Stability: ...' }, + // { type: 'blockquote_end' } // // a list: starting with list_start, ending with list_end, // maybe containing other nested lists in each item. // - // If one of these isnt' found, then anything that comes between + // If one of these isn't found, then anything that comes between // here and the next heading should be parsed as the desc. var stability; if (state === 'AFTERHEADING') { - if (type === 'code' && - (stability = text.match(/^Stability: ([0-5])(?:\s*-\s*)?(.*)$/))) { - current.stability = parseInt(stability[1], 10); - current.stabilityText = stability[2].trim(); + if (type === 'blockquote_start') { + state = 'AFTERHEADING_BLOCKQUOTE'; return; } else if (type === 'list_start' && !tok.ordered) { state = 'AFTERHEADING_LIST'; @@ -129,6 +129,20 @@ function doJSON(input, filename, cb) { return; } + if (state === 'AFTERHEADING_BLOCKQUOTE') { + if (type === 'blockquote_end') { + state = 'AFTERHEADING'; + return; + } + + if (type === 'paragraph' && + (stability = text.match(/^Stability: ([0-5])(?:\s*-\s*)?(.*)$/))) { + current.stability = parseInt(stability[1], 10); + current.stabilityText = stability[2].trim(); + return; + } + } + current.desc = current.desc || []; current.desc.push(tok); diff --git a/tools/eslint/README.md b/tools/eslint/README.md index 5493563c4e3..8ba9eaf0b5f 100644 --- a/tools/eslint/README.md +++ b/tools/eslint/README.md @@ -126,9 +126,6 @@ These folks keep the project moving and are resources for help. * Henry Zhu ([@hzoo](https://github.com/hzoo)) * Marat Dulin ([@mdevils](https://github.com/mdevils)) * Alexej Yaroshevich ([@zxqfox](https://github.com/zxqfox)) - -### Issues Team - * Kevin Partington ([@platinumazure](https://github.com/platinumazure)) * Vitor Balocco ([@vitorbal](https://github.com/vitorbal)) @@ -169,6 +166,8 @@ ESLint follows [semantic versioning](http://semver.org). However, due to the nat * An existing formatter is removed. * Part of the public API is removed or changed in an incompatible way. +According to our policy, any minor update may report more errors than the previous release (ex: from a bug fix). As such, we recommend using the tilde (`~`) in `package.json` e.g. `"eslint": "~3.1.0"` to guarantee the results of your builds. + ## Frequently Asked Questions ### How is ESLint different from JSHint? @@ -187,7 +186,10 @@ Yes. Since we are solving the same problems, ESLint and JSCS teams have decided ### So, should I stop using JSCS and start using ESLint? -Not yet. We are still working to smooth the transition. You can see our progress [here](https://github.com/eslint/eslint/milestones/JSCS%20Compatibility). We’ll announce when all of the changes necessary to support JSCS users in ESLint are complete and will start encouraging JSCS users to switch to ESLint at that time. Meanwhile, we recommend you to upgrade to JSCS 3.0 and provide feedback to the team. +Maybe, depending on how much you need it. [JSCS has reached end of life](http://eslint.org/blog/2016/07/jscs-end-of-life), but if it is working for you then there is no reason to move yet. We are still working to smooth the transition. You can see our progress [here](https://github.com/eslint/eslint/milestones/JSCS%20Compatibility). We’ll announce when all of the changes necessary to support JSCS users in ESLint are complete and will start encouraging JSCS users to switch to ESLint at that time. + +If you are having issues with JSCS, you can try to move to ESLint. We are focusing our time and energy on JSCS compatibility issues. + ### Is ESLint just linting or does it also check style? diff --git a/tools/eslint/bin/eslint.js b/tools/eslint/bin/eslint.js deleted file mode 100755 index e03ab6f426e..00000000000 --- a/tools/eslint/bin/eslint.js +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env node - -/** - * @fileoverview Main CLI that is run via the eslint command. - * @author Nicholas C. Zakas - */ - -"use strict"; - -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -var exitCode = 0, - useStdIn = (process.argv.indexOf("--stdin") > -1), - init = (process.argv.indexOf("--init") > -1), - debug = (process.argv.indexOf("--debug") > -1); - -// must do this initialization *before* other requires in order to work -if (debug) { - require("debug").enable("eslint:*,-eslint:code-path"); -} - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -// now we can safely include the other modules that use debug -var concat = require("concat-stream"), - cli = require("../lib/cli"), - path = require("path"), - fs = require("fs"); - -//------------------------------------------------------------------------------ -// Execution -//------------------------------------------------------------------------------ - -process.on("uncaughtException", function(err){ - // lazy load - var lodash = require("lodash"); - - if (typeof err.messageTemplate === "string" && err.messageTemplate.length > 0) { - var template = lodash.template(fs.readFileSync(path.resolve(__dirname, "../messages/" + err.messageTemplate + ".txt"), "utf-8")); - - console.log("\nOops! Something went wrong! :("); - console.log("\n" + template(err.messageData || {})); - } else { - console.log(err.message); - console.log(err.stack); - } - - process.exit(1); -}); - -if (useStdIn) { - process.stdin.pipe(concat({ encoding: "string" }, function(text) { - try { - exitCode = cli.execute(process.argv, text); - } catch (ex) { - console.error(ex.message); - console.error(ex.stack); - exitCode = 1; - } - })); -} else if (init) { - var configInit = require("../lib/config/config-initializer"); - configInit.initializeConfig(function(err) { - if (err) { - exitCode = 1; - console.error(err.message); - console.error(err.stack); - } else { - exitCode = 0; - } - }); -} else { - exitCode = cli.execute(process.argv); -} - -process.exitCode = exitCode; diff --git a/tools/eslint/conf/category-list.json b/tools/eslint/conf/category-list.json new file mode 100644 index 00000000000..d7e84b6c15f --- /dev/null +++ b/tools/eslint/conf/category-list.json @@ -0,0 +1,35 @@ +{ + "categories": [ + { "name": "Possible Errors", "description": "These rules relate to possible syntax or logic errors in JavaScript code:" }, + { "name": "Best Practices", "description": "These rules relate to better ways of doing things to help you avoid problems:" }, + { "name": "Strict Mode", "description": "These rules relate to strict mode directives:" }, + { "name": "Variables", "description": "These rules relate to variable declarations:" }, + { "name": "Node.js and CommonJS", "description": "These rules relate to code running in Node.js, or in browsers with CommonJS:" }, + { "name": "Stylistic Issues", "description": "These rules relate to style guidelines, and are therefore quite subjective:" }, + { "name": "ECMAScript 6", "description": "These rules relate to ES6, also known as ES2015:" } + ], + "removed": { + "name": "Removed", + "description": "These rules from older versions of ESLint have been replaced by newer rules:", + "rules": [ + { "removed": "generator-star", "replacedBy": ["generator-star-spacing"] }, + { "removed": "global-strict", "replacedBy": ["strict"] }, + { "removed": "no-arrow-condition", "replacedBy": ["no-confusing-arrow", "no-constant-condition"] }, + { "removed": "no-comma-dangle", "replacedBy": ["comma-dangle"] }, + { "removed": "no-empty-class", "replacedBy": ["no-empty-character-class"] }, + { "removed": "no-empty-label", "replacedBy": ["no-labels"] }, + { "removed": "no-extra-strict", "replacedBy": ["strict"] }, + { "removed": "no-reserved-keys", "replacedBy": ["quote-props"] }, + { "removed": "no-space-before-semi", "replacedBy": ["semi-spacing"] }, + { "removed": "no-wrap-func", "replacedBy": ["no-extra-parens"] }, + { "removed": "space-after-function-name", "replacedBy": ["space-before-function-paren"] }, + { "removed": "space-after-keywords", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-before-function-parentheses", "replacedBy": ["space-before-function-paren"] }, + { "removed": "space-before-keywords", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] }, + { "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] }, + { "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] }, + { "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] } + ] + } +} \ No newline at end of file diff --git a/tools/eslint/conf/environments.js b/tools/eslint/conf/environments.js index ee76503827c..d938a6cfaa9 100644 --- a/tools/eslint/conf/environments.js +++ b/tools/eslint/conf/environments.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var globals = require("globals"); +let globals = require("globals"); //------------------------------------------------------------------------------ // Public Interface diff --git a/tools/eslint/conf/eslint-all.js b/tools/eslint/conf/eslint-all.js index 8740e8c07d4..53d5cdb82d8 100644 --- a/tools/eslint/conf/eslint-all.js +++ b/tools/eslint/conf/eslint-all.js @@ -9,16 +9,18 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var ruleFiles = fs.readdirSync(path.resolve(__dirname, "../lib/rules")); -var enabledRules = ruleFiles.reduce(function(result, filename) { - result[path.basename(filename, ".js")] = "error"; +let ruleFiles = fs.readdirSync(path.resolve(__dirname, "../lib/rules")); +let enabledRules = ruleFiles.reduce(function(result, filename) { + if (path.extname(filename) === ".js") { + result[path.basename(filename, ".js")] = "error"; + } return result; }, {}); diff --git a/tools/eslint/conf/eslint.json b/tools/eslint/conf/eslint.json index 94317bcd89a..53b2e755906 100644 --- a/tools/eslint/conf/eslint.json +++ b/tools/eslint/conf/eslint.json @@ -99,6 +99,7 @@ "no-spaced-func": "off", "no-sparse-arrays": "error", "no-sync": "off", + "no-tabs": "off", "no-ternary": "off", "no-trailing-spaces": "off", "no-this-before-super": "error", @@ -174,6 +175,7 @@ "max-params": "off", "max-statements": "off", "max-statements-per-line": "off", + "multiline-ternary": "off", "new-cap": "off", "new-parens": "off", "newline-after-var": "off", diff --git a/tools/eslint/lib/ast-utils.js b/tools/eslint/lib/ast-utils.js index c8d6dcb4915..881cc26c5f0 100644 --- a/tools/eslint/lib/ast-utils.js +++ b/tools/eslint/lib/ast-utils.js @@ -9,18 +9,19 @@ // Requirements //------------------------------------------------------------------------------ -var esutils = require("esutils"); +let esutils = require("esutils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/; -var arrayOrTypedArrayPattern = /Array$/; -var arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/; -var bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/; -var breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/; -var thisTagPattern = /^[\s\*]*@this/m; +let anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/; +let anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/; +let arrayOrTypedArrayPattern = /Array$/; +let arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/; +let bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/; +let breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/; +let thisTagPattern = /^[\s\*]*@this/m; /** * Checks reference if is non initializer and writable. @@ -31,7 +32,7 @@ var thisTagPattern = /^[\s\*]*@this/m; * @private */ function isModifyingReference(reference, index, references) { - var identifier = reference.identifier, + let identifier = reference.identifier, modifyingDifferentIdentifier; /* @@ -159,7 +160,7 @@ function isMethodWhichHasThisArg(node) { * @returns {boolean} Whether or not the node has a `@this` tag in its comments. */ function hasJSDocThisTag(node, sourceCode) { - var jsdocComment = sourceCode.getJSDocComment(node); + let jsdocComment = sourceCode.getJSDocComment(node); if (jsdocComment && thisTagPattern.test(jsdocComment.value)) { return true; @@ -182,7 +183,7 @@ function hasJSDocThisTag(node, sourceCode) { * @private */ function isParenthesised(sourceCode, node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return Boolean(previousToken && nextToken) && @@ -284,7 +285,7 @@ module.exports = { * @returns {boolean} `true` if the node is an ESLint directive comment */ isDirectiveComment: function(node) { - var comment = node.value.trim(); + let comment = node.value.trim(); return ( node.type === "Line" && comment.indexOf("eslint-") === 0 || @@ -317,10 +318,10 @@ module.exports = { * @returns {escope.Variable|null} A found variable or `null`. */ getVariableByName: function(initScope, name) { - var scope = initScope; + let scope = initScope; while (scope) { - var variable = scope.set.get(name); + let variable = scope.set.get(name); if (variable) { return variable; @@ -359,7 +360,7 @@ module.exports = { } while (node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { @@ -378,14 +379,15 @@ module.exports = { // // setup... // return function foo() { ... }; // })(); - case "ReturnStatement": - var func = getUpperFunction(parent); + case "ReturnStatement": { + const func = getUpperFunction(parent); if (func === null || !isCallee(func)) { return true; } node = func.parent; break; + } // e.g. // var obj = { foo() { ... } }; @@ -551,5 +553,37 @@ module.exports = { // no default } return 18; + }, + + /** + * Checks whether a given node is a loop node or not. + * The following types are loop nodes: + * + * - DoWhileStatement + * - ForInStatement + * - ForOfStatement + * - ForStatement + * - WhileStatement + * + * @param {ASTNode|null} node - A node to check. + * @returns {boolean} `true` if the node is a loop node. + */ + isLoop: function(node) { + return Boolean(node && anyLoopPattern.test(node.type)); + }, + + /** + * Checks whether a given node is a function node or not. + * The following types are function nodes: + * + * - ArrowFunctionExpression + * - FunctionDeclaration + * - FunctionExpression + * + * @param {ASTNode|null} node - A node to check. + * @returns {boolean} `true` if the node is a function node. + */ + isFunction: function(node) { + return Boolean(node && anyFunctionPattern.test(node.type)); } }; diff --git a/tools/eslint/lib/cli-engine.js b/tools/eslint/lib/cli-engine.js index 410fd7f3674..cf28aa1d592 100644 --- a/tools/eslint/lib/cli-engine.js +++ b/tools/eslint/lib/cli-engine.js @@ -15,7 +15,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"), lodash = require("lodash"), @@ -44,16 +44,25 @@ var fs = require("fs"), /** * The options to configure a CLI engine with. * @typedef {Object} CLIEngineOptions + * @property {boolean} allowInlineConfig Enable or disable inline configuration comments. + * @property {boolean|Object} baseConfig Base config object. True enables recommend rules and environments. + * @property {boolean} cache Enable result caching. + * @property {string} cacheLocation The cache file to use instead of .eslintcache. * @property {string} configFile The configuration file to use. - * @property {boolean|object} baseConfig Base config object. True enables recommend rules and environments. - * @property {boolean} ignore False disables use of .eslintignore. - * @property {string[]} rulePaths An array of directories to load custom rules from. - * @property {boolean} useEslintrc False disables looking for .eslintrc + * @property {string} cwd The value to use for the current working directory. * @property {string[]} envs An array of environments to load. - * @property {string[]} globals An array of global variables to declare. * @property {string[]} extensions An array of file extensions to check. - * @property {Object} rules An object of rules to use. + * @property {boolean} fix Execute in autofix mode. + * @property {string[]} globals An array of global variables to declare. + * @property {boolean} ignore False disables use of .eslintignore. * @property {string} ignorePath The ignore file to use instead of .eslintignore. + * @property {string} ignorePattern A glob pattern of files to ignore. + * @property {boolean} useEslintrc False disables looking for .eslintrc + * @property {string} parser The name of the parser to use. + * @property {Object} parserOptions An object of parserOption settings to use. + * @property {string[]} plugins An array of plugins to load. + * @property {Object} rules An object of rules to use. + * @property {string[]} rulePaths An array of directories to load custom rules from. */ /** @@ -129,7 +138,7 @@ function calculateStatsPerRun(results) { */ function multipassFix(text, config, options) { - var messages = [], + let messages = [], fixedResult, fixed = false, passNumber = 0, @@ -203,7 +212,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { // clear all existing settings for a new file eslint.reset(); - var filePath, + let filePath, config, messages, stats, @@ -227,7 +236,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { loadedPlugins = Plugins.getAll(); - for (var plugin in loadedPlugins) { + for (let plugin in loadedPlugins) { if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) { processor = loadedPlugins[plugin].processors[fileExtension]; break; @@ -236,8 +245,8 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { if (processor) { debug("Using processor"); - var parsedBlocks = processor.preprocess(text, filename); - var unprocessedMessages = []; + let parsedBlocks = processor.preprocess(text, filename); + let unprocessedMessages = []; parsedBlocks.forEach(function(block) { unprocessedMessages.push(eslint.verify(block, config, { @@ -268,7 +277,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { stats = calculateStatsPerFile(messages); - var result = { + let result = { filePath: filename, messages: messages, errorCount: stats.errorCount, @@ -293,7 +302,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) { */ function processFile(filename, configHelper, options) { - var text = fs.readFileSync(path.resolve(filename), "utf8"), + let text = fs.readFileSync(path.resolve(filename), "utf8"), result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig); return result; @@ -308,10 +317,10 @@ function processFile(filename, configHelper, options) { * @private */ function createIgnoreResult(filePath, baseDir) { - var message; - var isHidden = /^\./.test(path.basename(filePath)); - var isInNodeModules = baseDir && /^node_modules/.test(path.relative(baseDir, filePath)); - var isInBowerComponents = baseDir && /^bower_components/.test(path.relative(baseDir, filePath)); + let message; + let isHidden = /^\./.test(path.basename(filePath)); + let isInNodeModules = baseDir && /^node_modules/.test(path.relative(baseDir, filePath)); + let isInBowerComponents = baseDir && /^bower_components/.test(path.relative(baseDir, filePath)); if (isHidden) { message = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern \'!\'\") to override."; @@ -340,7 +349,7 @@ function createIgnoreResult(filePath, baseDir) { /** * Checks if the given message is an error message. - * @param {object} message The message to check. + * @param {Object} message The message to check. * @returns {boolean} Whether or not the message is an error message. * @private */ @@ -368,8 +377,8 @@ function getCacheFile(cacheFile, cwd) { */ cacheFile = path.normalize(cacheFile); - var resolvedCacheFile = path.resolve(cwd, cacheFile); - var looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep; + let resolvedCacheFile = path.resolve(cwd, cacheFile); + let looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep; /** * return the name for the cache file in case the provided parameter is a directory @@ -379,7 +388,7 @@ function getCacheFile(cacheFile, cwd) { return path.join(resolvedCacheFile, ".cache_" + hash(cwd)); } - var fileStats; + let fileStats; try { fileStats = fs.lstatSync(resolvedCacheFile); @@ -446,7 +455,7 @@ function CLIEngine(options) { */ this.options = options; - var cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd); + let cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd); /** * Cache used to avoid operating on files that haven't changed since the @@ -458,7 +467,7 @@ function CLIEngine(options) { // load in additional rules if (this.options.rulePaths) { - var cwd = this.options.cwd; + let cwd = this.options.cwd; this.options.rulePaths.forEach(function(rulesdir) { debug("Loading rules from " + rulesdir); @@ -480,7 +489,7 @@ function CLIEngine(options) { */ CLIEngine.getFormatter = function(format) { - var formatterPath; + let formatterPath; // default is stylish format = format || "stylish"; @@ -493,7 +502,7 @@ CLIEngine.getFormatter = function(format) { // if there's a slash, then it's a file if (format.indexOf("/") > -1) { - var cwd = this.options ? this.options.cwd : process.cwd(); + let cwd = this.options ? this.options.cwd : process.cwd(); formatterPath = path.resolve(cwd, format); } else { @@ -518,10 +527,10 @@ CLIEngine.getFormatter = function(format) { * @returns {LintResult[]} The filtered results. */ CLIEngine.getErrorResults = function(results) { - var filtered = []; + let filtered = []; results.forEach(function(result) { - var filteredMessages = result.messages.filter(isErrorMessage); + let filteredMessages = result.messages.filter(isErrorMessage); if (filteredMessages.length > 0) { filtered.push({ @@ -579,7 +588,7 @@ CLIEngine.prototype = { * @returns {Object} The results for all files that were linted. */ executeOnFiles: function(patterns) { - var results = [], + let results = [], options = this.options, fileCache = this._fileCache, configHelper = new Config(options), @@ -594,7 +603,7 @@ CLIEngine.prototype = { * @returns {string} the hash of the config */ function hashOfConfigFor(filename) { - var config = configHelper.getConfig(filename); + let config = configHelper.getConfig(filename); if (!prevConfig) { prevConfig = {}; @@ -609,7 +618,7 @@ CLIEngine.prototype = { */ prevConfig.config = config; - var eslintVersion = pkg.version; + let eslintVersion = pkg.version; prevConfig.hash = hash(eslintVersion + "_" + stringify(config)); } @@ -625,7 +634,8 @@ CLIEngine.prototype = { * @returns {void} */ function executeOnFile(filename, warnIgnored) { - var hashOfConfig; + let hashOfConfig, + descriptor; if (warnIgnored) { results.push(createIgnoreResult(filename, options.cwd)); @@ -639,12 +649,12 @@ CLIEngine.prototype = { * with the metadata and the flag that determines if * the file has changed */ - var descriptor = fileCache.getFileDescriptor(filename); - var meta = descriptor.meta || {}; + descriptor = fileCache.getFileDescriptor(filename); + let meta = descriptor.meta || {}; hashOfConfig = hashOfConfigFor(filename); - var changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig; + let changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig; if (!changed) { debug("Skipping file since hasn't changed: " + filename); @@ -666,7 +676,7 @@ CLIEngine.prototype = { debug("Processing " + filename); - var res = processFile(filename, configHelper, options); + let res = processFile(filename, configHelper, options); if (options.cache) { @@ -732,7 +742,7 @@ CLIEngine.prototype = { */ executeOnText: function(text, filename, warnIgnored) { - var results = [], + let results = [], stats, options = this.options, configHelper = new Config(options), @@ -742,8 +752,11 @@ CLIEngine.prototype = { if (filename && !path.isAbsolute(filename)) { filename = path.resolve(options.cwd, filename); } - if (filename && warnIgnored && ignoredPaths.contains(filename)) { - results.push(createIgnoreResult(filename, options.cwd)); + + if (filename && ignoredPaths.contains(filename)) { + if (warnIgnored) { + results.push(createIgnoreResult(filename, options.cwd)); + } } else { results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig)); } @@ -765,7 +778,7 @@ CLIEngine.prototype = { * @returns {Object} A configuration object for the file. */ getConfigForFile: function(filePath) { - var configHelper = new Config(this.options); + let configHelper = new Config(this.options); return configHelper.getConfig(filePath); }, @@ -776,8 +789,8 @@ CLIEngine.prototype = { * @returns {boolean} Whether or not the given path is ignored. */ isPathIgnored: function(filePath) { - var ignoredPaths; - var resolvedPath = path.resolve(this.options.cwd, filePath); + let ignoredPaths; + let resolvedPath = path.resolve(this.options.cwd, filePath); ignoredPaths = new IgnoredPaths(this.options); return ignoredPaths.contains(resolvedPath); diff --git a/tools/eslint/lib/cli.js b/tools/eslint/lib/cli.js index 887c3c7671f..b8bbda4cae8 100644 --- a/tools/eslint/lib/cli.js +++ b/tools/eslint/lib/cli.js @@ -15,7 +15,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"), debug = require("debug"), @@ -70,7 +70,7 @@ function translateOptions(cliOptions) { * @private */ function printResults(engine, results, format, outputFile) { - var formatter, + let formatter, output, filePath; @@ -116,7 +116,7 @@ function printResults(engine, results, format, outputFile) { * Encapsulates all CLI behavior for eslint. Makes it easier to test as well as * for other Node.js programs to effectively run the CLI. */ -var cli = { +let cli = { /** * Executes the CLI based on an array of arguments that is passed in. @@ -126,7 +126,7 @@ var cli = { */ execute: function(args, text) { - var currentOptions, + let currentOptions, files, report, engine, @@ -172,7 +172,7 @@ var cli = { return 1; } - var fileConfig = engine.getConfigForFile(files[0]); + let fileConfig = engine.getConfigForFile(files[0]); log.info(JSON.stringify(fileConfig, null, " ")); return 0; diff --git a/tools/eslint/lib/code-path-analysis/code-path-analyzer.js b/tools/eslint/lib/code-path-analysis/code-path-analyzer.js index 4e55cccee64..00db3064dc4 100644 --- a/tools/eslint/lib/code-path-analysis/code-path-analyzer.js +++ b/tools/eslint/lib/code-path-analysis/code-path-analyzer.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"), +let assert = require("assert"), CodePath = require("./code-path"), CodePathSegment = require("./code-path-segment"), IdGenerator = require("./id-generator"), @@ -38,7 +38,7 @@ function isCaseNode(node) { * @returns {boolean} `true` if the node is a test of a choice statement. */ function isForkingByTrueOrFalse(node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { case "ConditionalExpression": @@ -83,7 +83,7 @@ function getBooleanValueIfSimpleConstant(node) { * @returns {boolean} `true` if the node is a reference. */ function isIdentifierReference(node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { case "LabeledStatement": @@ -135,12 +135,12 @@ function isIdentifierReference(node) { * @returns {void} */ function forwardCurrentToHead(analyzer, node) { - var codePath = analyzer.codePath; - var state = CodePath.getState(codePath); - var currentSegments = state.currentSegments; - var headSegments = state.headSegments; - var end = Math.max(currentSegments.length, headSegments.length); - var i, currentSegment, headSegment; + let codePath = analyzer.codePath; + let state = CodePath.getState(codePath); + let currentSegments = state.currentSegments; + let headSegments = state.headSegments; + let end = Math.max(currentSegments.length, headSegments.length); + let i, currentSegment, headSegment; // Fires leaving events. for (i = 0; i < end; ++i) { @@ -191,11 +191,11 @@ function forwardCurrentToHead(analyzer, node) { * @returns {void} */ function leaveFromCurrentSegment(analyzer, node) { - var state = CodePath.getState(analyzer.codePath); - var currentSegments = state.currentSegments; + let state = CodePath.getState(analyzer.codePath); + let currentSegments = state.currentSegments; - for (var i = 0; i < currentSegments.length; ++i) { - var currentSegment = currentSegments[i]; + for (let i = 0; i < currentSegments.length; ++i) { + let currentSegment = currentSegments[i]; debug.dump("onCodePathSegmentEnd " + currentSegment.id); if (currentSegment.reachable) { @@ -221,9 +221,9 @@ function leaveFromCurrentSegment(analyzer, node) { * @returns {void} */ function preprocess(analyzer, node) { - var codePath = analyzer.codePath; - var state = CodePath.getState(codePath); - var parent = node.parent; + let codePath = analyzer.codePath; + let state = CodePath.getState(codePath); + let parent = node.parent; switch (parent.type) { case "LogicalExpression": @@ -328,9 +328,9 @@ function preprocess(analyzer, node) { * @returns {void} */ function processCodePathToEnter(analyzer, node) { - var codePath = analyzer.codePath; - var state = codePath && CodePath.getState(codePath); - var parent = node.parent; + let codePath = analyzer.codePath; + let state = codePath && CodePath.getState(codePath); + let parent = node.parent; switch (node.type) { case "Program": @@ -419,9 +419,9 @@ function processCodePathToEnter(analyzer, node) { * @returns {void} */ function processCodePathToExit(analyzer, node) { - var codePath = analyzer.codePath; - var state = CodePath.getState(codePath); - var dontForward = false; + let codePath = analyzer.codePath; + let state = CodePath.getState(codePath); + let dontForward = false; switch (node.type) { case "IfStatement": @@ -536,8 +536,8 @@ function postprocess(analyzer, node) { case "Program": case "FunctionDeclaration": case "FunctionExpression": - case "ArrowFunctionExpression": - var codePath = analyzer.codePath; + case "ArrowFunctionExpression": { + let codePath = analyzer.codePath; // Mark the current path as the final node. CodePath.getState(codePath).makeFinal(); @@ -555,6 +555,7 @@ function postprocess(analyzer, node) { debug.dumpState(node, CodePath.getState(codePath), true); } break; + } default: break; diff --git a/tools/eslint/lib/code-path-analysis/code-path-segment.js b/tools/eslint/lib/code-path-analysis/code-path-segment.js index d5361ccd074..544a9da2784 100644 --- a/tools/eslint/lib/code-path-analysis/code-path-segment.js +++ b/tools/eslint/lib/code-path-analysis/code-path-segment.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("./debug-helpers"); +let debug = require("./debug-helpers"); //------------------------------------------------------------------------------ // Helpers @@ -22,11 +22,11 @@ var debug = require("./debug-helpers"); * @returns {CodePathSegment[]} The replaced array. */ function flattenUnusedSegments(segments) { - var done = Object.create(null); - var retv = []; + let done = Object.create(null); + let retv = []; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; // Ignores duplicated. if (done[segment.id]) { @@ -35,8 +35,8 @@ function flattenUnusedSegments(segments) { // Use previous segments if unused. if (!segment.internal.used) { - for (var j = 0; j < segment.allPrevSegments.length; ++j) { - var prevSegment = segment.allPrevSegments[j]; + for (let j = 0; j < segment.allPrevSegments.length; ++j) { + let prevSegment = segment.allPrevSegments[j]; if (!done[prevSegment.id]) { done[prevSegment.id] = true; @@ -175,7 +175,7 @@ CodePathSegment.newNext = function(id, allPrevSegments) { * @returns {CodePathSegment} The created segment. */ CodePathSegment.newUnreachable = function(id, allPrevSegments) { - var segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false); + let segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false); // In `if (a) return a; foo();` case, the unreachable segment preceded by // the return statement is not used but must not be remove. @@ -211,11 +211,11 @@ CodePathSegment.markUsed = function(segment) { } segment.internal.used = true; - var i; + let i; if (segment.reachable) { for (i = 0; i < segment.allPrevSegments.length; ++i) { - var prevSegment = segment.allPrevSegments[i]; + let prevSegment = segment.allPrevSegments[i]; prevSegment.allNextSegments.push(segment); prevSegment.nextSegments.push(segment); diff --git a/tools/eslint/lib/code-path-analysis/code-path-state.js b/tools/eslint/lib/code-path-analysis/code-path-state.js index 0492d832c2c..7c3d4a35e62 100644 --- a/tools/eslint/lib/code-path-analysis/code-path-state.js +++ b/tools/eslint/lib/code-path-analysis/code-path-state.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var CodePathSegment = require("./code-path-segment"), +let CodePathSegment = require("./code-path-segment"), ForkContext = require("./fork-context"); //------------------------------------------------------------------------------ @@ -30,8 +30,8 @@ var CodePathSegment = require("./code-path-segment"), * @returns {void} */ function addToReturnedOrThrown(dest, others, all, segments) { - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; dest.push(segment); if (others.indexOf(segment) === -1) { @@ -52,7 +52,7 @@ function getContinueContext(state, label) { return state.loopContext; } - var context = state.loopContext; + let context = state.loopContext; while (context) { if (context.label === label) { @@ -73,7 +73,7 @@ function getContinueContext(state, label) { * @returns {LoopContext|SwitchContext} A context for a `break` statement. */ function getBreakContext(state, label) { - var context = state.breakContext; + let context = state.breakContext; while (context) { if (label ? context.label === label : context.breakable) { @@ -93,7 +93,7 @@ function getBreakContext(state, label) { * @returns {TryContext|CodePathState} A context for a `return` statement. */ function getReturnContext(state) { - var context = state.tryContext; + let context = state.tryContext; while (context) { if (context.hasFinalizer && context.position !== "finally") { @@ -112,7 +112,7 @@ function getReturnContext(state) { * @returns {TryContext|CodePathState} A context for a `throw` statement. */ function getThrowContext(state) { - var context = state.tryContext; + let context = state.tryContext; while (context) { if (context.position === "try" || @@ -149,9 +149,9 @@ function remove(xs, x) { * @returns {void} */ function removeConnection(prevSegments, nextSegments) { - for (var i = 0; i < prevSegments.length; ++i) { - var prevSegment = prevSegments[i]; - var nextSegment = nextSegments[i]; + for (let i = 0; i < prevSegments.length; ++i) { + let prevSegment = prevSegments[i]; + let nextSegment = nextSegments[i]; remove(prevSegment.nextSegments, nextSegment); remove(prevSegment.allNextSegments, nextSegment); @@ -169,11 +169,11 @@ function removeConnection(prevSegments, nextSegments) { * @returns {void} */ function makeLooped(state, fromSegments, toSegments) { - var end = Math.min(fromSegments.length, toSegments.length); + let end = Math.min(fromSegments.length, toSegments.length); - for (var i = 0; i < end; ++i) { - var fromSegment = fromSegments[i]; - var toSegment = toSegments[i]; + for (let i = 0; i < end; ++i) { + let fromSegment = fromSegments[i]; + let toSegment = toSegments[i]; if (toSegment.reachable) { fromSegment.nextSegments.push(toSegment); @@ -225,7 +225,7 @@ function finalizeTestSegmentsOfFor(context, choiceContext, head) { * @constructor * @param {IdGenerator} idGenerator - An id generator to generate id for code * path segments. - * @param {function} onLooped - A callback function to notify looping. + * @param {Function} onLooped - A callback function to notify looping. */ function CodePathState(idGenerator, onLooped) { this.idGenerator = idGenerator; @@ -241,9 +241,9 @@ function CodePathState(idGenerator, onLooped) { this.initialSegment = this.forkContext.head[0]; // returnedSegments and thrownSegments push elements into finalSegments also. - var final = this.finalSegments = []; - var returned = this.returnedForkContext = []; - var thrown = this.thrownForkContext = []; + let final = this.finalSegments = []; + let returned = this.returnedForkContext = []; + let thrown = this.thrownForkContext = []; returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final); thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final); @@ -266,7 +266,7 @@ CodePathState.prototype = { * @type {ForkContext} */ get parentForkContext() { - var current = this.forkContext; + let current = this.forkContext; return current && current.upper; }, @@ -292,7 +292,7 @@ CodePathState.prototype = { * @returns {ForkContext} The last context. */ popForkContext: function() { - var lastContext = this.forkContext; + let lastContext = this.forkContext; this.forkContext = lastContext.upper; this.forkContext.replaceHead(lastContext.makeNext(0, -1)); @@ -370,12 +370,12 @@ CodePathState.prototype = { * @returns {ChoiceContext} The popped context. */ popChoiceContext: function() { - var context = this.choiceContext; + let context = this.choiceContext; this.choiceContext = context.upper; - var forkContext = this.forkContext; - var headSegments = forkContext.head; + let forkContext = this.forkContext; + let headSegments = forkContext.head; switch (context.kind) { case "&&": @@ -396,7 +396,7 @@ CodePathState.prototype = { * test chunk. */ if (context.isForkingAsResult) { - var parentContext = this.choiceContext; + let parentContext = this.choiceContext; parentContext.trueForkContext.addAll(context.trueForkContext); parentContext.falseForkContext.addAll(context.falseForkContext); @@ -443,7 +443,7 @@ CodePathState.prototype = { } // Merges all paths. - var prevForkContext = context.trueForkContext; + let prevForkContext = context.trueForkContext; prevForkContext.addAll(context.falseForkContext); forkContext.replaceHead(prevForkContext.makeNext(0, -1)); @@ -458,8 +458,8 @@ CodePathState.prototype = { * @returns {void} */ makeLogicalRight: function() { - var context = this.choiceContext; - var forkContext = this.forkContext; + let context = this.choiceContext; + let forkContext = this.forkContext; if (context.processed) { @@ -467,7 +467,7 @@ CodePathState.prototype = { * This got segments already from the child choice context. * Creates the next path from own true/false fork context. */ - var prevForkContext = + let prevForkContext = context.kind === "&&" ? context.trueForkContext : /* kind === "||" */ context.falseForkContext; @@ -502,8 +502,8 @@ CodePathState.prototype = { * @returns {void} */ makeIfConsequent: function() { - var context = this.choiceContext; - var forkContext = this.forkContext; + let context = this.choiceContext; + let forkContext = this.forkContext; /* * If any result were not transferred from child contexts, @@ -529,8 +529,8 @@ CodePathState.prototype = { * @returns {void} */ makeIfAlternate: function() { - var context = this.choiceContext; - var forkContext = this.forkContext; + let context = this.choiceContext; + let forkContext = this.forkContext; /* * The head segments are the path of the `if` block. @@ -583,12 +583,12 @@ CodePathState.prototype = { * @returns {void} */ popSwitchContext: function() { - var context = this.switchContext; + let context = this.switchContext; this.switchContext = context.upper; - var forkContext = this.forkContext; - var brokenForkContext = this.popBreakContext().brokenForkContext; + let forkContext = this.forkContext; + let brokenForkContext = this.popBreakContext().brokenForkContext; if (context.countForks === 0) { @@ -605,10 +605,10 @@ CodePathState.prototype = { return; } - var lastSegments = forkContext.head; + let lastSegments = forkContext.head; this.forkBypassPath(); - var lastCaseSegments = forkContext.head; + let lastCaseSegments = forkContext.head; /* * `brokenForkContext` is used to make the next segment. @@ -640,7 +640,7 @@ CodePathState.prototype = { } // Pops the segment context stack until the entry segment. - for (var i = 0; i < context.countForks; ++i) { + for (let i = 0; i < context.countForks; ++i) { this.forkContext = this.forkContext.upper; } @@ -659,7 +659,7 @@ CodePathState.prototype = { * @returns {void} */ makeSwitchCaseBody: function(isEmpty, isDefault) { - var context = this.switchContext; + let context = this.switchContext; if (!context.hasCase) { return; @@ -670,8 +670,8 @@ CodePathState.prototype = { * The parent fork context has two segments. * Those are from the current case and the body of the previous case. */ - var parentForkContext = this.forkContext; - var forkContext = this.pushForkContext(); + let parentForkContext = this.forkContext; + let forkContext = this.pushForkContext(); forkContext.add(parentForkContext.makeNext(0, -1)); @@ -731,7 +731,7 @@ CodePathState.prototype = { * @returns {void} */ popTryContext: function() { - var context = this.tryContext; + let context = this.tryContext; this.tryContext = context.upper; @@ -747,19 +747,19 @@ CodePathState.prototype = { * block. */ - var returned = context.returnedForkContext; - var thrown = context.thrownForkContext; + let returned = context.returnedForkContext; + let thrown = context.thrownForkContext; if (returned.empty && thrown.empty) { return; } // Separate head to normal paths and leaving paths. - var headSegments = this.forkContext.head; + let headSegments = this.forkContext.head; this.forkContext = this.forkContext.upper; - var normalSegments = headSegments.slice(0, headSegments.length / 2 | 0); - var leavingSegments = headSegments.slice(headSegments.length / 2 | 0); + let normalSegments = headSegments.slice(0, headSegments.length / 2 | 0); + let leavingSegments = headSegments.slice(headSegments.length / 2 | 0); // Forwards the leaving path to upper contexts. if (!returned.empty) { @@ -785,9 +785,9 @@ CodePathState.prototype = { * @returns {void} */ makeCatchBlock: function() { - var context = this.tryContext; - var forkContext = this.forkContext; - var thrown = context.thrownForkContext; + let context = this.tryContext; + let forkContext = this.forkContext; + let thrown = context.thrownForkContext; // Update state. context.position = "catch"; @@ -796,7 +796,7 @@ CodePathState.prototype = { // Merge thrown paths. thrown.add(forkContext.head); - var thrownSegments = thrown.makeNext(0, -1); + let thrownSegments = thrown.makeNext(0, -1); // Fork to a bypass and the merged thrown path. this.pushForkContext(); @@ -814,11 +814,11 @@ CodePathState.prototype = { * @returns {void} */ makeFinallyBlock: function() { - var context = this.tryContext; - var forkContext = this.forkContext; - var returned = context.returnedForkContext; - var thrown = context.thrownForkContext; - var headOfLeavingSegments = forkContext.head; + let context = this.tryContext; + let forkContext = this.forkContext; + let returned = context.returnedForkContext; + let thrown = context.thrownForkContext; + let headOfLeavingSegments = forkContext.head; // Update state. if (context.position === "catch") { @@ -843,11 +843,11 @@ CodePathState.prototype = { * Create a parallel segment from merging returned and thrown. * This segment will leave at the end of this finally block. */ - var segments = forkContext.makeNext(-1, -1); - var j; + let segments = forkContext.makeNext(-1, -1); + let j; - for (var i = 0; i < forkContext.count; ++i) { - var prevSegsOfLeavingSegment = [headOfLeavingSegments[i]]; + for (let i = 0; i < forkContext.count; ++i) { + let prevSegsOfLeavingSegment = [headOfLeavingSegments[i]]; for (j = 0; j < returned.segmentsList.length; ++j) { prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]); @@ -872,13 +872,13 @@ CodePathState.prototype = { * @returns {void} */ makeFirstThrowablePathInTryBlock: function() { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (!forkContext.reachable) { return; } - var context = getThrowContext(this); + let context = getThrowContext(this); if (context === this || context.position !== "try" || @@ -905,8 +905,8 @@ CodePathState.prototype = { * @returns {void} */ pushLoopContext: function(type, label) { - var forkContext = this.forkContext; - var breakContext = this.pushBreakContext(true, label); + let forkContext = this.forkContext; + let breakContext = this.pushBreakContext(true, label); switch (type) { case "WhileStatement": @@ -977,13 +977,13 @@ CodePathState.prototype = { * @returns {void} */ popLoopContext: function() { - var context = this.loopContext; + let context = this.loopContext; this.loopContext = context.upper; - var forkContext = this.forkContext; - var brokenForkContext = this.popBreakContext().brokenForkContext; - var choiceContext; + let forkContext = this.forkContext; + let brokenForkContext = this.popBreakContext().brokenForkContext; + let choiceContext; // Creates a looped path. switch (context.type) { @@ -996,7 +996,7 @@ CodePathState.prototype = { context.continueDestSegments); break; - case "DoWhileStatement": + case "DoWhileStatement": { choiceContext = this.popChoiceContext(); if (!choiceContext.processed) { @@ -1008,15 +1008,16 @@ CodePathState.prototype = { } // `true` paths go to looping. - var segmentsList = choiceContext.trueForkContext.segmentsList; + const segmentsList = choiceContext.trueForkContext.segmentsList; - for (var i = 0; i < segmentsList.length; ++i) { + for (let i = 0; i < segmentsList.length; ++i) { makeLooped( this, segmentsList[i], context.entrySegments); } break; + } case "ForInStatement": case "ForOfStatement": @@ -1047,9 +1048,9 @@ CodePathState.prototype = { * @returns {void} */ makeWhileTest: function(test) { - var context = this.loopContext; - var forkContext = this.forkContext; - var testSegments = forkContext.makeNext(0, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let testSegments = forkContext.makeNext(0, -1); // Update state. context.test = test; @@ -1063,9 +1064,9 @@ CodePathState.prototype = { * @returns {void} */ makeWhileBody: function() { - var context = this.loopContext; - var choiceContext = this.choiceContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let choiceContext = this.choiceContext; + let forkContext = this.forkContext; if (!choiceContext.processed) { choiceContext.trueForkContext.add(forkContext.head); @@ -1085,9 +1086,9 @@ CodePathState.prototype = { * @returns {void} */ makeDoWhileBody: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var bodySegments = forkContext.makeNext(-1, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let bodySegments = forkContext.makeNext(-1, -1); // Update state. context.entrySegments = bodySegments; @@ -1101,15 +1102,15 @@ CodePathState.prototype = { * @returns {void} */ makeDoWhileTest: function(test) { - var context = this.loopContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let forkContext = this.forkContext; context.test = test; // Creates paths of `continue` statements. if (!context.continueForkContext.empty) { context.continueForkContext.add(forkContext.head); - var testSegments = context.continueForkContext.makeNext(0, -1); + let testSegments = context.continueForkContext.makeNext(0, -1); forkContext.replaceHead(testSegments); } @@ -1122,10 +1123,10 @@ CodePathState.prototype = { * @returns {void} */ makeForTest: function(test) { - var context = this.loopContext; - var forkContext = this.forkContext; - var endOfInitSegments = forkContext.head; - var testSegments = forkContext.makeNext(-1, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let endOfInitSegments = forkContext.head; + let testSegments = forkContext.makeNext(-1, -1); // Update state. context.test = test; @@ -1140,9 +1141,9 @@ CodePathState.prototype = { * @returns {void} */ makeForUpdate: function() { - var context = this.loopContext; - var choiceContext = this.choiceContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let choiceContext = this.choiceContext; + let forkContext = this.forkContext; // Make the next paths of the test. if (context.testSegments) { @@ -1155,7 +1156,7 @@ CodePathState.prototype = { } // Update state. - var updateSegments = forkContext.makeDisconnected(-1, -1); + let updateSegments = forkContext.makeDisconnected(-1, -1); context.continueDestSegments = context.updateSegments = updateSegments; forkContext.replaceHead(updateSegments); @@ -1167,9 +1168,9 @@ CodePathState.prototype = { * @returns {void} */ makeForBody: function() { - var context = this.loopContext; - var choiceContext = this.choiceContext; - var forkContext = this.forkContext; + let context = this.loopContext; + let choiceContext = this.choiceContext; + let forkContext = this.forkContext; // Update state. if (context.updateSegments) { @@ -1191,7 +1192,7 @@ CodePathState.prototype = { context.endOfInitSegments = forkContext.head; } - var bodySegments = context.endOfTestSegments; + let bodySegments = context.endOfTestSegments; if (!bodySegments) { @@ -1199,7 +1200,7 @@ CodePathState.prototype = { * If there is not the `test` part, the `body` path comes from the * `init` part and the `update` part. */ - var prevForkContext = ForkContext.newEmpty(forkContext); + let prevForkContext = ForkContext.newEmpty(forkContext); prevForkContext.add(context.endOfInitSegments); if (context.endOfUpdateSegments) { @@ -1219,9 +1220,9 @@ CodePathState.prototype = { * @returns {void} */ makeForInOfLeft: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var leftSegments = forkContext.makeDisconnected(-1, -1); + let context = this.loopContext; + let forkContext = this.forkContext; + let leftSegments = forkContext.makeDisconnected(-1, -1); // Update state. context.prevSegments = forkContext.head; @@ -1236,12 +1237,12 @@ CodePathState.prototype = { * @returns {void} */ makeForInOfRight: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var temp = ForkContext.newEmpty(forkContext); + let context = this.loopContext; + let forkContext = this.forkContext; + let temp = ForkContext.newEmpty(forkContext); temp.add(context.prevSegments); - var rightSegments = temp.makeNext(-1, -1); + let rightSegments = temp.makeNext(-1, -1); // Update state. context.endOfLeftSegments = forkContext.head; @@ -1255,12 +1256,12 @@ CodePathState.prototype = { * @returns {void} */ makeForInOfBody: function() { - var context = this.loopContext; - var forkContext = this.forkContext; - var temp = ForkContext.newEmpty(forkContext); + let context = this.loopContext; + let forkContext = this.forkContext; + let temp = ForkContext.newEmpty(forkContext); temp.add(context.endOfLeftSegments); - var bodySegments = temp.makeNext(-1, -1); + let bodySegments = temp.makeNext(-1, -1); // Make a path: `right` -> `left`. makeLooped(this, forkContext.head, context.leftSegments); @@ -1280,7 +1281,7 @@ CodePathState.prototype = { * @param {boolean} breakable - The flag to indicate it can break by * an unlabeled BreakStatement. * @param {string|null} label - The label of this context. - * @returns {object} The new context. + * @returns {Object} The new context. */ pushBreakContext: function(breakable, label) { this.breakContext = { @@ -1295,17 +1296,17 @@ CodePathState.prototype = { /** * Removes the top item of the break context stack. * - * @returns {object} The removed context. + * @returns {Object} The removed context. */ popBreakContext: function() { - var context = this.breakContext; - var forkContext = this.forkContext; + let context = this.breakContext; + let forkContext = this.forkContext; this.breakContext = context.upper; // Process this context here for other than switches and loops. if (!context.breakable) { - var brokenForkContext = context.brokenForkContext; + let brokenForkContext = context.brokenForkContext; if (!brokenForkContext.empty) { brokenForkContext.add(forkContext.head); @@ -1326,13 +1327,13 @@ CodePathState.prototype = { * @returns {void} */ makeBreak: function(label) { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (!forkContext.reachable) { return; } - var context = getBreakContext(this, label); + let context = getBreakContext(this, label); /* istanbul ignore else: foolproof (syntax error) */ if (context) { @@ -1352,13 +1353,13 @@ CodePathState.prototype = { * @returns {void} */ makeContinue: function(label) { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (!forkContext.reachable) { return; } - var context = getContinueContext(this, label); + let context = getContinueContext(this, label); /* istanbul ignore else: foolproof (syntax error) */ if (context) { @@ -1387,7 +1388,7 @@ CodePathState.prototype = { * @returns {void} */ makeReturn: function() { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (forkContext.reachable) { getReturnContext(this).returnedForkContext.add(forkContext.head); @@ -1404,7 +1405,7 @@ CodePathState.prototype = { * @returns {void} */ makeThrow: function() { - var forkContext = this.forkContext; + let forkContext = this.forkContext; if (forkContext.reachable) { getThrowContext(this).thrownForkContext.add(forkContext.head); @@ -1417,7 +1418,7 @@ CodePathState.prototype = { * @returns {void} */ makeFinal: function() { - var segments = this.currentSegments; + let segments = this.currentSegments; if (segments.length > 0 && segments[0].reachable) { this.returnedForkContext.add(segments); diff --git a/tools/eslint/lib/code-path-analysis/code-path.js b/tools/eslint/lib/code-path-analysis/code-path.js index 035e34e712e..3fdc99afc3f 100644 --- a/tools/eslint/lib/code-path-analysis/code-path.js +++ b/tools/eslint/lib/code-path-analysis/code-path.js @@ -9,8 +9,8 @@ // Requirements //------------------------------------------------------------------------------ -var CodePathState = require("./code-path-state"); -var IdGenerator = require("./id-generator"); +let CodePathState = require("./code-path-state"); +let IdGenerator = require("./id-generator"); //------------------------------------------------------------------------------ // Public Interface @@ -22,7 +22,7 @@ var IdGenerator = require("./id-generator"); * @constructor * @param {string} id - An identifier. * @param {CodePath|null} upper - The code path of the upper function scope. - * @param {function} onLooped - A callback function to notify looping. + * @param {Function} onLooped - A callback function to notify looping. */ function CodePath(id, upper, onLooped) { @@ -117,10 +117,10 @@ CodePath.prototype = { * - `controller.skip()` - Skip the following segments in this branch. * - `controller.break()` - Skip all following segments. * - * @param {object} [options] - Omittable. + * @param {Object} [options] - Omittable. * @param {CodePathSegment} [options.first] - The first segment to traverse. * @param {CodePathSegment} [options.last] - The last segment to traverse. - * @param {function} callback - A callback function. + * @param {Function} callback - A callback function. * @returns {void} */ traverseSegments: function(options, callback) { @@ -130,18 +130,18 @@ CodePath.prototype = { } options = options || {}; - var startSegment = options.first || this.internal.initialSegment; - var lastSegment = options.last; - - var item = null; - var index = 0; - var end = 0; - var segment = null; - var visited = Object.create(null); - var stack = [[startSegment, 0]]; - var skippedSegment = null; - var broken = false; - var controller = { + let startSegment = options.first || this.internal.initialSegment; + let lastSegment = options.last; + + let item = null; + let index = 0; + let end = 0; + let segment = null; + let visited = Object.create(null); + let stack = [[startSegment, 0]]; + let skippedSegment = null; + let broken = false; + let controller = { skip: function() { if (stack.length <= 1) { broken = true; diff --git a/tools/eslint/lib/code-path-analysis/debug-helpers.js b/tools/eslint/lib/code-path-analysis/debug-helpers.js index e68c94bc496..ea31a1a9d73 100644 --- a/tools/eslint/lib/code-path-analysis/debug-helpers.js +++ b/tools/eslint/lib/code-path-analysis/debug-helpers.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug")("eslint:code-path"); +let debug = require("debug")("eslint:code-path"); //------------------------------------------------------------------------------ // Helpers @@ -54,8 +54,8 @@ module.exports = { * @returns {void} */ dumpState: !debug.enabled ? debug : /* istanbul ignore next */ function(node, state, leaving) { - for (var i = 0; i < state.currentSegments.length; ++i) { - var segInternal = state.currentSegments[i].internal; + for (let i = 0; i < state.currentSegments.length; ++i) { + let segInternal = state.currentSegments[i].internal; if (leaving) { segInternal.exitNodes.push(node); @@ -80,7 +80,7 @@ module.exports = { * @see http://www.webgraphviz.com */ dumpDot: !debug.enabled ? debug : /* istanbul ignore next */ function(codePath) { - var text = + let text = "\n" + "digraph {\n" + "node[shape=box,style=\"rounded,filled\",fillcolor=white];\n" + @@ -93,11 +93,11 @@ module.exports = { text += "thrown[label=\"✘\",shape=circle,width=0.3,height=0.3,fixedsize];\n"; } - var traceMap = Object.create(null); - var arrows = this.makeDotArrows(codePath, traceMap); + let traceMap = Object.create(null); + let arrows = this.makeDotArrows(codePath, traceMap); - for (var id in traceMap) { // eslint-disable-line guard-for-in - var segment = traceMap[id]; + for (let id in traceMap) { // eslint-disable-line guard-for-in + let segment = traceMap[id]; text += id + "["; @@ -140,26 +140,26 @@ module.exports = { * The DOT code can be visialized with Graphvis. * * @param {CodePath} codePath - A code path to make DOT. - * @param {object} traceMap - Optional. A map to check whether or not segments had been done. + * @param {Object} traceMap - Optional. A map to check whether or not segments had been done. * @returns {string} A DOT code of the code path. */ makeDotArrows: function(codePath, traceMap) { - var stack = [[codePath.initialSegment, 0]]; - var done = traceMap || Object.create(null); - var lastId = codePath.initialSegment.id; - var text = "initial->" + codePath.initialSegment.id; + let stack = [[codePath.initialSegment, 0]]; + let done = traceMap || Object.create(null); + let lastId = codePath.initialSegment.id; + let text = "initial->" + codePath.initialSegment.id; while (stack.length > 0) { - var item = stack.pop(); - var segment = item[0]; - var index = item[1]; + let item = stack.pop(); + let segment = item[0]; + let index = item[1]; if (done[segment.id] && index === 0) { continue; } done[segment.id] = segment; - var nextSegment = segment.allNextSegments[index]; + let nextSegment = segment.allNextSegments[index]; if (!nextSegment) { continue; diff --git a/tools/eslint/lib/code-path-analysis/fork-context.js b/tools/eslint/lib/code-path-analysis/fork-context.js index 00e0f97c403..93e59e7a028 100644 --- a/tools/eslint/lib/code-path-analysis/fork-context.js +++ b/tools/eslint/lib/code-path-analysis/fork-context.js @@ -13,7 +13,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"), +let assert = require("assert"), CodePathSegment = require("./code-path-segment"); //------------------------------------------------------------------------------ @@ -40,11 +40,11 @@ function isReachable(segment) { * @param {ForkContext} context - An instance. * @param {number} begin - The first index of the previous segments. * @param {number} end - The last index of the previous segments. - * @param {function} create - A factory function of new segments. + * @param {Function} create - A factory function of new segments. * @returns {CodePathSegment[]} New segments. */ function makeSegments(context, begin, end, create) { - var list = context.segmentsList; + let list = context.segmentsList; if (begin < 0) { begin = list.length + begin; @@ -53,12 +53,12 @@ function makeSegments(context, begin, end, create) { end = list.length + end; } - var segments = []; + let segments = []; - for (var i = 0; i < context.count; ++i) { - var allPrevSegments = []; + for (let i = 0; i < context.count; ++i) { + let allPrevSegments = []; - for (var j = begin; j <= end; ++j) { + for (let j = begin; j <= end; ++j) { allPrevSegments.push(list[j][i]); } @@ -80,9 +80,9 @@ function makeSegments(context, begin, end, create) { */ function mergeExtraSegments(context, segments) { while (segments.length > context.count) { - var merged = []; + let merged = []; - for (var i = 0, length = segments.length / 2 | 0; i < length; ++i) { + for (let i = 0, length = segments.length / 2 | 0; i < length; ++i) { merged.push(CodePathSegment.newNext( context.idGenerator.next(), [segments[i], segments[i + length]] @@ -120,7 +120,7 @@ ForkContext.prototype = { * @type {CodePathSegment[]} */ get head() { - var list = this.segmentsList; + let list = this.segmentsList; return list.length === 0 ? [] : list[list.length - 1]; }, @@ -138,7 +138,7 @@ ForkContext.prototype = { * @type {boolean} */ get reachable() { - var segments = this.head; + let segments = this.head; return segments.length > 0 && segments.some(isReachable); }, @@ -214,9 +214,9 @@ ForkContext.prototype = { addAll: function(context) { assert(context.count === this.count); - var source = context.segmentsList; + let source = context.segmentsList; - for (var i = 0; i < source.length; ++i) { + for (let i = 0; i < source.length; ++i) { this.segmentsList.push(source[i]); } }, @@ -238,7 +238,7 @@ ForkContext.prototype = { * @returns {ForkContext} New fork context. */ ForkContext.newRoot = function(idGenerator) { - var context = new ForkContext(idGenerator, null, 1); + let context = new ForkContext(idGenerator, null, 1); context.add([CodePathSegment.newRoot(idGenerator.next())]); diff --git a/tools/eslint/lib/config.js b/tools/eslint/lib/config.js index a485774d775..8c8533a2283 100644 --- a/tools/eslint/lib/config.js +++ b/tools/eslint/lib/config.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var path = require("path"), +let path = require("path"), ConfigOps = require("./config/config-ops"), ConfigFile = require("./config/config-file"), Plugins = require("./config/plugins"), @@ -23,7 +23,7 @@ var path = require("path"), // Constants //------------------------------------------------------------------------------ -var PERSONAL_CONFIG_DIR = userHome || null; +let PERSONAL_CONFIG_DIR = userHome || null; //------------------------------------------------------------------------------ // Helpers @@ -48,7 +48,7 @@ function isObject(item) { * @private */ function loadConfig(configToLoad) { - var config = {}, + let config = {}, filePath = ""; if (configToLoad) { @@ -75,7 +75,7 @@ function loadConfig(configToLoad) { * @private */ function getPersonalConfig() { - var config, + let config, filename; if (PERSONAL_CONFIG_DIR) { @@ -106,7 +106,7 @@ function hasRules(options) { * @returns {Object} The local config object, or an empty object if there is no local config. */ function getLocalConfig(thisConfig, directory) { - var found, + let found, i, localConfig, localConfigFile, @@ -162,10 +162,10 @@ function getLocalConfig(thisConfig, directory) { if (personalConfig) { config = ConfigOps.merge(config, personalConfig); - } else if (!hasRules(thisConfig.options)) { + } else if (!hasRules(thisConfig.options) && !thisConfig.options.baseConfig) { // No config file, no manual configuration, and no rules, so error. - var noConfigError = new Error("No ESLint configuration found."); + let noConfigError = new Error("No ESLint configuration found."); noConfigError.messageTemplate = "no-config-found"; noConfigError.messageData = { @@ -191,7 +191,7 @@ function getLocalConfig(thisConfig, directory) { * @param {Object} options Options to be passed in */ function Config(options) { - var useConfig; + let useConfig; options = options || {}; @@ -217,7 +217,7 @@ function Config(options) { * If user declares "foo", convert to "foo:false". */ this.globals = (options.globals || []).reduce(function(globals, def) { - var parts = def.split(":"); + let parts = def.split(":"); globals[parts[0]] = (parts.length > 1 && parts[1] === "true"); @@ -244,7 +244,7 @@ function Config(options) { * @returns {Object} config object */ Config.prototype.getConfig = function(filePath) { - var config, + let config, userConfig, directory = filePath ? path.dirname(filePath) : this.options.cwd; diff --git a/tools/eslint/lib/config/autoconfig.js b/tools/eslint/lib/config/autoconfig.js index be3d0970741..2cd753e95dd 100644 --- a/tools/eslint/lib/config/autoconfig.js +++ b/tools/eslint/lib/config/autoconfig.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), debug = require("debug"), eslint = require("../eslint"), configRule = require("./config-rule"), @@ -20,7 +20,7 @@ var lodash = require("lodash"), // Data //------------------------------------------------------------------------------ -var MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only +let MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only RECOMMENDED_CONFIG_NAME = "eslint:recommended"; //------------------------------------------------------------------------------ @@ -89,7 +89,7 @@ Registry.prototype = { * @returns {void} */ populateFromCoreRules: function() { - var rulesConfig = configRule.createCoreRuleConfigs(); + let rulesConfig = configRule.createCoreRuleConfigs(); this.rules = makeRegistryItems(rulesConfig); }, @@ -109,7 +109,7 @@ Registry.prototype = { * @returns {Object[]} "rules" configurations to use for linting */ buildRuleSets: function() { - var idx = 0, + let idx = 0, ruleIds = Object.keys(this.rules), ruleSets = []; @@ -122,7 +122,7 @@ Registry.prototype = { * @param {string} rule The ruleId to add. * @returns {void} */ - var addRuleToRuleSet = function(rule) { + let addRuleToRuleSet = function(rule) { /* * This check ensures that there is a rule configuration and that @@ -130,7 +130,7 @@ Registry.prototype = { * If it has too many configs, we will only use the most basic of * the possible configurations. */ - var hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS); + let hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS); if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) { @@ -170,12 +170,12 @@ Registry.prototype = { * @returns {void} */ stripFailingConfigs: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), newRegistry = new Registry(); newRegistry.rules = lodash.assign({}, this.rules); ruleIds.forEach(function(ruleId) { - var errorFreeItems = newRegistry.rules[ruleId].filter(function(registryItem) { + let errorFreeItems = newRegistry.rules[ruleId].filter(function(registryItem) { return (registryItem.errorCount === 0); }); @@ -195,7 +195,7 @@ Registry.prototype = { * @returns {void} */ stripExtraConfigs: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), newRegistry = new Registry(); newRegistry.rules = lodash.assign({}, this.rules); @@ -216,11 +216,11 @@ Registry.prototype = { * @returns {Registry} A registry of failing rules. */ getFailingRulesRegistry: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), failingRegistry = new Registry(); ruleIds.forEach(function(ruleId) { - var failingConfigs = this.rules[ruleId].filter(function(registryItem) { + let failingConfigs = this.rules[ruleId].filter(function(registryItem) { return (registryItem.errorCount > 0); }); @@ -239,7 +239,7 @@ Registry.prototype = { * @returns {Object} An eslint config with rules section populated */ createConfig: function() { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), config = {rules: {}}; ruleIds.forEach(function(ruleId) { @@ -258,7 +258,7 @@ Registry.prototype = { * @returns {Registry} A registry of rules */ filterBySpecificity: function(specificity) { - var ruleIds = Object.keys(this.rules), + let ruleIds = Object.keys(this.rules), newRegistry = new Registry(); newRegistry.rules = lodash.assign({}, this.rules); @@ -280,7 +280,7 @@ Registry.prototype = { * @returns {Registry} New registry with errorCount populated */ lintSourceCode: function(sourceCodes, config, cb) { - var totalFilesLinting, + let totalFilesLinting, lintConfig, ruleSets, ruleSetIdx, @@ -307,7 +307,7 @@ Registry.prototype = { ruleSets.forEach(function(ruleSet) { lintConfig = lodash.assign({}, config, {rules: ruleSet}); - var lintResults = eslint.verify(sourceCodes[filename], lintConfig); + let lintResults = eslint.verify(sourceCodes[filename], lintConfig); lintResults.forEach(function(result) { @@ -344,11 +344,11 @@ Registry.prototype = { * @returns {Object} config object using `"extends": "eslint:recommended"` */ function extendFromRecommended(config) { - var newConfig = lodash.assign({}, config); + let newConfig = lodash.assign({}, config); ConfigOps.normalizeToStrings(newConfig); - var recRules = Object.keys(recConfig.rules).filter(function(ruleId) { + let recRules = Object.keys(recConfig.rules).filter(function(ruleId) { return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]); }); diff --git a/tools/eslint/lib/config/config-file.js b/tools/eslint/lib/config/config-file.js index e2996e3eb90..9120c12f3c4 100644 --- a/tools/eslint/lib/config/config-file.js +++ b/tools/eslint/lib/config/config-file.js @@ -11,7 +11,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug"), +let debug = require("debug"), fs = require("fs"), path = require("path"), ConfigOps = require("./config-ops"), @@ -48,7 +48,7 @@ function sortByKey(a, b) { // Private //------------------------------------------------------------------------------ -var CONFIG_FILES = [ +let CONFIG_FILES = [ ".eslintrc.js", ".eslintrc.yaml", ".eslintrc.yml", @@ -57,7 +57,7 @@ var CONFIG_FILES = [ "package.json" ]; -var resolver = new ModuleResolver(); +let resolver = new ModuleResolver(); debug = debug("eslint:config-file"); @@ -94,7 +94,7 @@ function loadYAMLConfigFile(filePath) { debug("Loading YAML config file: " + filePath); // lazy load YAML to improve performance when not used - var yaml = require("js-yaml"); + let yaml = require("js-yaml"); try { @@ -137,7 +137,7 @@ function loadLegacyConfigFile(filePath) { debug("Loading config file: " + filePath); // lazy load YAML to improve performance when not used - var yaml = require("js-yaml"); + let yaml = require("js-yaml"); try { return yaml.safeLoad(stripComments(readFile(filePath))) || /* istanbul ignore next */ {}; @@ -192,7 +192,7 @@ function loadPackageJSONConfigFile(filePath) { * @private */ function loadConfigFile(file) { - var config, + let config, filePath = file.filePath; switch (path.extname(filePath)) { @@ -236,7 +236,7 @@ function loadConfigFile(file) { function writeJSONConfigFile(config, filePath) { debug("Writing JSON config file: " + filePath); - var content = stringify(config, {cmp: sortByKey, space: 4}); + let content = stringify(config, {cmp: sortByKey, space: 4}); fs.writeFileSync(filePath, content, "utf8"); } @@ -252,9 +252,9 @@ function writeYAMLConfigFile(config, filePath) { debug("Writing YAML config file: " + filePath); // lazy load YAML to improve performance when not used - var yaml = require("js-yaml"); + let yaml = require("js-yaml"); - var content = yaml.safeDump(config, {sortKeys: true}); + let content = yaml.safeDump(config, {sortKeys: true}); fs.writeFileSync(filePath, content, "utf8"); } @@ -269,7 +269,7 @@ function writeYAMLConfigFile(config, filePath) { function writeJSConfigFile(config, filePath) { debug("Writing JS config file: " + filePath); - var content = "module.exports = " + stringify(config, {cmp: sortByKey, space: 4}) + ";"; + let content = "module.exports = " + stringify(config, {cmp: sortByKey, space: 4}) + ";"; fs.writeFileSync(filePath, content, "utf8"); } @@ -313,7 +313,7 @@ function write(config, filePath) { function getBaseDir(configFilePath) { // calculates the path of the project including ESLint as dependency - var projectPath = path.resolve(__dirname, "../../../"); + let projectPath = path.resolve(__dirname, "../../../"); if (configFilePath && pathIsInside(configFilePath, projectPath)) { @@ -336,7 +336,7 @@ function getBaseDir(configFilePath) { * @private */ function getLookupPath(configFilePath) { - var basedir = getBaseDir(configFilePath); + let basedir = getBaseDir(configFilePath); return path.join(basedir, "node_modules"); } @@ -352,7 +352,7 @@ function getLookupPath(configFilePath) { * @private */ function applyExtends(config, filePath, relativeTo) { - var configExtends = config.extends; + let configExtends = config.extends; // normalize into an array for easier handling if (!Array.isArray(config.extends)) { @@ -431,7 +431,7 @@ function normalizePackageName(name, prefix) { * it's a scoped package * package name is "eslint-config", or just a username */ - var scopedPackageShortcutRegex = new RegExp("^(@[^\/]+)(?:\/(?:" + prefix + ")?)?$"), + let scopedPackageShortcutRegex = new RegExp("^(@[^\/]+)(?:\/(?:" + prefix + ")?)?$"), scopedPackageNameRegex = new RegExp("^" + prefix + "(-|$)"); if (scopedPackageShortcutRegex.test(name)) { @@ -463,11 +463,11 @@ function resolve(filePath, relativeTo) { if (isFilePath(filePath)) { return { filePath: path.resolve(relativeTo || "", filePath) }; } else { - var normalizedPackageName; + let normalizedPackageName; if (filePath.indexOf("plugin:") === 0) { - var packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7); - var configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1); + let packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7); + let configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1); normalizedPackageName = normalizePackageName(packagePath, "eslint-plugin"); debug("Attempting to resolve " + normalizedPackageName); @@ -493,7 +493,7 @@ function resolve(filePath, relativeTo) { * @private */ function load(filePath, applyEnvironments, relativeTo) { - var resolvedPath = resolve(filePath, relativeTo), + let resolvedPath = resolve(filePath, relativeTo), dirname = path.dirname(resolvedPath.filePath), lookupPath = getLookupPath(dirname), config = loadConfigFile(resolvedPath); @@ -565,9 +565,9 @@ module.exports = { */ getFilenameForDirectory: function(directory) { - var filename; + let filename; - for (var i = 0, len = CONFIG_FILES.length; i < len; i++) { + for (let i = 0, len = CONFIG_FILES.length; i < len; i++) { filename = path.join(directory, CONFIG_FILES[i]); if (fs.existsSync(filename)) { return filename; diff --git a/tools/eslint/lib/config/config-initializer.js b/tools/eslint/lib/config/config-initializer.js index 91d2454a8a4..ca52a06c657 100644 --- a/tools/eslint/lib/config/config-initializer.js +++ b/tools/eslint/lib/config/config-initializer.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var util = require("util"), +let util = require("util"), debug = require("debug"), lodash = require("lodash"), inquirer = require("inquirer"), @@ -38,7 +38,7 @@ debug = debug("eslint:config-initializer"); function writeFile(config, format) { // default is .js - var extname = ".js"; + let extname = ".js"; if (format === "YAML") { extname = ".yml"; @@ -60,7 +60,7 @@ function writeFile(config, format) { * @returns {void} */ function installModules(config) { - var modules = [], + let modules = [], installStatus, modulesToInstall; @@ -86,7 +86,7 @@ function installModules(config) { // Install packages which aren't already installed modulesToInstall = Object.keys(installStatus).filter(function(module) { - var notInstalled = installStatus[module] === false; + let notInstalled = installStatus[module] === false; if (module === "eslint" && notInstalled) { log.info("Local ESLint installation not found."); @@ -113,10 +113,10 @@ function installModules(config) { * @returns {Object} config object with configured rules */ function configureRules(answers, config) { - var BAR_TOTAL = 20, + let BAR_TOTAL = 20, BAR_SOURCE_CODE_TOTAL = 4; - var newConfig = lodash.assign({}, config), + let newConfig = lodash.assign({}, config), bar, patterns, sourceCodes, @@ -163,7 +163,7 @@ function configureRules(answers, config) { debug("\nRegistry: " + util.inspect(registry.rules, {depth: null})); // Create a list of recommended rules, because we don't want to disable them - var recRules = Object.keys(recConfig.rules).filter(function(ruleId) { + let recRules = Object.keys(recConfig.rules).filter(function(ruleId) { return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]); }); @@ -202,12 +202,12 @@ function configureRules(answers, config) { bar.update(BAR_TOTAL); // Log out some stats to let the user know what happened - var finalRuleIds = Object.keys(newConfig.rules), + let finalRuleIds = Object.keys(newConfig.rules), totalRules = finalRuleIds.length; - var enabledRules = finalRuleIds.filter(function(ruleId) { + let enabledRules = finalRuleIds.filter(function(ruleId) { return (newConfig.rules[ruleId] !== 0); }).length; - var resultMessage = [ + let resultMessage = [ "\nEnabled " + enabledRules + " out of " + totalRules, "rules based on " + fileQty, "file" + ((fileQty === 1) ? "." : "s.") @@ -225,7 +225,7 @@ function configureRules(answers, config) { * @returns {Object} config object */ function processAnswers(answers) { - var config = {rules: {}, env: {}}; + let config = {rules: {}, env: {}}; if (answers.es6) { config.env.es6 = true; @@ -275,10 +275,10 @@ function processAnswers(answers) { * @returns {Object} config object */ function getConfigForStyleGuide(guide) { - var guides = { + let guides = { google: {extends: "google"}, airbnb: {extends: "airbnb", plugins: ["react"]}, - standard: {extends: "standard", plugins: ["standard"]} + standard: {extends: "standard", plugins: ["standard", "promise"]} }; if (!guides[guide]) { @@ -293,11 +293,11 @@ function getConfigForStyleGuide(guide) { /* istanbul ignore next: no need to test inquirer*/ /** * Ask use a few questions on command prompt - * @param {function} callback callback function when file has been written + * @param {Function} callback callback function when file has been written * @returns {void} */ function promptUser(callback) { - var config; + let config; inquirer.prompt([ { @@ -419,7 +419,7 @@ function promptUser(callback) { // early exit if you are using automatic style generation if (earlyAnswers.source === "auto") { try { - var combinedAnswers = lodash.assign({}, earlyAnswers, secondAnswers); + let combinedAnswers = lodash.assign({}, earlyAnswers, secondAnswers); config = processAnswers(combinedAnswers); installModules(config); @@ -469,7 +469,7 @@ function promptUser(callback) { } ], function(answers) { try { - var totalAnswers = lodash.assign({}, earlyAnswers, secondAnswers, answers); + let totalAnswers = lodash.assign({}, earlyAnswers, secondAnswers, answers); config = processAnswers(totalAnswers); installModules(config); @@ -488,7 +488,7 @@ function promptUser(callback) { // Public Interface //------------------------------------------------------------------------------ -var init = { +let init = { getConfigForStyleGuide: getConfigForStyleGuide, processAnswers: processAnswers, initializeConfig: /* istanbul ignore next */ function(callback) { diff --git a/tools/eslint/lib/config/config-ops.js b/tools/eslint/lib/config/config-ops.js index d62169502b7..2e0c29a752d 100644 --- a/tools/eslint/lib/config/config-ops.js +++ b/tools/eslint/lib/config/config-ops.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), debug = require("debug"), Environments = require("./environments"); @@ -19,7 +19,7 @@ var lodash = require("lodash"), debug = debug("eslint:config-ops"); -var RULE_SEVERITY_STRINGS = ["off", "warn", "error"], +let RULE_SEVERITY_STRINGS = ["off", "warn", "error"], RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce(function(map, value, index) { map[value] = index; return map; @@ -53,7 +53,7 @@ module.exports = { */ createEnvironmentConfig: function(env) { - var envConfig = this.createEmptyConfig(); + let envConfig = this.createEmptyConfig(); if (env) { @@ -62,7 +62,7 @@ module.exports = { Object.keys(env).filter(function(name) { return env[name]; }).forEach(function(name) { - var environment = Environments.get(name); + let environment = Environments.get(name); if (environment) { debug("Creating config for environment " + name); @@ -134,8 +134,8 @@ module.exports = { * (https://github.com/KyleAMathews/deepmerge) * and modified to meet our needs. */ - var array = Array.isArray(src) || Array.isArray(target); - var dst = array && [] || {}; + let array = Array.isArray(src) || Array.isArray(target); + let dst = array && [] || {}; combine = !!combine; isRule = !!isRule; @@ -202,7 +202,7 @@ module.exports = { if (config.rules) { Object.keys(config.rules).forEach(function(ruleId) { - var ruleConfig = config.rules[ruleId]; + let ruleConfig = config.rules[ruleId]; if (typeof ruleConfig === "string") { config.rules[ruleId] = RULE_SEVERITY[ruleConfig.toLowerCase()] || 0; @@ -224,7 +224,7 @@ module.exports = { if (config.rules) { Object.keys(config.rules).forEach(function(ruleId) { - var ruleConfig = config.rules[ruleId]; + let ruleConfig = config.rules[ruleId]; if (typeof ruleConfig === "number") { config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0]; @@ -242,7 +242,7 @@ module.exports = { */ isErrorSeverity: function(ruleConfig) { - var severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; + let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; if (typeof severity === "string") { severity = RULE_SEVERITY[severity.toLowerCase()] || 0; @@ -257,7 +257,7 @@ module.exports = { * @returns {boolean} `true` if the configuration has valid severity. */ isValidSeverity: function(ruleConfig) { - var severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; + let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; if (typeof severity === "string") { severity = severity.toLowerCase(); @@ -267,7 +267,7 @@ module.exports = { /** * Checks whether every rule of a given config has valid severity or not. - * @param {object} config - The configuration for rules. + * @param {Object} config - The configuration for rules. * @returns {boolean} `true` if the configuration has valid severity. */ isEverySeverityValid: function(config) { diff --git a/tools/eslint/lib/config/config-rule.js b/tools/eslint/lib/config/config-rule.js index c0a394efee1..f4c2803ff7e 100644 --- a/tools/eslint/lib/config/config-rule.js +++ b/tools/eslint/lib/config/config-rule.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var rules = require("../rules"), +let rules = require("../rules"), loadRules = require("../load-rules"); @@ -41,7 +41,7 @@ function explodeArray(xs) { * @returns {array} A mixture of the elements of the first and second arrays. */ function combineArrays(arr1, arr2) { - var res = []; + let res = []; if (arr1.length === 0) { return explodeArray(arr2); @@ -78,8 +78,8 @@ function combineArrays(arr1, arr2) { * @returns {Array[]} Array of arrays of objects grouped by property */ function groupByProperty(objects) { - var groupedObj = objects.reduce(function(accumulator, obj) { - var prop = Object.keys(obj)[0]; + let groupedObj = objects.reduce(function(accumulator, obj) { + let prop = Object.keys(obj)[0]; accumulator[prop] = accumulator[prop] ? accumulator[prop].concat(obj) : [obj]; return accumulator; @@ -144,7 +144,7 @@ function groupByProperty(objects) { * @returns {Object[]} Combined objects for each combination of input properties and values */ function combinePropertyObjects(objArr1, objArr2) { - var res = []; + let res = []; if (objArr1.length === 0) { return objArr2; @@ -154,9 +154,9 @@ function combinePropertyObjects(objArr1, objArr2) { } objArr1.forEach(function(obj1) { objArr2.forEach(function(obj2) { - var combinedObj = {}; - var obj1Props = Object.keys(obj1); - var obj2Props = Object.keys(obj2); + let combinedObj = {}; + let obj1Props = Object.keys(obj1); + let obj2Props = Object.keys(obj2); obj1Props.forEach(function(prop1) { combinedObj[prop1] = obj1[prop1]; @@ -229,12 +229,12 @@ RuleConfigSet.prototype = { * @returns {void} */ addObject: function(obj) { - var objectConfigSet = { + let objectConfigSet = { objectConfigs: [], add: function(property, values) { - var optionObj; + let optionObj; - for (var idx = 0; idx < values.length; idx++) { + for (let idx = 0; idx < values.length; idx++) { optionObj = {}; optionObj[property] = values[idx]; this.objectConfigs.push(optionObj); @@ -274,7 +274,7 @@ RuleConfigSet.prototype = { * @returns {array[]} Valid rule configurations */ function generateConfigsFromSchema(schema) { - var configSet = new RuleConfigSet(); + let configSet = new RuleConfigSet(); if (Array.isArray(schema)) { schema.forEach(function(opt) { @@ -301,11 +301,11 @@ function generateConfigsFromSchema(schema) { * @returns {rulesConfig} Hash of rule names and arrays of possible configurations */ function createCoreRuleConfigs() { - var ruleList = loadRules(); + let ruleList = loadRules(); return Object.keys(ruleList).reduce(function(accumulator, id) { - var rule = rules.get(id); - var schema = (typeof rule === "function") ? rule.schema : rule.meta.schema; + let rule = rules.get(id); + let schema = (typeof rule === "function") ? rule.schema : rule.meta.schema; accumulator[id] = generateConfigsFromSchema(schema); return accumulator; diff --git a/tools/eslint/lib/config/config-validator.js b/tools/eslint/lib/config/config-validator.js index ebc70516c19..6695260a23a 100644 --- a/tools/eslint/lib/config/config-validator.js +++ b/tools/eslint/lib/config/config-validator.js @@ -9,12 +9,12 @@ // Requirements //------------------------------------------------------------------------------ -var rules = require("../rules"), +let rules = require("../rules"), Environments = require("./environments"), schemaValidator = require("is-my-json-valid"), util = require("util"); -var validators = { +let validators = { rules: Object.create(null) }; @@ -25,10 +25,10 @@ var validators = { /** * Gets a complete options schema for a rule. * @param {string} id The rule's unique name. - * @returns {object} JSON Schema for the rule's options. + * @returns {Object} JSON Schema for the rule's options. */ function getRuleOptionsSchema(id) { - var rule = rules.get(id), + let rule = rules.get(id), schema = rule && rule.schema || rule && rule.meta && rule.meta.schema; // Given a tuple of schemas, insert warning level at the beginning @@ -61,7 +61,7 @@ function getRuleOptionsSchema(id) { * @returns {void} */ function validateRuleOptions(id, options, source) { - var validateRule = validators.rules[id], + let validateRule = validators.rules[id], message, severity, localOptions, @@ -119,7 +119,7 @@ function validateRuleOptions(id, options, source) { /** * Validates an environment object - * @param {object} environment The environment config object to validate. + * @param {Object} environment The environment config object to validate. * @param {string} source The location to report with any errors. * @returns {void} */ @@ -137,7 +137,7 @@ function validateEnvironment(environment, source) { if (typeof environment === "object") { Object.keys(environment).forEach(function(env) { if (!Environments.get(env)) { - var message = [ + let message = [ source, ":\n", "\tEnvironment key \"", env, "\" is unknown\n" ]; @@ -152,7 +152,7 @@ function validateEnvironment(environment, source) { /** * Validates an entire config object. - * @param {object} config The config object to validate. + * @param {Object} config The config object to validate. * @param {string} source The location to report with any errors. * @returns {void} */ diff --git a/tools/eslint/lib/config/environments.js b/tools/eslint/lib/config/environments.js index 8daef864e31..9a5defbfc27 100644 --- a/tools/eslint/lib/config/environments.js +++ b/tools/eslint/lib/config/environments.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var envs = require("../../conf/environments"); +let envs = require("../../conf/environments"); //------------------------------------------------------------------------------ // Private //------------------------------------------------------------------------------ -var environments = Object.create(null); +let environments = new Map(); /** * Loads the default environments. @@ -23,7 +23,7 @@ var environments = Object.create(null); */ function load() { Object.keys(envs).forEach(function(envName) { - environments[envName] = envs[envName]; + environments.set(envName, envs[envName]); }); } @@ -36,15 +36,15 @@ load(); module.exports = { - load: load, + load, /** * Gets the environment with the given name. * @param {string} name The name of the environment to retrieve. * @returns {Object?} The environment object or null if not found. */ - get: function(name) { - return environments[name] || null; + get(name) { + return environments.get(name) || null; }, /** @@ -53,8 +53,8 @@ module.exports = { * @param {Object} env The environment settings. * @returns {void} */ - define: function(name, env) { - environments[name] = env; + define(name, env) { + environments.set(name, env); }, /** @@ -63,7 +63,7 @@ module.exports = { * @param {string} pluginName The name of the plugin. * @returns {void} */ - importPlugin: function(plugin, pluginName) { + importPlugin(plugin, pluginName) { if (plugin.environments) { Object.keys(plugin.environments).forEach(function(envName) { this.define(pluginName + "/" + envName, plugin.environments[envName]); @@ -75,8 +75,8 @@ module.exports = { * Resets all environments. Only use for tests! * @returns {void} */ - testReset: function() { - environments = Object.create(null); + testReset() { + environments = new Map(); load(); } }; diff --git a/tools/eslint/lib/config/plugins.js b/tools/eslint/lib/config/plugins.js index e157eb123c9..7065045c121 100644 --- a/tools/eslint/lib/config/plugins.js +++ b/tools/eslint/lib/config/plugins.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug"), +let debug = require("debug"), Environments = require("./environments"), rules = require("../rules"); @@ -18,9 +18,9 @@ var debug = require("debug"), debug = debug("eslint:plugins"); -var plugins = Object.create(null); +let plugins = Object.create(null); -var PLUGIN_NAME_PREFIX = "eslint-plugin-", +let PLUGIN_NAME_PREFIX = "eslint-plugin-", NAMESPACE_REGEX = /^@.*\//i; /** @@ -67,7 +67,7 @@ module.exports = { * @returns {void} */ define: function(pluginName, plugin) { - var pluginNameWithoutNamespace = removeNamespace(pluginName), + let pluginNameWithoutNamespace = removeNamespace(pluginName), pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace); plugins[pluginNameWithoutPrefix] = plugin; @@ -104,7 +104,7 @@ module.exports = { * @throws {Error} If the plugin cannot be loaded. */ load: function(pluginName) { - var pluginNamespace = getNamespace(pluginName), + let pluginNamespace = getNamespace(pluginName), pluginNameWithoutNamespace = removeNamespace(pluginName), pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace), plugin = null; diff --git a/tools/eslint/lib/eslint.js b/tools/eslint/lib/eslint.js index 69ad96e820b..01b43eb4ee1 100644 --- a/tools/eslint/lib/eslint.js +++ b/tools/eslint/lib/eslint.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"), +let assert = require("assert"), EventEmitter = require("events").EventEmitter, escope = require("escope"), levn = require("levn"), @@ -41,19 +41,16 @@ var assert = require("assert"), * @returns {Object} Result map object of names and boolean values */ function parseBooleanConfig(string, comment) { - var items = {}; + let items = {}; - // Collapse whitespace around : to make parsing easier - string = string.replace(/\s*:\s*/g, ":"); - - // Collapse whitespace around , - string = string.replace(/\s*,\s*/g, ","); + // Collapse whitespace around `:` and `,` to make parsing easier + string = string.replace(/\s*([:,])\s*/g, "$1"); string.split(/\s|,+/).forEach(function(name) { if (!name) { return; } - var pos = name.indexOf(":"), + let pos = name.indexOf(":"), value; if (pos !== -1) { @@ -78,7 +75,7 @@ function parseBooleanConfig(string, comment) { * @returns {Object} Result map object */ function parseJsonConfig(string, location, messages) { - var items = {}; + let items = {}; // Parses a JSON-like comment by the same way as parsing CLI option. try { @@ -125,7 +122,7 @@ function parseJsonConfig(string, location, messages) { * @returns {Object} Result map of values and true values */ function parseListConfig(string) { - var items = {}; + let items = {}; // Collapse whitespace around , string = string.replace(/\s*,\s*/g, ","); @@ -150,7 +147,7 @@ function parseListConfig(string) { * @returns {void} */ function addDeclaredGlobals(program, globalScope, config) { - var declaredGlobals = {}, + let declaredGlobals = {}, exportedGlobals = {}, explicitGlobals = {}, builtin = Environments.get("builtin"); @@ -159,7 +156,7 @@ function addDeclaredGlobals(program, globalScope, config) { Object.keys(config.env).forEach(function(name) { if (config.env[name]) { - var env = Environments.get(name), + let env = Environments.get(name), environmentGlobals = env && env.globals; if (environmentGlobals) { @@ -173,7 +170,7 @@ function addDeclaredGlobals(program, globalScope, config) { lodash.assign(explicitGlobals, config.astGlobals); Object.keys(declaredGlobals).forEach(function(name) { - var variable = globalScope.set.get(name); + let variable = globalScope.set.get(name); if (!variable) { variable = new escope.Variable(name, globalScope); @@ -185,7 +182,7 @@ function addDeclaredGlobals(program, globalScope, config) { }); Object.keys(explicitGlobals).forEach(function(name) { - var variable = globalScope.set.get(name); + let variable = globalScope.set.get(name); if (!variable) { variable = new escope.Variable(name, globalScope); @@ -199,7 +196,7 @@ function addDeclaredGlobals(program, globalScope, config) { // mark all exported variables as such Object.keys(exportedGlobals).forEach(function(name) { - var variable = globalScope.set.get(name); + let variable = globalScope.set.get(name); if (variable) { variable.eslintUsed = true; @@ -212,8 +209,8 @@ function addDeclaredGlobals(program, globalScope, config) { * references and remove the ones that were added by configuration. */ globalScope.through = globalScope.through.filter(function(reference) { - var name = reference.identifier.name; - var variable = globalScope.set.get(name); + let name = reference.identifier.name; + let variable = globalScope.set.get(name); if (variable) { @@ -267,7 +264,7 @@ function disableReporting(reportingConfig, start, rulesToDisable) { * @returns {void} */ function enableReporting(reportingConfig, start, rulesToEnable) { - var i; + let i; if (rulesToEnable.length) { rulesToEnable.forEach(function(rule) { @@ -281,7 +278,7 @@ function enableReporting(reportingConfig, start, rulesToEnable) { } else { // find all previous disabled locations if they was started as list of rules - var prevStart; + let prevStart; for (i = reportingConfig.length - 1; i >= 0; i--) { if (prevStart && prevStart !== reportingConfig[i].start) { @@ -305,22 +302,22 @@ function enableReporting(reportingConfig, start, rulesToEnable) { * @param {Object} config The existing configuration data. * @param {Object[]} reportingConfig The existing reporting configuration data. * @param {Object[]} messages The messages queue. - * @returns {object} Modified config object + * @returns {Object} Modified config object */ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messages) { - var commentConfig = { + let commentConfig = { exported: {}, astGlobals: {}, rules: {}, env: {} }; - var commentRules = {}; + let commentRules = {}; ast.comments.forEach(function(comment) { - var value = comment.value.trim(); - var match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value); + let value = comment.value.trim(); + let match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value); if (match) { value = value.substring(match.index + match[1].length); @@ -348,16 +345,17 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa enableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value))); break; - case "eslint": - var items = parseJsonConfig(value, comment.loc, messages); + case "eslint": { + const items = parseJsonConfig(value, comment.loc, messages); Object.keys(items).forEach(function(name) { - var ruleValue = items[name]; + let ruleValue = items[name]; validator.validateRuleOptions(name, ruleValue, filename + " line " + comment.loc.start.line); commentRules[name] = ruleValue; }); break; + } // no default } @@ -375,7 +373,7 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa // apply environment configs Object.keys(commentConfig.env).forEach(function(name) { - var env = Environments.get(name); + let env = Environments.get(name); if (env) { commentConfig = ConfigOps.merge(commentConfig, env); @@ -395,9 +393,9 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa */ function isDisabledByReportingConfig(reportingConfig, ruleId, location) { - for (var i = 0, c = reportingConfig.length; i < c; i++) { + for (let i = 0, c = reportingConfig.length; i < c; i++) { - var ignore = reportingConfig[i]; + let ignore = reportingConfig[i]; if ((!ignore.rule || ignore.rule === ruleId) && (location.line > ignore.start.line || (location.line === ignore.start.line && location.column >= ignore.start.column)) && @@ -419,13 +417,13 @@ function prepareConfig(config) { config.globals = config.globals || config.global || {}; delete config.global; - var copiedRules = {}, + let copiedRules = {}, parserOptions = {}, preparedConfig; if (typeof config.rules === "object") { Object.keys(config.rules).forEach(function(k) { - var rule = config.rules[k]; + let rule = config.rules[k]; if (rule === null) { throw new Error("Invalid config for rule '" + k + "'\."); @@ -441,7 +439,7 @@ function prepareConfig(config) { // merge in environment parserOptions if (typeof config.env === "object") { Object.keys(config.env).forEach(function(envName) { - var env = Environments.get(envName); + let env = Environments.get(envName); if (config.env[envName] && env && env.parserOptions) { parserOptions = ConfigOps.merge(parserOptions, env.parserOptions); @@ -484,8 +482,8 @@ function createStubRule(message) { /** * Creates a fake rule object - * @param {object} context context object for each rule - * @returns {object} collection of node to listen on + * @param {Object} context context object for each rule + * @returns {Object} collection of node to listen on */ function createRuleModule(context) { return { @@ -509,7 +507,7 @@ function createStubRule(message) { */ function getRuleReplacementMessage(ruleId) { if (ruleId in replacements.rules) { - var newRules = replacements.rules[ruleId]; + let newRules = replacements.rules[ruleId]; return "Rule \'" + ruleId + "\' was removed and replaced by: " + newRules.join(", "); } @@ -517,15 +515,15 @@ function getRuleReplacementMessage(ruleId) { return null; } -var eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g; +let eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g; /** * Checks whether or not there is a comment which has "eslint-env *" in a given text. * @param {string} text - A source code text to check. - * @returns {object|null} A result of parseListConfig() with "eslint-env *" comment. + * @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment. */ function findEslintEnv(text) { - var match, retv; + let match, retv; eslintEnvPattern.lastIndex = 0; @@ -565,7 +563,7 @@ function stripUnicodeBOM(text) { */ module.exports = (function() { - var api = Object.create(new EventEmitter()), + let api = Object.create(new EventEmitter()), messages = [], currentConfig = null, currentScopes = null, @@ -587,7 +585,7 @@ module.exports = (function() { */ function parse(text, config) { - var parser, + let parser, parserOptions = { loc: true, range: true, @@ -629,8 +627,8 @@ module.exports = (function() { } catch (ex) { // If the message includes a leading line number, strip it: - var message = ex.message.replace(/^line \d+:/i, "").trim(); - var source = (ex.lineNumber) ? SourceCode.splitLines(text)[ex.lineNumber - 1] : null; + let message = ex.message.replace(/^line \d+:/i, "").trim(); + let source = (ex.lineNumber) ? SourceCode.splitLines(text)[ex.lineNumber - 1] : null; messages.push({ ruleId: null, @@ -721,7 +719,7 @@ module.exports = (function() { */ api.verify = function(textOrSourceCode, config, filenameOrOptions, saveState) { - var ast, + let ast, shebang, ecmaFeatures, ecmaVersion, @@ -742,7 +740,7 @@ module.exports = (function() { } // search and apply "eslint-env *". - var envInFile = findEslintEnv(text || textOrSourceCode.text); + let envInFile = findEslintEnv(text || textOrSourceCode.text); if (envInFile) { if (!config || !config.env) { @@ -797,7 +795,7 @@ module.exports = (function() { Object.keys(config.rules).filter(function(key) { return getRuleSeverity(config.rules[key]) > 0; }).forEach(function(key) { - var ruleCreator, + let ruleCreator, severity, options, rule; @@ -805,7 +803,7 @@ module.exports = (function() { ruleCreator = rules.get(key); if (!ruleCreator) { - var replacementMsg = getRuleReplacementMessage(key); + let replacementMsg = getRuleReplacementMessage(key); if (replacementMsg) { ruleCreator = createStubRule(replacementMsg); @@ -819,7 +817,7 @@ module.exports = (function() { options = getRuleOptions(config.rules[key]); try { - var ruleContext = new RuleContext( + let ruleContext = new RuleContext( key, api, severity, options, config.settings, config.parserOptions, config.parser, ruleCreator.meta); @@ -865,7 +863,7 @@ module.exports = (function() { scopeMap = []; currentScopes.forEach(function(scope, index) { - var range = scope.block.range[0]; + let range = scope.block.range[0]; /* * Sometimes two scopes are returned for a given node. This is @@ -888,7 +886,7 @@ module.exports = (function() { } } - var eventGenerator = new NodeEventGenerator(api); + let eventGenerator = new NodeEventGenerator(api); eventGenerator = new CodePathAnalyzer(eventGenerator); eventGenerator = new CommentEventGenerator(eventGenerator, sourceCode); @@ -912,7 +910,7 @@ module.exports = (function() { // sort by line and column messages.sort(function(a, b) { - var lineDiff = a.line - b.line; + let lineDiff = a.line - b.line; if (lineDiff === 0) { return a.column - b.column; @@ -954,7 +952,10 @@ module.exports = (function() { location = node.loc.start; } - // else, assume location was provided, so node may be omitted + // Store end location. + let endLocation = location.end; + + location = location.start || location; if (isDisabledByReportingConfig(reportingConfig, ruleId, location)) { return; @@ -971,7 +972,7 @@ module.exports = (function() { }); } - var problem = { + let problem = { ruleId: ruleId, severity: severity, message: message, @@ -981,6 +982,12 @@ module.exports = (function() { source: sourceCode.lines[location.line - 1] || "" }; + // Define endLine and endColumn if exists. + if (endLocation) { + problem.endLine = endLocation.line; + problem.endColumn = endLocation.column + 1; // switch to 1-base instead of 0-base + } + // ensure there's range and text properties, otherwise it's not a valid fix if (fix && Array.isArray(fix.range) && (typeof fix.text === "string")) { @@ -1004,7 +1011,7 @@ module.exports = (function() { }; // methods that exist on SourceCode object - var externalMethods = { + let externalMethods = { getSource: "getText", getSourceLines: "getLines", getAllComments: "getAllComments", @@ -1026,7 +1033,7 @@ module.exports = (function() { // copy over methods Object.keys(externalMethods).forEach(function(methodName) { - var exMethodName = externalMethods[methodName]; + let exMethodName = externalMethods[methodName]; // All functions expected to have less arguments than 5. api[methodName] = function(a, b, c, d, e) { @@ -1050,14 +1057,14 @@ module.exports = (function() { * @returns {Object} An object representing the current node's scope. */ api.getScope = function() { - var parents = traverser.parents(), + let parents = traverser.parents(), scope = currentScopes[0]; // Don't do this for Program nodes - they have no parents if (parents.length) { // if current node introduces a scope, add it to the list - var current = traverser.current(); + let current = traverser.current(); if (currentConfig.parserOptions.ecmaVersion >= 6) { if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) { @@ -1070,7 +1077,7 @@ module.exports = (function() { } // Ascend the current node's parents - for (var i = parents.length - 1; i >= 0; --i) { + for (let i = parents.length - 1; i >= 0; --i) { // Get the innermost scope scope = scopeManager.acquire(parents[i], true); @@ -1096,7 +1103,7 @@ module.exports = (function() { * false if not. */ api.markVariableAsUsed = function(name) { - var scope = this.getScope(), + let scope = this.getScope(), hasGlobalReturn = currentConfig.parserOptions.ecmaFeatures && currentConfig.parserOptions.ecmaFeatures.globalReturn, specialScope = hasGlobalReturn || currentConfig.parserOptions.sourceType === "module", variables, @@ -1140,13 +1147,13 @@ module.exports = (function() { * @param {Function} ruleModule Function from context to object mapping AST node types to event handlers * @returns {void} */ - var defineRule = api.defineRule = function(ruleId, ruleModule) { + let defineRule = api.defineRule = function(ruleId, ruleModule) { rules.define(ruleId, ruleModule); }; /** * Defines many new linting rules. - * @param {object} rulesToDefine map from unique rule identifier to rule + * @param {Object} rulesToDefine map from unique rule identifier to rule * @returns {void} */ api.defineRules = function(rulesToDefine) { diff --git a/tools/eslint/lib/file-finder.js b/tools/eslint/lib/file-finder.js index 45594057000..f003504c25e 100644 --- a/tools/eslint/lib/file-finder.js +++ b/tools/eslint/lib/file-finder.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"); //------------------------------------------------------------------------------ @@ -55,11 +55,11 @@ function FileFinder(files, cwd) { * @returns {Object} Hashmap of filenames */ function normalizeDirectoryEntries(entries, directory, supportedConfigs) { - var fileHash = {}; + let fileHash = {}; entries.forEach(function(entry) { if (supportedConfigs.indexOf(entry) >= 0) { - var resolvedEntry = path.resolve(directory, entry); + let resolvedEntry = path.resolve(directory, entry); if (fs.statSync(resolvedEntry).isFile()) { fileHash[entry] = resolvedEntry; @@ -79,7 +79,7 @@ function normalizeDirectoryEntries(entries, directory, supportedConfigs) { * @returns {string[]} The file paths found. */ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) { - var cache = this.cache, + let cache = this.cache, child, dirs, fileNames, @@ -106,10 +106,10 @@ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) { dirs[searched++] = directory; cache[directory] = []; - var filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames); + let filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames); if (Object.keys(filesMap).length) { - for (var k = 0; k < fileNames.length; k++) { + for (let k = 0; k < fileNames.length; k++) { if (filesMap[fileNames[k]]) { filePath = filesMap[fileNames[k]]; diff --git a/tools/eslint/lib/formatters/checkstyle.js b/tools/eslint/lib/formatters/checkstyle.js index 0bb9627adf2..11ee60490a0 100644 --- a/tools/eslint/lib/formatters/checkstyle.js +++ b/tools/eslint/lib/formatters/checkstyle.js @@ -4,13 +4,15 @@ */ "use strict"; +let xmlEscape = require("../util/xml-escape"); + //------------------------------------------------------------------------------ // Helper Functions //------------------------------------------------------------------------------ /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -22,44 +24,19 @@ function getMessageType(message) { } } -/** - * Returns the escaped value for a character - * @param {string} s string to examine - * @returns {string} severity level - * @private - */ -function xmlEscape(s) { - return ("" + s).replace(/[<>&"']/g, function(c) { - switch (c) { - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - case "\"": - return """; - case "'": - return "'"; - default: - throw new Error("unreachable"); - } - }); -} - //------------------------------------------------------------------------------ // Public Interface //------------------------------------------------------------------------------ module.exports = function(results) { - var output = ""; + let output = ""; output += ""; output += ""; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; output += ""; diff --git a/tools/eslint/lib/formatters/compact.js b/tools/eslint/lib/formatters/compact.js index 0c31b073e3f..72233f6f363 100644 --- a/tools/eslint/lib/formatters/compact.js +++ b/tools/eslint/lib/formatters/compact.js @@ -10,7 +10,7 @@ /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -29,12 +29,12 @@ function getMessageType(message) { module.exports = function(results) { - var output = "", + let output = "", total = 0; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; total += messages.length; diff --git a/tools/eslint/lib/formatters/html.js b/tools/eslint/lib/formatters/html.js index da3f7596fd0..87d2910b48a 100644 --- a/tools/eslint/lib/formatters/html.js +++ b/tools/eslint/lib/formatters/html.js @@ -4,17 +4,17 @@ */ "use strict"; -var lodash = require("lodash"); -var fs = require("fs"); -var path = require("path"); +let lodash = require("lodash"); +let fs = require("fs"); +let path = require("path"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var pageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-page.html"), "utf-8")); -var messageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-message.html"), "utf-8")); -var resultTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-result.html"), "utf-8")); +let pageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-page.html"), "utf-8")); +let messageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-message.html"), "utf-8")); +let resultTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-result.html"), "utf-8")); /** * Given a word and a count, append an s if count is not one. @@ -33,8 +33,8 @@ function pluralize(word, count) { * @returns {string} The formatted string, pluralized where necessary */ function renderSummary(totalErrors, totalWarnings) { - var totalProblems = totalErrors + totalWarnings; - var renderedText = totalProblems + " " + pluralize("problem", totalProblems); + let totalProblems = totalErrors + totalWarnings; + let renderedText = totalProblems + " " + pluralize("problem", totalProblems); if (totalProblems !== 0) { renderedText += " (" + totalErrors + " " + pluralize("error", totalErrors) + ", " + totalWarnings + " " + pluralize("warning", totalWarnings) + ")"; @@ -71,7 +71,7 @@ function renderMessages(messages, parentIndex) { * @returns {string} HTML (table row) describing a message. */ return lodash.map(messages, function(message) { - var lineNumber, + let lineNumber, columnNumber; lineNumber = message.line || 0; @@ -110,7 +110,7 @@ function renderResults(results) { //------------------------------------------------------------------------------ module.exports = function(results) { - var totalErrors, + let totalErrors, totalWarnings; totalErrors = 0; diff --git a/tools/eslint/lib/formatters/jslint-xml.js b/tools/eslint/lib/formatters/jslint-xml.js index 483172ca5d8..11fe812d063 100644 --- a/tools/eslint/lib/formatters/jslint-xml.js +++ b/tools/eslint/lib/formatters/jslint-xml.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let xmlEscape = require("../util/xml-escape"); //------------------------------------------------------------------------------ // Public Interface @@ -12,21 +12,21 @@ var lodash = require("lodash"); module.exports = function(results) { - var output = ""; + let output = ""; output += ""; output += ""; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; output += ""; messages.forEach(function(message) { output += ""; }); diff --git a/tools/eslint/lib/formatters/junit.js b/tools/eslint/lib/formatters/junit.js index c53fd8141ba..6b7bed30a15 100644 --- a/tools/eslint/lib/formatters/junit.js +++ b/tools/eslint/lib/formatters/junit.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let xmlEscape = require("../util/xml-escape"); //------------------------------------------------------------------------------ // Helper Functions @@ -12,7 +12,7 @@ var lodash = require("lodash"); /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -30,28 +30,28 @@ function getMessageType(message) { module.exports = function(results) { - var output = ""; + let output = ""; output += "\n"; output += "\n"; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; if (messages.length) { output += "\n"; } messages.forEach(function(message) { - var type = message.fatal ? "error" : "failure"; + let type = message.fatal ? "error" : "failure"; output += ""; - output += "<" + type + " message=\"" + lodash.escape(message.message || "") + "\">"; + output += "<" + type + " message=\"" + xmlEscape(message.message || "") + "\">"; output += ""; output += ""; diff --git a/tools/eslint/lib/formatters/stylish.js b/tools/eslint/lib/formatters/stylish.js index d8645755bf9..ebcea1ccdbd 100644 --- a/tools/eslint/lib/formatters/stylish.js +++ b/tools/eslint/lib/formatters/stylish.js @@ -4,7 +4,7 @@ */ "use strict"; -var chalk = require("chalk"), +let chalk = require("chalk"), table = require("text-table"); //------------------------------------------------------------------------------ @@ -27,14 +27,14 @@ function pluralize(word, count) { module.exports = function(results) { - var output = "\n", + let output = "\n", total = 0, errors = 0, warnings = 0, summaryColor = "yellow"; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; if (messages.length === 0) { return; @@ -45,7 +45,7 @@ module.exports = function(results) { output += table( messages.map(function(message) { - var messageType; + let messageType; if (message.fatal || message.severity === 2) { messageType = chalk.red("error"); diff --git a/tools/eslint/lib/formatters/table.js b/tools/eslint/lib/formatters/table.js index e2876444556..d760c18ec5f 100644 --- a/tools/eslint/lib/formatters/table.js +++ b/tools/eslint/lib/formatters/table.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var chalk, +let chalk, table, pluralize; @@ -26,7 +26,7 @@ pluralize = require("pluralize"); * @returns {string} A text table. */ function drawTable(messages) { - var rows; + let rows; rows = []; @@ -43,7 +43,7 @@ function drawTable(messages) { ]); messages.forEach(function(message) { - var messageType; + let messageType; if (message.fatal || message.severity === 2) { messageType = chalk.red("error"); @@ -96,7 +96,7 @@ function drawTable(messages) { * @returns {string} A column of text tables. */ function drawReport(results) { - var files; + let files; files = results.map(function(result) { if (!result.messages.length) { @@ -118,7 +118,7 @@ function drawReport(results) { //------------------------------------------------------------------------------ module.exports = function(report) { - var result, + let result, errorCount, warningCount; diff --git a/tools/eslint/lib/formatters/tap.js b/tools/eslint/lib/formatters/tap.js index d898e30393e..c5c70171f1f 100644 --- a/tools/eslint/lib/formatters/tap.js +++ b/tools/eslint/lib/formatters/tap.js @@ -4,7 +4,7 @@ */ "use strict"; -var yaml = require("js-yaml"); +let yaml = require("js-yaml"); //------------------------------------------------------------------------------ // Helper Functions @@ -12,8 +12,8 @@ var yaml = require("js-yaml"); /** * Returns a canonical error level string based upon the error message passed in. - * @param {object} message Individual error message provided by eslint - * @returns {String} Error level string + * @param {Object} message Individual error message provided by eslint + * @returns {string} Error level string */ function getMessageType(message) { if (message.fatal || message.severity === 2) { @@ -25,12 +25,12 @@ function getMessageType(message) { /** * Takes in a JavaScript object and outputs a TAP diagnostics string - * @param {object} diagnostic JavaScript object to be embedded as YAML into output. + * @param {Object} diagnostic JavaScript object to be embedded as YAML into output. * @returns {string} diagnostics string with YAML embedded - TAP version 13 compliant */ function outputDiagnostics(diagnostic) { - var prefix = " "; - var output = prefix + "---\n"; + let prefix = " "; + let output = prefix + "---\n"; output += prefix + yaml.safeDump(diagnostic).split("\n").join("\n" + prefix); output += "...\n"; @@ -42,18 +42,18 @@ function outputDiagnostics(diagnostic) { //------------------------------------------------------------------------------ module.exports = function(results) { - var output = "TAP version 13\n1.." + results.length + "\n"; + let output = "TAP version 13\n1.." + results.length + "\n"; results.forEach(function(result, id) { - var messages = result.messages; - var testResult = "ok"; - var diagnostics = {}; + let messages = result.messages; + let testResult = "ok"; + let diagnostics = {}; if (messages.length > 0) { testResult = "not ok"; messages.forEach(function(message) { - var diagnostic = { + let diagnostic = { message: message.message, severity: getMessageType(message), data: { diff --git a/tools/eslint/lib/formatters/unix.js b/tools/eslint/lib/formatters/unix.js index ce429fee25b..ee4e14929b5 100644 --- a/tools/eslint/lib/formatters/unix.js +++ b/tools/eslint/lib/formatters/unix.js @@ -10,8 +10,8 @@ /** * Returns a canonical error level string based upon the error message passed in. - * @param {object} message Individual error message provided by eslint - * @returns {String} Error level string + * @param {Object} message Individual error message provided by eslint + * @returns {string} Error level string */ function getMessageType(message) { if (message.fatal || message.severity === 2) { @@ -28,12 +28,12 @@ function getMessageType(message) { module.exports = function(results) { - var output = "", + let output = "", total = 0; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; total += messages.length; diff --git a/tools/eslint/lib/formatters/visualstudio.js b/tools/eslint/lib/formatters/visualstudio.js index 5d53dde289e..836577271ea 100644 --- a/tools/eslint/lib/formatters/visualstudio.js +++ b/tools/eslint/lib/formatters/visualstudio.js @@ -11,7 +11,7 @@ /** * Returns the severity of warning or error - * @param {object} message message object to examine + * @param {Object} message message object to examine * @returns {string} severity level * @private */ @@ -30,12 +30,12 @@ function getMessageType(message) { module.exports = function(results) { - var output = "", + let output = "", total = 0; results.forEach(function(result) { - var messages = result.messages; + let messages = result.messages; total += messages.length; diff --git a/tools/eslint/lib/ignored-paths.js b/tools/eslint/lib/ignored-paths.js index 9a7739ebee9..729bddd20a3 100644 --- a/tools/eslint/lib/ignored-paths.js +++ b/tools/eslint/lib/ignored-paths.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), fs = require("fs"), path = require("path"), debug = require("debug"), @@ -23,12 +23,12 @@ debug = debug("eslint:ignored-paths"); // Constants //------------------------------------------------------------------------------ -var ESLINT_IGNORE_FILENAME = ".eslintignore"; -var DEFAULT_IGNORE_DIRS = [ +let ESLINT_IGNORE_FILENAME = ".eslintignore"; +let DEFAULT_IGNORE_DIRS = [ "node_modules/", "bower_components/" ]; -var DEFAULT_OPTIONS = { +let DEFAULT_OPTIONS = { dotfiles: false, cwd: process.cwd() }; @@ -47,15 +47,15 @@ var DEFAULT_OPTIONS = { function findIgnoreFile(cwd) { cwd = cwd || DEFAULT_OPTIONS.cwd; - var ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME); + let ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME); return fs.existsSync(ignoreFilePath) ? ignoreFilePath : ""; } /** * Merge options with defaults - * @param {object} options Options to merge with DEFAULT_OPTIONS constant - * @returns {object} Merged options + * @param {Object} options Options to merge with DEFAULT_OPTIONS constant + * @returns {Object} Merged options */ function mergeDefaultOptions(options) { options = (options || {}); @@ -78,7 +78,7 @@ function IgnoredPaths(options) { /** * add pattern to node-ignore instance - * @param {object} ig, instance of node-ignore + * @param {Object} ig, instance of node-ignore * @param {string} pattern, pattern do add to ig * @returns {array} raw ignore rules */ @@ -88,7 +88,7 @@ function IgnoredPaths(options) { /** * add ignore file to node-ignore instance - * @param {object} ig, instance of node-ignore + * @param {Object} ig, instance of node-ignore * @param {string} filepath, file to add to ig * @returns {array} raw ignore rules */ @@ -124,7 +124,7 @@ function IgnoredPaths(options) { addPattern(this.ig.default, this.defaultPatterns); if (options.ignore !== false) { - var ignorePath; + let ignorePath; if (options.ignorePath) { debug("Using specific ignore file"); @@ -174,9 +174,9 @@ function IgnoredPaths(options) { */ IgnoredPaths.prototype.contains = function(filepath, category) { - var result = false; - var absolutePath = path.resolve(this.options.cwd, filepath); - var relativePath = pathUtil.getRelativePath(absolutePath, this.options.cwd); + let result = false; + let absolutePath = path.resolve(this.options.cwd, filepath); + let relativePath = pathUtil.getRelativePath(absolutePath, this.options.cwd); if ((typeof category === "undefined") || (category === "default")) { result = result || (this.ig.default.filter([relativePath]).length === 0); @@ -195,13 +195,13 @@ IgnoredPaths.prototype.contains = function(filepath, category) { * @returns {string[]} list of glob ignore patterns */ IgnoredPaths.prototype.getIgnoredFoldersGlobPatterns = function() { - var dirs = DEFAULT_IGNORE_DIRS; + let dirs = DEFAULT_IGNORE_DIRS; if (this.options.ignore) { /* eslint-disable no-underscore-dangle */ - var patterns = this.ig.custom._rules.filter(function(rule) { + let patterns = this.ig.custom._rules.filter(function(rule) { return rule.negative; }).map(function(rule) { return rule.origin; diff --git a/tools/eslint/lib/internal-rules/internal-no-invalid-meta.js b/tools/eslint/lib/internal-rules/internal-no-invalid-meta.js new file mode 100644 index 00000000000..820218dc47e --- /dev/null +++ b/tools/eslint/lib/internal-rules/internal-no-invalid-meta.js @@ -0,0 +1,212 @@ +/** + * @fileoverview Internal rule to prevent missing or invalid meta property in core rules. + * @author Vitor Balocco + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Gets the property of the Object node passed in that has the name specified. + * + * @param {string} property Name of the property to return. + * @param {ASTNode} node The ObjectExpression node. + * @returns {ASTNode} The Property node or null if not found. + */ +function getPropertyFromObject(property, node) { + let properties = node.properties; + + for (let i = 0; i < properties.length; i++) { + if (properties[i].key.name === property) { + return properties[i]; + } + } + + return null; +} + +/** + * Extracts the `meta` property from the ObjectExpression that all rules export. + * + * @param {ASTNode} exportsNode ObjectExpression node that the rule exports. + * @returns {ASTNode} The `meta` Property node or null if not found. + */ +function getMetaPropertyFromExportsNode(exportsNode) { + return getPropertyFromObject("meta", exportsNode); +} + +/** + * Whether this `meta` ObjectExpression has a `docs` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs` property exists. + */ +function hasMetaDocs(metaPropertyNode) { + return Boolean(getPropertyFromObject("docs", metaPropertyNode.value)); +} + +/** + * Whether this `meta` ObjectExpression has a `docs.description` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs.description` property exists. + */ +function hasMetaDocsDescription(metaPropertyNode) { + let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); + + return metaDocs && getPropertyFromObject("description", metaDocs.value); +} + +/** + * Whether this `meta` ObjectExpression has a `docs.category` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs.category` property exists. + */ +function hasMetaDocsCategory(metaPropertyNode) { + let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); + + return metaDocs && getPropertyFromObject("category", metaDocs.value); +} + +/** + * Whether this `meta` ObjectExpression has a `docs.recommended` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `docs.recommended` property exists. + */ +function hasMetaDocsRecommended(metaPropertyNode) { + let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); + + return metaDocs && getPropertyFromObject("recommended", metaDocs.value); +} + +/** + * Whether this `meta` ObjectExpression has a `schema` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `schema` property exists. + */ +function hasMetaSchema(metaPropertyNode) { + return getPropertyFromObject("schema", metaPropertyNode.value); +} + +/** + * Whether this `meta` ObjectExpression has a `fixable` property defined or not. + * + * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule. + * @returns {boolean} `true` if a `fixable` property exists. + */ +function hasMetaFixable(metaPropertyNode) { + return getPropertyFromObject("fixable", metaPropertyNode.value); +} + +/** + * Checks the validity of the meta definition of this rule and reports any errors found. + * + * @param {RuleContext} context The ESLint rule context. + * @param {ASTNode} exportsNode ObjectExpression node that the rule exports. + * @param {boolean} ruleIsFixable whether the rule is fixable or not. + * @returns {void} + */ +function checkMetaValidity(context, exportsNode, ruleIsFixable) { + let metaProperty = getMetaPropertyFromExportsNode(exportsNode); + + if (!metaProperty) { + context.report(exportsNode, "Rule is missing a meta property."); + return; + } + + if (!hasMetaDocs(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs property."); + return; + } + + if (!hasMetaDocsDescription(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs.description property."); + return; + } + + if (!hasMetaDocsCategory(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs.category property."); + return; + } + + if (!hasMetaDocsRecommended(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.docs.recommended property."); + return; + } + + if (!hasMetaSchema(metaProperty)) { + context.report(metaProperty, "Rule is missing a meta.schema property."); + return; + } + + if (ruleIsFixable && !hasMetaFixable(metaProperty)) { + context.report(metaProperty, "Rule is fixable, but is missing a meta.fixable property."); + return; + } +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "enforce correct use of `meta` property in core rules", + category: "Internal", + recommended: false + }, + + schema: [] + }, + + create: function(context) { + let metaExportsValue; + let ruleIsFixable = false; + + return { + AssignmentExpression: function(node) { + if (node.left && + node.right && + node.left.type === "MemberExpression" && + node.left.object.name === "module" && + node.left.property.name === "exports") { + + metaExportsValue = node.right; + } + }, + + CallExpression: function(node) { + + // If the rule has a call for `context.report` and a property `fix` + // is being passed in, then we consider that the rule is fixable. + // + // Note that we only look for context.report() calls in the new + // style (with single MessageDescriptor argument), because only + // calls in the new style can specify a fix. + if (node.callee.type === "MemberExpression" && + node.callee.object.type === "Identifier" && + node.callee.object.name === "context" && + node.callee.property.type === "Identifier" && + node.callee.property.name === "report" && + node.arguments.length === 1 && + node.arguments[0].type === "ObjectExpression") { + + if (getPropertyFromObject("fix", node.arguments[0])) { + ruleIsFixable = true; + } + } + }, + + "Program:exit": function() { + checkMetaValidity(context, metaExportsValue, ruleIsFixable); + } + }; + } +}; diff --git a/tools/eslint/lib/load-rules.js b/tools/eslint/lib/load-rules.js index 6691dbba4b3..ed7732db3fe 100644 --- a/tools/eslint/lib/load-rules.js +++ b/tools/eslint/lib/load-rules.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"); //------------------------------------------------------------------------------ @@ -29,7 +29,7 @@ module.exports = function(rulesDir, cwd) { rulesDir = path.resolve(cwd, rulesDir); } - var rules = Object.create(null); + let rules = Object.create(null); fs.readdirSync(rulesDir).forEach(function(file) { if (path.extname(file) !== ".js") { diff --git a/tools/eslint/lib/options.js b/tools/eslint/lib/options.js index eb58a623330..b1ab7eb9675 100644 --- a/tools/eslint/lib/options.js +++ b/tools/eslint/lib/options.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var optionator = require("optionator"); +let optionator = require("optionator"); //------------------------------------------------------------------------------ // Initialization and Public Interface diff --git a/tools/eslint/lib/rule-context.js b/tools/eslint/lib/rule-context.js index 49b4dfc77d5..e0428744b92 100644 --- a/tools/eslint/lib/rule-context.js +++ b/tools/eslint/lib/rule-context.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var RuleFixer = require("./util/rule-fixer"); +let RuleFixer = require("./util/rule-fixer"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var PASSTHROUGHS = [ +let PASSTHROUGHS = [ "getAncestors", "getDeclaredVariables", "getFilename", @@ -111,7 +111,7 @@ RuleContext.prototype = { * @returns {void} */ report: function(nodeOrDescriptor, location, message, opts) { - var descriptor, + let descriptor, fix = null; // check to see if it's a new style call diff --git a/tools/eslint/lib/rules.js b/tools/eslint/lib/rules.js index 24a8fd8a497..3552d494a00 100644 --- a/tools/eslint/lib/rules.js +++ b/tools/eslint/lib/rules.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var loadRules = require("./load-rules"); +let loadRules = require("./load-rules"); //------------------------------------------------------------------------------ // Privates //------------------------------------------------------------------------------ -var rules = Object.create(null); +let rules = Object.create(null); //------------------------------------------------------------------------------ // Public Interface @@ -38,7 +38,7 @@ function define(ruleId, ruleModule) { * @returns {void} */ function load(rulesDir, cwd) { - var newRules = loadRules(rulesDir, cwd); + let newRules = loadRules(rulesDir, cwd); Object.keys(newRules).forEach(function(ruleId) { define(ruleId, newRules[ruleId]); @@ -53,7 +53,7 @@ function load(rulesDir, cwd) { */ function importPlugin(pluginRules, pluginName) { Object.keys(pluginRules).forEach(function(ruleId) { - var qualifiedRuleId = pluginName + "/" + ruleId, + let qualifiedRuleId = pluginName + "/" + ruleId, rule = pluginRules[ruleId]; define(qualifiedRuleId, rule); diff --git a/tools/eslint/lib/rules/.eslintrc.yml b/tools/eslint/lib/rules/.eslintrc.yml new file mode 100644 index 00000000000..fded5b84978 --- /dev/null +++ b/tools/eslint/lib/rules/.eslintrc.yml @@ -0,0 +1,2 @@ +rules: + internal-no-invalid-meta: "error" diff --git a/tools/eslint/lib/rules/accessor-pairs.js b/tools/eslint/lib/rules/accessor-pairs.js index 3ed9f0dc0cc..b80b44dc9fb 100644 --- a/tools/eslint/lib/rules/accessor-pairs.js +++ b/tools/eslint/lib/rules/accessor-pairs.js @@ -28,7 +28,7 @@ function isIdentifier(node, name) { * @returns {boolean} `true` if the node is an argument of the specified method call. */ function isArgumentOfMethodCall(node, index, object, property) { - var parent = node.parent; + let parent = node.parent; return ( parent.type === "CallExpression" && @@ -91,9 +91,9 @@ module.exports = { }] }, create: function(context) { - var config = context.options[0] || {}; - var checkGetWithoutSet = config.getWithoutSet === true; - var checkSetWithoutGet = config.setWithoutGet !== false; + let config = context.options[0] || {}; + let checkGetWithoutSet = config.getWithoutSet === true; + let checkSetWithoutGet = config.setWithoutGet !== false; /** * Checks a object expression to see if it has setter and getter both present or none. @@ -102,14 +102,14 @@ module.exports = { * @private */ function checkLonelySetGet(node) { - var isSetPresent = false; - var isGetPresent = false; - var isDescriptor = isPropertyDescriptor(node); + let isSetPresent = false; + let isGetPresent = false; + let isDescriptor = isPropertyDescriptor(node); - for (var i = 0, end = node.properties.length; i < end; i++) { - var property = node.properties[i]; + for (let i = 0, end = node.properties.length; i < end; i++) { + let property = node.properties[i]; - var propToCheck = ""; + let propToCheck = ""; if (property.kind === "init") { if (isDescriptor && !property.computed) { @@ -139,9 +139,9 @@ module.exports = { } if (checkSetWithoutGet && isSetPresent && !isGetPresent) { - context.report(node, "Getter is not present"); + context.report(node, "Getter is not present."); } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) { - context.report(node, "Setter is not present"); + context.report(node, "Setter is not present."); } } diff --git a/tools/eslint/lib/rules/array-bracket-spacing.js b/tools/eslint/lib/rules/array-bracket-spacing.js index 09598031b49..6e26e0cbd50 100644 --- a/tools/eslint/lib/rules/array-bracket-spacing.js +++ b/tools/eslint/lib/rules/array-bracket-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -40,7 +40,7 @@ module.exports = { ] }, create: function(context) { - var spaced = context.options[0] === "always", + let spaced = context.options[0] === "always", sourceCode = context.getSourceCode(); /** @@ -54,7 +54,7 @@ module.exports = { return context.options[1] ? context.options[1][option] === !spaced : false; } - var options = { + let options = { spaced: spaced, singleElementException: isOptionSet("singleValue"), objectsInArraysException: isOptionSet("objectsInArrays"), @@ -75,9 +75,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space after '" + token.value + "'", + message: "There should be no space after '" + token.value + "'.", fix: function(fixer) { - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); return fixer.removeRange([token.range[1], nextToken.range[0]]); } @@ -94,9 +94,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space before '" + token.value + "'", + message: "There should be no space before '" + token.value + "'.", fix: function(fixer) { - var previousToken = sourceCode.getTokenBefore(token); + let previousToken = sourceCode.getTokenBefore(token); return fixer.removeRange([previousToken.range[1], token.range[0]]); } @@ -113,7 +113,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required after '" + token.value + "'", + message: "A space is required after '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextAfter(token, " "); } @@ -130,7 +130,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required before '" + token.value + "'", + message: "A space is required before '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextBefore(token, " "); } @@ -165,20 +165,20 @@ module.exports = { return; } - var first = sourceCode.getFirstToken(node), + let first = sourceCode.getFirstToken(node), second = sourceCode.getFirstToken(node, 1), penultimate = sourceCode.getLastToken(node, 1), last = sourceCode.getLastToken(node), firstElement = node.elements[0], lastElement = node.elements[node.elements.length - 1]; - var openingBracketMustBeSpaced = + let openingBracketMustBeSpaced = options.objectsInArraysException && isObjectType(firstElement) || options.arraysInArraysException && isArrayType(firstElement) || options.singleElementException && node.elements.length === 1 ? !options.spaced : options.spaced; - var closingBracketMustBeSpaced = + let closingBracketMustBeSpaced = options.objectsInArraysException && isObjectType(lastElement) || options.arraysInArraysException && isArrayType(lastElement) || options.singleElementException && node.elements.length === 1 diff --git a/tools/eslint/lib/rules/array-callback-return.js b/tools/eslint/lib/rules/array-callback-return.js index 714c189c6b5..d72fd57b2e8 100644 --- a/tools/eslint/lib/rules/array-callback-return.js +++ b/tools/eslint/lib/rules/array-callback-return.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/; -var TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/; +let TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/; +let TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/; /** * Checks a given code path segment is reachable. @@ -104,7 +104,7 @@ function isTargetMethod(node) { */ function isCallbackOfArrayMethod(node) { while (node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { @@ -123,14 +123,15 @@ function isCallbackOfArrayMethod(node) { // // setup... // return function callback() { ... }; // })()); - case "ReturnStatement": - var func = astUtils.getUpperFunction(parent); + case "ReturnStatement": { + const func = astUtils.getUpperFunction(parent); if (func === null || !astUtils.isCallee(func)) { return false; } node = func.parent; break; + } // e.g. // Array.from([], function() {}); @@ -176,7 +177,7 @@ module.exports = { }, create: function(context) { - var funcInfo = { + let funcInfo = { upper: null, codePath: null, hasReturn: false, diff --git a/tools/eslint/lib/rules/arrow-body-style.js b/tools/eslint/lib/rules/arrow-body-style.js index 13486fa74bc..16f082edae5 100644 --- a/tools/eslint/lib/rules/arrow-body-style.js +++ b/tools/eslint/lib/rules/arrow-body-style.js @@ -50,11 +50,11 @@ module.exports = { }, create: function(context) { - var options = context.options; - var always = options[0] === "always"; - var asNeeded = !options[0] || options[0] === "as-needed"; - var never = options[0] === "never"; - var requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral; + let options = context.options; + let always = options[0] === "always"; + let asNeeded = !options[0] || options[0] === "as-needed"; + let never = options[0] === "never"; + let requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral; /** * Determines whether a arrow function body needs braces @@ -62,7 +62,7 @@ module.exports = { * @returns {void} */ function validate(node) { - var arrowBody = node.body; + let arrowBody = node.body; if (arrowBody.type === "BlockStatement") { if (never) { @@ -72,7 +72,7 @@ module.exports = { message: "Unexpected block statement surrounding arrow body." }); } else { - var blockBody = arrowBody.body; + let blockBody = arrowBody.body; if (blockBody.length !== 1) { return; diff --git a/tools/eslint/lib/rules/arrow-parens.js b/tools/eslint/lib/rules/arrow-parens.js index 86b972e8009..fd70ee3465a 100644 --- a/tools/eslint/lib/rules/arrow-parens.js +++ b/tools/eslint/lib/rules/arrow-parens.js @@ -26,11 +26,11 @@ module.exports = { }, create: function(context) { - var message = "Expected parentheses around arrow function argument."; - var asNeededMessage = "Unexpected parentheses around single function argument"; - var asNeeded = context.options[0] === "as-needed"; + let message = "Expected parentheses around arrow function argument."; + let asNeededMessage = "Unexpected parentheses around single function argument."; + let asNeeded = context.options[0] === "as-needed"; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines whether a arrow function argument end with `)` @@ -38,7 +38,7 @@ module.exports = { * @returns {void} */ function parens(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); // as-needed: x => x if (asNeeded && node.params.length === 1 && node.params[0].type === "Identifier") { @@ -47,8 +47,8 @@ module.exports = { node: node, message: asNeededMessage, fix: function(fixer) { - var paramToken = context.getTokenAfter(token); - var closingParenToken = context.getTokenAfter(paramToken); + let paramToken = context.getTokenAfter(token); + let closingParenToken = context.getTokenAfter(paramToken); return fixer.replaceTextRange([ token.range[0], @@ -61,7 +61,7 @@ module.exports = { } if (token.type === "Identifier") { - var after = sourceCode.getTokenAfter(token); + let after = sourceCode.getTokenAfter(token); // (x) => x if (after.value !== ")") { diff --git a/tools/eslint/lib/rules/arrow-spacing.js b/tools/eslint/lib/rules/arrow-spacing.js index 3af5ae1f844..354c860c7b0 100644 --- a/tools/eslint/lib/rules/arrow-spacing.js +++ b/tools/eslint/lib/rules/arrow-spacing.js @@ -37,13 +37,13 @@ module.exports = { create: function(context) { // merge rules with default - var rule = { before: true, after: true }, + let rule = { before: true, after: true }, option = context.options[0] || {}; rule.before = option.before !== false; rule.after = option.after !== false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Get tokens of arrow(`=>`) and before/after arrow. @@ -51,14 +51,14 @@ module.exports = { * @returns {Object} Tokens of arrow and before/after arrow. */ function getTokens(node) { - var t = sourceCode.getFirstToken(node); - var before; + let t = sourceCode.getFirstToken(node); + let before; while (t.type !== "Punctuator" || t.value !== "=>") { before = t; t = sourceCode.getTokenAfter(t); } - var after = sourceCode.getTokenAfter(t); + let after = sourceCode.getTokenAfter(t); return { before: before, arrow: t, after: after }; } @@ -69,8 +69,8 @@ module.exports = { * @returns {Object} count of space before/after arrow. */ function countSpaces(tokens) { - var before = tokens.arrow.range[0] - tokens.before.range[1]; - var after = tokens.after.range[0] - tokens.arrow.range[1]; + let before = tokens.arrow.range[0] - tokens.before.range[1]; + let after = tokens.after.range[0] - tokens.arrow.range[1]; return { before: before, after: after }; } @@ -83,8 +83,8 @@ module.exports = { * @returns {void} */ function spaces(node) { - var tokens = getTokens(node); - var countSpace = countSpaces(tokens); + let tokens = getTokens(node); + let countSpace = countSpaces(tokens); if (rule.before) { @@ -92,7 +92,7 @@ module.exports = { if (countSpace.before === 0) { context.report({ node: tokens.before, - message: "Missing space before =>", + message: "Missing space before =>.", fix: function(fixer) { return fixer.insertTextBefore(tokens.arrow, " "); } @@ -104,7 +104,7 @@ module.exports = { if (countSpace.before > 0) { context.report({ node: tokens.before, - message: "Unexpected space before =>", + message: "Unexpected space before =>.", fix: function(fixer) { return fixer.removeRange([tokens.before.range[1], tokens.arrow.range[0]]); } @@ -118,7 +118,7 @@ module.exports = { if (countSpace.after === 0) { context.report({ node: tokens.after, - message: "Missing space after =>", + message: "Missing space after =>.", fix: function(fixer) { return fixer.insertTextAfter(tokens.arrow, " "); } @@ -130,7 +130,7 @@ module.exports = { if (countSpace.after > 0) { context.report({ node: tokens.after, - message: "Unexpected space after =>", + message: "Unexpected space after =>.", fix: function(fixer) { return fixer.removeRange([tokens.arrow.range[1], tokens.after.range[0]]); } diff --git a/tools/eslint/lib/rules/block-scoped-var.js b/tools/eslint/lib/rules/block-scoped-var.js index 3da07adcba1..f8198ea10ac 100644 --- a/tools/eslint/lib/rules/block-scoped-var.js +++ b/tools/eslint/lib/rules/block-scoped-var.js @@ -20,7 +20,7 @@ module.exports = { }, create: function(context) { - var stack = []; + let stack = []; /** * Makes a block scope. @@ -45,7 +45,7 @@ module.exports = { * @returns {void} */ function report(reference) { - var identifier = reference.identifier; + let identifier = reference.identifier; context.report( identifier, @@ -64,7 +64,7 @@ module.exports = { } // Defines a predicate to check whether or not a given reference is outside of valid scope. - var scopeRange = stack[stack.length - 1]; + let scopeRange = stack[stack.length - 1]; /** * Check if a reference is out of scope @@ -73,15 +73,15 @@ module.exports = { * @private */ function isOutsideOfScope(reference) { - var idRange = reference.identifier.range; + let idRange = reference.identifier.range; return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1]; } // Gets declared variables, and checks its references. - var variables = context.getDeclaredVariables(node); + let variables = context.getDeclaredVariables(node); - for (var i = 0; i < variables.length; ++i) { + for (let i = 0; i < variables.length; ++i) { // Reports. variables[i] diff --git a/tools/eslint/lib/rules/block-spacing.js b/tools/eslint/lib/rules/block-spacing.js index 54ae83d117d..eb24cea319d 100644 --- a/tools/eslint/lib/rules/block-spacing.js +++ b/tools/eslint/lib/rules/block-spacing.js @@ -5,7 +5,7 @@ "use strict"; -var util = require("../ast-utils"); +let util = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var always = (context.options[0] !== "never"), + let always = (context.options[0] !== "never"), message = always ? "Requires a space" : "Unexpected space(s)", sourceCode = context.getSourceCode(); @@ -72,10 +72,10 @@ module.exports = { function checkSpacingInsideBraces(node) { // Gets braces and the first/last token of content. - var openBrace = getOpenBrace(node); - var closeBrace = sourceCode.getLastToken(node); - var firstToken = sourceCode.getTokenOrCommentAfter(openBrace); - var lastToken = sourceCode.getTokenOrCommentBefore(closeBrace); + let openBrace = getOpenBrace(node); + let closeBrace = sourceCode.getLastToken(node); + let firstToken = sourceCode.getTokenOrCommentAfter(openBrace); + let lastToken = sourceCode.getTokenOrCommentBefore(closeBrace); // Skip if the node is invalid or empty. if (openBrace.type !== "Punctuator" || diff --git a/tools/eslint/lib/rules/brace-style.js b/tools/eslint/lib/rules/brace-style.js index 785a71e4e7b..325130a4a2f 100644 --- a/tools/eslint/lib/rules/brace-style.js +++ b/tools/eslint/lib/rules/brace-style.js @@ -34,11 +34,11 @@ module.exports = { }, create: function(context) { - var style = context.options[0] || "1tbs", + let style = context.options[0] || "1tbs", params = context.options[1] || {}, sourceCode = context.getSourceCode(); - var OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.", + let OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.", OPEN_MESSAGE_ALLMAN = "Opening curly brace appears on the same line as controlling statement.", BODY_MESSAGE = "Statement inside of curly braces should be on next line.", CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.", @@ -61,7 +61,7 @@ module.exports = { /** * Check if the token is an punctuator with a value of curly brace - * @param {object} token - Token to check + * @param {Object} token - Token to check * @returns {boolean} true if its a curly punctuator * @private */ @@ -78,11 +78,11 @@ module.exports = { * @private */ function checkBlock() { - var blockProperties = arguments; + let blockProperties = arguments; return function(node) { Array.prototype.forEach.call(blockProperties, function(blockProp) { - var block = node[blockProp], + let block = node[blockProp], previousToken, curlyToken, curlyTokenEnd, @@ -129,7 +129,7 @@ module.exports = { * @private */ function checkIfStatement(node) { - var tokens; + let tokens; checkBlock("consequent", "alternate")(node); @@ -157,7 +157,7 @@ module.exports = { * @private */ function checkTryStatement(node) { - var tokens; + let tokens; checkBlock("block", "finalizer")(node); @@ -180,7 +180,7 @@ module.exports = { * @private */ function checkCatchClause(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), firstToken = sourceCode.getFirstToken(node); checkBlock("body")(node); @@ -205,7 +205,7 @@ module.exports = { * @private */ function checkSwitchStatement(node) { - var tokens; + let tokens; if (node.cases && node.cases.length) { tokens = sourceCode.getTokensBefore(node.cases[0], 2); diff --git a/tools/eslint/lib/rules/callback-return.js b/tools/eslint/lib/rules/callback-return.js index 1d70d0c6373..0b9d4a48941 100644 --- a/tools/eslint/lib/rules/callback-return.js +++ b/tools/eslint/lib/rules/callback-return.js @@ -24,7 +24,7 @@ module.exports = { create: function(context) { - var callbacks = context.options[0] || ["callback", "cb", "next"], + let callbacks = context.options[0] || ["callback", "cb", "next"], sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- @@ -50,7 +50,7 @@ module.exports = { /** * Check to see if a node contains only identifers * @param {ASTNode} node The node to check - * @returns {Boolean} Whether or not the node contains only identifers + * @returns {boolean} Whether or not the node contains only identifers */ function containsOnlyIdentifiers(node) { if (node.type === "Identifier") { @@ -71,7 +71,7 @@ module.exports = { /** * Check to see if a CallExpression is in our callback list. * @param {ASTNode} node The node to check against our callback names list. - * @returns {Boolean} Whether or not this function matches our callback name. + * @returns {boolean} Whether or not this function matches our callback name. */ function isCallback(node) { return containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1; @@ -118,7 +118,7 @@ module.exports = { } // find the closest block, return or loop - var closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {}, + let closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {}, lastItem, parentType; // if our parent is a return we know we're ok diff --git a/tools/eslint/lib/rules/camelcase.js b/tools/eslint/lib/rules/camelcase.js index 28f9e8296b1..b336e595dc9 100644 --- a/tools/eslint/lib/rules/camelcase.js +++ b/tools/eslint/lib/rules/camelcase.js @@ -37,11 +37,11 @@ module.exports = { //-------------------------------------------------------------------------- // contains reported nodes to avoid reporting twice on destructuring with shorthand notation - var reported = []; + let reported = []; /** * Checks if a string contains an underscore and isn't all upper-case - * @param {String} name The string to check. + * @param {string} name The string to check. * @returns {boolean} if the string is underscored * @private */ @@ -64,7 +64,7 @@ module.exports = { } } - var options = context.options[0] || {}, + let options = context.options[0] || {}, properties = options.properties || ""; if (properties !== "always" && properties !== "never") { @@ -79,7 +79,7 @@ module.exports = { * Leading and trailing underscores are commonly used to flag * private/protected identifiers, strip them */ - var name = node.name.replace(/^_+|_+$/g, ""), + let name = node.name.replace(/^_+|_+$/g, ""), effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; // MemberExpressions get special rules diff --git a/tools/eslint/lib/rules/comma-dangle.js b/tools/eslint/lib/rules/comma-dangle.js index d2478cacfb0..69a72e8fcad 100644 --- a/tools/eslint/lib/rules/comma-dangle.js +++ b/tools/eslint/lib/rules/comma-dangle.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); /** * Checks whether or not a trailing comma is allowed in a given node. @@ -45,9 +45,9 @@ module.exports = { }, create: function(context) { - var mode = context.options[0]; - var UNEXPECTED_MESSAGE = "Unexpected trailing comma."; - var MISSING_MESSAGE = "Missing trailing comma."; + let mode = context.options[0]; + let UNEXPECTED_MESSAGE = "Unexpected trailing comma."; + let MISSING_MESSAGE = "Missing trailing comma."; /** * Checks whether or not a given node is multiline. @@ -58,13 +58,13 @@ module.exports = { * @returns {boolean} `true` if the node is multiline. */ function isMultiline(node) { - var lastItem = lodash.last(node.properties || node.elements || node.specifiers); + let lastItem = lodash.last(node.properties || node.elements || node.specifiers); if (!lastItem) { return false; } - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), penultimateToken = sourceCode.getLastToken(lastItem), lastToken = sourceCode.getTokenAfter(penultimateToken); @@ -91,13 +91,13 @@ module.exports = { * @returns {void} */ function forbidTrailingComma(node) { - var lastItem = lodash.last(node.properties || node.elements || node.specifiers); + let lastItem = lodash.last(node.properties || node.elements || node.specifiers); if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { return; } - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), trailingToken; // last item can be surrounded by parentheses for object and array literals @@ -132,7 +132,7 @@ module.exports = { * @returns {void} */ function forceTrailingComma(node) { - var lastItem = lodash.last(node.properties || node.elements || node.specifiers); + let lastItem = lodash.last(node.properties || node.elements || node.specifiers); if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { return; @@ -142,7 +142,7 @@ module.exports = { return; } - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), penultimateToken = lastItem, trailingToken = sourceCode.getTokenAfter(lastItem); @@ -199,7 +199,7 @@ module.exports = { } // Chooses a checking function. - var checkForTrailingComma; + let checkForTrailingComma; if (mode === "always") { checkForTrailingComma = forceTrailingComma; diff --git a/tools/eslint/lib/rules/comma-spacing.js b/tools/eslint/lib/rules/comma-spacing.js index 22fb8b235f5..ea516e03335 100644 --- a/tools/eslint/lib/rules/comma-spacing.js +++ b/tools/eslint/lib/rules/comma-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -38,10 +38,10 @@ module.exports = { create: function(context) { - var sourceCode = context.getSourceCode(); - var tokensAndComments = sourceCode.tokensAndComments; + let sourceCode = context.getSourceCode(); + let tokensAndComments = sourceCode.tokensAndComments; - var options = { + let options = { before: context.options[0] ? !!context.options[0].before : false, after: context.options[0] ? !!context.options[0].after : true }; @@ -51,7 +51,7 @@ module.exports = { //-------------------------------------------------------------------------- // list of comma tokens to ignore for the check of leading whitespace - var commaTokensToIgnore = []; + let commaTokensToIgnore = []; /** * Determines if a given token is a comma operator. @@ -82,8 +82,8 @@ module.exports = { return fixer.insertTextAfter(node, " "); } } else { - var start, end; - var newText = ""; + let start, end; + let newText = ""; if (dir === "before") { start = otherNode.range[1]; @@ -136,10 +136,10 @@ module.exports = { * @returns {void} */ function addNullElementsToIgnoreList(node) { - var previousToken = sourceCode.getFirstToken(node); + let previousToken = sourceCode.getFirstToken(node); node.elements.forEach(function(element) { - var token; + let token; if (element === null) { token = sourceCode.getTokenAfter(previousToken); @@ -162,7 +162,7 @@ module.exports = { return { "Program:exit": function() { - var previousToken, + let previousToken, nextToken; tokensAndComments.forEach(function(token, i) { diff --git a/tools/eslint/lib/rules/comma-style.js b/tools/eslint/lib/rules/comma-style.js index 173df90c33e..69b657f62d4 100644 --- a/tools/eslint/lib/rules/comma-style.js +++ b/tools/eslint/lib/rules/comma-style.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -39,7 +39,7 @@ module.exports = { }, create: function(context) { - var style = context.options[0] || "last", + let style = context.options[0] || "last", exceptions = {}, sourceCode = context.getSourceCode(); @@ -108,7 +108,7 @@ module.exports = { * @returns {void} */ function validateComma(node, property) { - var items = node[property], + let items = node[property], arrayLiteral = (node.type === "ArrayExpression"), previousItemToken; @@ -118,7 +118,7 @@ module.exports = { previousItemToken = sourceCode.getFirstToken(node); items.forEach(function(item) { - var commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken, + let commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken, currentItemToken = item ? sourceCode.getFirstToken(item) : sourceCode.getTokenAfter(commaToken), reportItem = item || currentItemToken, tokenBeforeComma = sourceCode.getTokenBefore(commaToken); @@ -158,7 +158,7 @@ module.exports = { */ if (arrayLiteral) { - var lastToken = sourceCode.getLastToken(node), + let lastToken = sourceCode.getLastToken(node), nextToLastToken = sourceCode.getTokenBefore(lastToken); if (isComma(nextToLastToken)) { @@ -177,7 +177,7 @@ module.exports = { // Public //-------------------------------------------------------------------------- - var nodes = {}; + let nodes = {}; if (!exceptions.VariableDeclaration) { nodes.VariableDeclaration = function(node) { diff --git a/tools/eslint/lib/rules/complexity.js b/tools/eslint/lib/rules/complexity.js index 029b739808d..394df98c44a 100644 --- a/tools/eslint/lib/rules/complexity.js +++ b/tools/eslint/lib/rules/complexity.js @@ -45,7 +45,7 @@ module.exports = { }, create: function(context) { - var option = context.options[0], + let option = context.options[0], THRESHOLD = 20; if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { @@ -63,7 +63,7 @@ module.exports = { //-------------------------------------------------------------------------- // Using a stack to store complexity (handling nested functions) - var fns = []; + let fns = []; /** * When parsing a new function, store it in our function stack @@ -81,7 +81,7 @@ module.exports = { * @private */ function endFunction(node) { - var complexity = fns.pop(), + let complexity = fns.pop(), name = "anonymous"; if (node.id) { diff --git a/tools/eslint/lib/rules/computed-property-spacing.js b/tools/eslint/lib/rules/computed-property-spacing.js index 89f0cc87b1e..1122c5c83c3 100644 --- a/tools/eslint/lib/rules/computed-property-spacing.js +++ b/tools/eslint/lib/rules/computed-property-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -28,8 +28,8 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" + let sourceCode = context.getSourceCode(); + let propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" //-------------------------------------------------------------------------- // Helpers @@ -46,7 +46,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space after '" + token.value + "'", + message: "There should be no space after '" + token.value + "'.", fix: function(fixer) { return fixer.removeRange([token.range[1], tokenAfter.range[0]]); } @@ -64,7 +64,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space before '" + token.value + "'", + message: "There should be no space before '" + token.value + "'.", fix: function(fixer) { return fixer.removeRange([tokenBefore.range[1], token.range[0]]); } @@ -81,7 +81,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required after '" + token.value + "'", + message: "A space is required after '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextAfter(token, " "); } @@ -98,7 +98,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required before '" + token.value + "'", + message: "A space is required before '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextBefore(token, " "); } @@ -108,7 +108,7 @@ module.exports = { /** * Returns a function that checks the spacing of a node on the property name * that was passed in. - * @param {String} propertyName The property on the node to check for spacing + * @param {string} propertyName The property on the node to check for spacing * @returns {Function} A function that will check spacing on a node */ function checkSpacing(propertyName) { @@ -117,9 +117,9 @@ module.exports = { return; } - var property = node[propertyName]; + let property = node[propertyName]; - var before = sourceCode.getTokenBefore(property), + let before = sourceCode.getTokenBefore(property), first = sourceCode.getFirstToken(property), last = sourceCode.getLastToken(property), after = sourceCode.getTokenAfter(property); diff --git a/tools/eslint/lib/rules/consistent-return.js b/tools/eslint/lib/rules/consistent-return.js index 10f1d41cf4b..ffadd31bfd7 100644 --- a/tools/eslint/lib/rules/consistent-return.js +++ b/tools/eslint/lib/rules/consistent-return.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -57,9 +57,9 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true; - var funcInfo = null; + let options = context.options[0] || {}; + let treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true; + let funcInfo = null; /** * Checks whether of not the implicit returning is consistent if the last @@ -69,7 +69,7 @@ module.exports = { * @returns {void} */ function checkLastSegment(node) { - var loc, type; + let loc, type; /* * Skip if it expected no return value or unreachable. @@ -135,8 +135,8 @@ module.exports = { // Reports a given return statement if it's inconsistent. ReturnStatement: function(node) { - var argument = node.argument; - var hasReturnValue = Boolean(argument); + let argument = node.argument; + let hasReturnValue = Boolean(argument); if (treatUndefinedAsUnspecified && hasReturnValue) { hasReturnValue = !isIdentifier(argument, "undefined") && argument.operator !== "void"; diff --git a/tools/eslint/lib/rules/consistent-this.js b/tools/eslint/lib/rules/consistent-this.js index 042e1a0aaed..339c43995e8 100644 --- a/tools/eslint/lib/rules/consistent-this.js +++ b/tools/eslint/lib/rules/consistent-this.js @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var aliases = []; + let aliases = []; if (context.options.length === 0) { aliases.push("that"); @@ -57,7 +57,7 @@ module.exports = { * @returns {void} */ function checkAssignment(node, name, value) { - var isThis = value.type === "ThisExpression"; + let isThis = value.type === "ThisExpression"; if (aliases.indexOf(name) !== -1) { if (!isThis || node.operator && node.operator !== "=") { @@ -73,12 +73,12 @@ module.exports = { * Ensures that a variable declaration of the alias in a program or function * is assigned to the correct value. * @param {string} alias alias the check the assignment of. - * @param {object} scope scope of the current code we are checking. + * @param {Object} scope scope of the current code we are checking. * @private * @returns {void} */ function checkWasAssigned(alias, scope) { - var variable = scope.set.get(alias); + let variable = scope.set.get(alias); if (!variable) { return; @@ -94,7 +94,7 @@ module.exports = { // The alias has been declared and not assigned: check it was // assigned later in the same scope. if (!variable.references.some(function(reference) { - var write = reference.writeExpr; + let write = reference.writeExpr; return ( reference.from === scope && @@ -115,7 +115,7 @@ module.exports = { * @returns {void} */ function ensureWasAssigned() { - var scope = context.getScope(); + let scope = context.getScope(); aliases.forEach(function(alias) { checkWasAssigned(alias, scope); @@ -128,8 +128,8 @@ module.exports = { "FunctionDeclaration:exit": ensureWasAssigned, VariableDeclarator: function(node) { - var id = node.id; - var isDestructuring = + let id = node.id; + let isDestructuring = id.type === "ArrayPattern" || id.type === "ObjectPattern"; if (node.init !== null && !isDestructuring) { diff --git a/tools/eslint/lib/rules/constructor-super.js b/tools/eslint/lib/rules/constructor-super.js index 4b2aacf5755..7b7e8cfd3e9 100644 --- a/tools/eslint/lib/rules/constructor-super.js +++ b/tools/eslint/lib/rules/constructor-super.js @@ -75,10 +75,11 @@ function isPossibleConstructor(node) { isPossibleConstructor(node.consequent) ); - case "SequenceExpression": - var lastExpression = node.expressions[node.expressions.length - 1]; + case "SequenceExpression": { + const lastExpression = node.expressions[node.expressions.length - 1]; return isPossibleConstructor(lastExpression); + } default: return false; @@ -111,7 +112,7 @@ module.exports = { * - scope: The scope of own class. * - codePath: The code path object of the constructor. */ - var funcInfo = null; + let funcInfo = null; /* * {Map} @@ -120,7 +121,7 @@ module.exports = { * - calledInEveryPaths: A flag of be called `super()` in all code paths. * - validNodes: */ - var segInfoMap = Object.create(null); + let segInfoMap = Object.create(null); /** * Gets the flag which shows `super()` is called in some paths. @@ -163,8 +164,8 @@ module.exports = { if (isConstructorFunction(node)) { // Class > ClassBody > MethodDefinition > FunctionExpression - var classNode = node.parent.parent.parent; - var superClass = classNode.superClass; + let classNode = node.parent.parent.parent; + let superClass = classNode.superClass; funcInfo = { upper: funcInfo, @@ -192,7 +193,7 @@ module.exports = { * @returns {void} */ onCodePathEnd: function(codePath, node) { - var hasExtends = funcInfo.hasExtends; + let hasExtends = funcInfo.hasExtends; // Pop. funcInfo = funcInfo.upper; @@ -202,9 +203,9 @@ module.exports = { } // Reports if `super()` lacked. - var segments = codePath.returnedSegments; - var calledInEveryPaths = segments.every(isCalledInEveryPath); - var calledInSomePaths = segments.some(isCalledInSomePath); + let segments = codePath.returnedSegments; + let calledInEveryPaths = segments.every(isCalledInEveryPath); + let calledInSomePaths = segments.some(isCalledInSomePath); if (!calledInEveryPaths) { context.report({ @@ -227,14 +228,14 @@ module.exports = { } // Initialize info. - var info = segInfoMap[segment.id] = { + let info = segInfoMap[segment.id] = { calledInSomePaths: false, calledInEveryPaths: false, validNodes: [] }; // When there are previous segments, aggregates these. - var prevSegments = segment.prevSegments; + let prevSegments = segment.prevSegments; if (prevSegments.length > 0) { info.calledInSomePaths = prevSegments.some(isCalledInSomePath); @@ -257,13 +258,13 @@ module.exports = { } // Update information inside of the loop. - var isRealLoop = toSegment.prevSegments.length >= 2; + let isRealLoop = toSegment.prevSegments.length >= 2; funcInfo.codePath.traverseSegments( {first: toSegment, last: fromSegment}, function(segment) { - var info = segInfoMap[segment.id]; - var prevSegments = segment.prevSegments; + let info = segInfoMap[segment.id]; + let prevSegments = segment.prevSegments; // Updates flags. info.calledInSomePaths = prevSegments.some(isCalledInSomePath); @@ -271,12 +272,12 @@ module.exports = { // If flags become true anew, reports the valid nodes. if (info.calledInSomePaths || isRealLoop) { - var nodes = info.validNodes; + let nodes = info.validNodes; info.validNodes = []; - for (var i = 0; i < nodes.length; ++i) { - var node = nodes[i]; + for (let i = 0; i < nodes.length; ++i) { + let node = nodes[i]; context.report({ message: "Unexpected duplicate 'super()'.", @@ -305,23 +306,22 @@ module.exports = { // Reports if needed. if (funcInfo.hasExtends) { - var segments = funcInfo.codePath.currentSegments; - var reachable = false; - var duplicate = false; + let segments = funcInfo.codePath.currentSegments; + let duplicate = false; + let info = null; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { - var info = segInfoMap[segment.id]; + info = segInfoMap[segment.id]; - reachable = true; duplicate = duplicate || info.calledInSomePaths; info.calledInSomePaths = info.calledInEveryPaths = true; } } - if (reachable) { + if (info) { if (duplicate) { context.report({ message: "Unexpected duplicate 'super()'.", @@ -360,13 +360,13 @@ module.exports = { } // Returning argument is a substitute of 'super()'. - var segments = funcInfo.codePath.currentSegments; + let segments = funcInfo.codePath.currentSegments; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { - var info = segInfoMap[segment.id]; + let info = segInfoMap[segment.id]; info.calledInSomePaths = info.calledInEveryPaths = true; } diff --git a/tools/eslint/lib/rules/curly.js b/tools/eslint/lib/rules/curly.js index 257366fabe8..912f321565e 100644 --- a/tools/eslint/lib/rules/curly.js +++ b/tools/eslint/lib/rules/curly.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -53,12 +53,12 @@ module.exports = { create: function(context) { - var multiOnly = (context.options[0] === "multi"); - var multiLine = (context.options[0] === "multi-line"); - var multiOrNest = (context.options[0] === "multi-or-nest"); - var consistent = (context.options[1] === "consistent"); + let multiOnly = (context.options[0] === "multi"); + let multiLine = (context.options[0] === "multi-line"); + let multiOrNest = (context.options[0] === "multi-or-nest"); + let consistent = (context.options[1] === "consistent"); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -71,7 +71,7 @@ module.exports = { * @private */ function isCollapsedOneLiner(node) { - var before = sourceCode.getTokenBefore(node), + let before = sourceCode.getTokenBefore(node), last = sourceCode.getLastToken(node); return before.loc.start.line === last.loc.end.line; @@ -84,7 +84,7 @@ module.exports = { * @private */ function isOneLiner(node) { - var first = sourceCode.getFirstToken(node), + let first = sourceCode.getFirstToken(node), last = sourceCode.getLastToken(node); return first.loc.start.line === last.loc.end.line; @@ -96,7 +96,7 @@ module.exports = { * @returns {Token} The `else` keyword token. */ function getElseKeyword(node) { - var token = sourceCode.getTokenAfter(node.consequent); + let token = sourceCode.getTokenAfter(node.consequent); while (token.type !== "Keyword" || token.value !== "else") { token = sourceCode.getTokenAfter(token); @@ -180,7 +180,7 @@ module.exports = { * @param {ASTNode} body The body node to check for blocks. * @param {string} name The name to report if there's a problem. * @param {string} suffix Additional string to add to the end of a report. - * @returns {object} a prepared check object, with "actual", "expected", "check" properties. + * @returns {Object} a prepared check object, with "actual", "expected", "check" properties. * "actual" will be `true` or `false` whether the body is already a block statement. * "expected" will be `true` or `false` if the body should be a block statement or not, or * `null` if it doesn't matter, depending on the rule options. It can be modified to change @@ -189,8 +189,8 @@ module.exports = { * properties. */ function prepareCheck(node, body, name, suffix) { - var hasBlock = (body.type === "BlockStatement"); - var expected = null; + let hasBlock = (body.type === "BlockStatement"); + let expected = null; if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) { expected = true; @@ -230,11 +230,11 @@ module.exports = { /** * Prepares to check the bodies of a "if", "else if" and "else" chain. * @param {ASTNode} node The first IfStatement node of the chain. - * @returns {object[]} prepared checks for each body of the chain. See `prepareCheck` for more + * @returns {Object[]} prepared checks for each body of the chain. See `prepareCheck` for more * information. */ function prepareIfChecks(node) { - var preparedChecks = []; + let preparedChecks = []; do { preparedChecks.push(prepareCheck(node, node.consequent, "if", "condition")); @@ -252,7 +252,7 @@ module.exports = { * all have braces. * If all nodes shouldn't have braces, make sure they don't. */ - var expected = preparedChecks.some(function(preparedCheck) { + let expected = preparedChecks.some(function(preparedCheck) { if (preparedCheck.expected !== null) { return preparedCheck.expected; } diff --git a/tools/eslint/lib/rules/default-case.js b/tools/eslint/lib/rules/default-case.js index ae70a59284f..9bcb1c065b8 100644 --- a/tools/eslint/lib/rules/default-case.js +++ b/tools/eslint/lib/rules/default-case.js @@ -4,7 +4,7 @@ */ "use strict"; -var DEFAULT_COMMENT_PATTERN = /^no default$/; +let DEFAULT_COMMENT_PATTERN = /^no default$/; //------------------------------------------------------------------------------ // Rule Definition @@ -30,12 +30,12 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var commentPattern = options.commentPattern ? + let options = context.options[0] || {}; + let commentPattern = options.commentPattern ? new RegExp(options.commentPattern) : DEFAULT_COMMENT_PATTERN; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -67,16 +67,16 @@ module.exports = { return; } - var hasDefault = node.cases.some(function(v) { + let hasDefault = node.cases.some(function(v) { return v.test === null; }); if (!hasDefault) { - var comment; - var comments; + let comment; + let comments; - var lastCase = last(node.cases); + let lastCase = last(node.cases); comments = sourceCode.getComments(lastCase).trailing; diff --git a/tools/eslint/lib/rules/dot-location.js b/tools/eslint/lib/rules/dot-location.js index 2b29e0f49bf..5a5ad353bfd 100644 --- a/tools/eslint/lib/rules/dot-location.js +++ b/tools/eslint/lib/rules/dot-location.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -28,12 +28,12 @@ module.exports = { create: function(context) { - var config = context.options[0]; + let config = context.options[0]; // default to onObject if no preference is passed - var onObject = config === "object" || !config; + let onObject = config === "object" || !config; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports if the dot between object and property is on the correct loccation. @@ -43,7 +43,7 @@ module.exports = { * @returns {void} */ function checkDotLocation(obj, prop, node) { - var dot = sourceCode.getTokenBefore(prop); + let dot = sourceCode.getTokenBefore(prop); if (dot.type === "Punctuator" && dot.value === ".") { if (onObject) { diff --git a/tools/eslint/lib/rules/dot-notation.js b/tools/eslint/lib/rules/dot-notation.js index 07e0b0a8db8..e359b118ccb 100644 --- a/tools/eslint/lib/rules/dot-notation.js +++ b/tools/eslint/lib/rules/dot-notation.js @@ -8,8 +8,8 @@ // Rule Definition //------------------------------------------------------------------------------ -var validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; -var keywords = require("../util/keywords"); +let validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; +let keywords = require("../util/keywords"); module.exports = { meta: { @@ -36,10 +36,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords; + let options = context.options[0] || {}; + let allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords; - var allowPattern; + let allowPattern; if (options.allowPattern) { allowPattern = new RegExp(options.allowPattern); diff --git a/tools/eslint/lib/rules/eol-last.js b/tools/eslint/lib/rules/eol-last.js index 60b070f1abe..faa4521cf12 100644 --- a/tools/eslint/lib/rules/eol-last.js +++ b/tools/eslint/lib/rules/eol-last.js @@ -35,7 +35,7 @@ module.exports = { Program: function checkBadEOF(node) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), src = sourceCode.getText(), location = {column: 1}, linebreakStyle = context.options[0] || "unix", diff --git a/tools/eslint/lib/rules/eqeqeq.js b/tools/eslint/lib/rules/eqeqeq.js index 441f5b751cf..124c9dd61a3 100644 --- a/tools/eslint/lib/rules/eqeqeq.js +++ b/tools/eslint/lib/rules/eqeqeq.js @@ -25,7 +25,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Checks if an expression is a typeof expression @@ -71,12 +71,12 @@ module.exports = { /** * Gets the location (line and column) of the binary expression's operator * @param {ASTNode} node The binary expression node to check - * @param {String} operator The operator to find + * @param {string} operator The operator to find * @returns {Object} { line, column } location of operator * @private */ function getOperatorLocation(node) { - var opToken = sourceCode.getTokenAfter(node.left); + let opToken = sourceCode.getTokenAfter(node.left); return {line: opToken.loc.start.line, column: opToken.loc.start.column}; } diff --git a/tools/eslint/lib/rules/func-names.js b/tools/eslint/lib/rules/func-names.js index 44b989b2c47..12d8d34d5da 100644 --- a/tools/eslint/lib/rules/func-names.js +++ b/tools/eslint/lib/rules/func-names.js @@ -5,6 +5,15 @@ "use strict"; +/** + * Checks whether or not a given variable is a function name. + * @param {escope.Variable} variable - A variable to check. + * @returns {boolean} `true` if the variable is a function name. + */ +function isFunctionName(variable) { + return variable && variable.defs[0].type === "FunctionName"; +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -25,7 +34,7 @@ module.exports = { }, create: function(context) { - var never = context.options[0] === "never"; + let never = context.options[0] === "never"; /** * Determines whether the current FunctionExpression node is a get, set, or @@ -33,7 +42,7 @@ module.exports = { * @returns {boolean} True if the node is a get, set, or shorthand method. */ function isObjectOrClassMethod() { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); return (parent.type === "MethodDefinition" || ( parent.type === "Property" && ( @@ -45,9 +54,16 @@ module.exports = { } return { - FunctionExpression: function(node) { + "FunctionExpression:exit": function(node) { + + // Skip recursive functions. + let nameVar = context.getDeclaredVariables(node)[0]; + + if (isFunctionName(nameVar) && nameVar.references.length > 0) { + return; + } - var name = node.id && node.id.name; + let name = node.id && node.id.name; if (never) { if (name) { diff --git a/tools/eslint/lib/rules/func-style.js b/tools/eslint/lib/rules/func-style.js index 9dad6c07556..e1cdc1d1bd1 100644 --- a/tools/eslint/lib/rules/func-style.js +++ b/tools/eslint/lib/rules/func-style.js @@ -34,12 +34,12 @@ module.exports = { create: function(context) { - var style = context.options[0], + let style = context.options[0], allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions === true, enforceDeclarations = (style === "declaration"), stack = []; - var nodesToCheck = { + let nodesToCheck = { Program: function() { stack = []; }, @@ -79,7 +79,7 @@ module.exports = { }; nodesToCheck["ArrowFunctionExpression:exit"] = function(node) { - var hasThisExpr = stack.pop(); + let hasThisExpr = stack.pop(); if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") { context.report(node.parent, "Expected a function declaration."); diff --git a/tools/eslint/lib/rules/generator-star-spacing.js b/tools/eslint/lib/rules/generator-star-spacing.js index 0cab2be50eb..e55fe9b5121 100644 --- a/tools/eslint/lib/rules/generator-star-spacing.js +++ b/tools/eslint/lib/rules/generator-star-spacing.js @@ -40,7 +40,7 @@ module.exports = { create: function(context) { - var mode = (function(option) { + let mode = (function(option) { if (!option || typeof option === "string") { return { before: { before: true, after: false }, @@ -52,7 +52,7 @@ module.exports = { return option; }(context.options[0])); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Gets `*` token from a given node. @@ -63,7 +63,7 @@ module.exports = { * @returns {Token} `*` token. */ function getStarToken(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); while (token.value !== "*") { token = sourceCode.getTokenAfter(token); @@ -83,11 +83,11 @@ module.exports = { */ function checkSpacing(side, leftToken, rightToken) { if (!!(rightToken.range[0] - leftToken.range[1]) !== mode[side]) { - var after = leftToken.value === "*"; - var spaceRequired = mode[side]; - var node = after ? leftToken : rightToken; - var type = spaceRequired ? "Missing" : "Unexpected"; - var message = type + " space " + side + " *."; + let after = leftToken.value === "*"; + let spaceRequired = mode[side]; + let node = after ? leftToken : rightToken; + let type = spaceRequired ? "Missing" : "Unexpected"; + let message = type + " space " + side + " *."; context.report({ node: node, @@ -111,7 +111,7 @@ module.exports = { * @returns {void} */ function checkFunction(node) { - var prevToken, starToken, nextToken; + let prevToken, starToken, nextToken; if (!node.generator) { return; diff --git a/tools/eslint/lib/rules/global-require.js b/tools/eslint/lib/rules/global-require.js index d1298719a9a..0a104bc3493 100644 --- a/tools/eslint/lib/rules/global-require.js +++ b/tools/eslint/lib/rules/global-require.js @@ -5,7 +5,7 @@ "use strict"; -var ACCEPTABLE_PARENTS = [ +let ACCEPTABLE_PARENTS = [ "AssignmentExpression", "VariableDeclarator", "MemberExpression", @@ -23,7 +23,7 @@ var ACCEPTABLE_PARENTS = [ * @returns {Reference|null} Returns the found reference or null if none were found. */ function findReference(scope, node) { - var references = scope.references.filter(function(reference) { + let references = scope.references.filter(function(reference) { return reference.identifier.range[0] === node.range[0] && reference.identifier.range[1] === node.range[1]; }); @@ -43,7 +43,7 @@ function findReference(scope, node) { * @returns {boolean} Whether or not the name is shadowed. */ function isShadowed(scope, node) { - var reference = findReference(scope, node); + let reference = findReference(scope, node); return reference && reference.resolved && reference.resolved.defs.length > 0; } @@ -62,7 +62,7 @@ module.exports = { create: function(context) { return { CallExpression: function(node) { - var currentScope = context.getScope(), + let currentScope = context.getScope(), isGoodRequire; if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) { diff --git a/tools/eslint/lib/rules/guard-for-in.js b/tools/eslint/lib/rules/guard-for-in.js index b43dda39e46..7e4dfbc43e3 100644 --- a/tools/eslint/lib/rules/guard-for-in.js +++ b/tools/eslint/lib/rules/guard-for-in.js @@ -30,7 +30,7 @@ module.exports = { * If the for-in statement has {}, then the real body is the body * of the BlockStatement. Otherwise, just use body as provided. */ - var body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body; + let body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body; if (body && body.type !== "IfStatement") { context.report(node, "The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype."); diff --git a/tools/eslint/lib/rules/handle-callback-err.js b/tools/eslint/lib/rules/handle-callback-err.js index 09bf0da9771..836d3a6de76 100644 --- a/tools/eslint/lib/rules/handle-callback-err.js +++ b/tools/eslint/lib/rules/handle-callback-err.js @@ -26,7 +26,7 @@ module.exports = { create: function(context) { - var errorArgument = context.options[0] || "err"; + let errorArgument = context.options[0] || "err"; /** * Checks if the given argument should be interpreted as a regexp pattern. @@ -34,7 +34,7 @@ module.exports = { * @returns {boolean} Whether or not the string should be interpreted as a pattern. */ function isPattern(stringToCheck) { - var firstChar = stringToCheck[0]; + let firstChar = stringToCheck[0]; return firstChar === "^"; } @@ -46,7 +46,7 @@ module.exports = { */ function matchesConfiguredErrorName(name) { if (isPattern(errorArgument)) { - var regexp = new RegExp(errorArgument); + let regexp = new RegExp(errorArgument); return regexp.test(name); } @@ -55,7 +55,7 @@ module.exports = { /** * Get the parameters of a given function scope. - * @param {object} scope The function scope. + * @param {Object} scope The function scope. * @returns {array} All parameters of the given scope. */ function getParameters(scope) { @@ -70,7 +70,7 @@ module.exports = { * @returns {void} */ function checkForError(node) { - var scope = context.getScope(), + let scope = context.getScope(), parameters = getParameters(scope), firstParameter = parameters[0]; diff --git a/tools/eslint/lib/rules/id-blacklist.js b/tools/eslint/lib/rules/id-blacklist.js index 142d8d21f4b..d2be0d12c30 100644 --- a/tools/eslint/lib/rules/id-blacklist.js +++ b/tools/eslint/lib/rules/id-blacklist.js @@ -34,12 +34,12 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var blacklist = context.options; + let blacklist = context.options; /** * Checks if a string matches the provided pattern - * @param {String} name The string to check. + * @param {string} name The string to check. * @returns {boolean} if the string is a match * @private */ @@ -51,7 +51,7 @@ module.exports = { * Verifies if we should report an error or not based on the effective * parent node and the identifier name. * @param {ASTNode} effectiveParent The effective parent node of the node to be reported - * @param {String} name The identifier name of the identifier node + * @param {string} name The identifier name of the identifier node * @returns {boolean} whether an error should be reported or not */ function shouldReport(effectiveParent, name) { @@ -67,7 +67,7 @@ module.exports = { * @private */ function report(node) { - context.report(node, "Identifier '{{name}}' is blacklisted", { + context.report(node, "Identifier '{{name}}' is blacklisted.", { name: node.name }); } @@ -75,7 +75,7 @@ module.exports = { return { Identifier: function(node) { - var name = node.name, + let name = node.name, effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; // MemberExpressions get special rules diff --git a/tools/eslint/lib/rules/id-length.js b/tools/eslint/lib/rules/id-length.js index 43437513acb..d337cdaccef 100644 --- a/tools/eslint/lib/rules/id-length.js +++ b/tools/eslint/lib/rules/id-length.js @@ -45,18 +45,18 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var minLength = typeof options.min !== "undefined" ? options.min : 2; - var maxLength = typeof options.max !== "undefined" ? options.max : Infinity; - var properties = options.properties !== "never"; - var exceptions = (options.exceptions ? options.exceptions : []) + let options = context.options[0] || {}; + let minLength = typeof options.min !== "undefined" ? options.min : 2; + let maxLength = typeof options.max !== "undefined" ? options.max : Infinity; + let properties = options.properties !== "never"; + let exceptions = (options.exceptions ? options.exceptions : []) .reduce(function(obj, item) { obj[item] = true; return obj; }, {}); - var SUPPORTED_EXPRESSIONS = { + let SUPPORTED_EXPRESSIONS = { MemberExpression: properties && function(parent) { return !parent.computed && ( @@ -87,24 +87,24 @@ module.exports = { return { Identifier: function(node) { - var name = node.name; - var parent = node.parent; + let name = node.name; + let parent = node.parent; - var isShort = name.length < minLength; - var isLong = name.length > maxLength; + let isShort = name.length < minLength; + let isLong = name.length > maxLength; if (!(isShort || isLong) || exceptions[name]) { return; // Nothing to report } - var isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; + let isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) { context.report( node, isShort ? - "Identifier name '{{name}}' is too short. (< {{min}})" : - "Identifier name '{{name}}' is too long. (> {{max}})", + "Identifier name '{{name}}' is too short (< {{min}})." : + "Identifier name '{{name}}' is too long (> {{max}}).", { name: name, min: minLength, max: maxLength } ); } diff --git a/tools/eslint/lib/rules/id-match.js b/tools/eslint/lib/rules/id-match.js index 4c9f4351088..4128cbf3d1a 100644 --- a/tools/eslint/lib/rules/id-match.js +++ b/tools/eslint/lib/rules/id-match.js @@ -38,16 +38,16 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var pattern = context.options[0] || "^.+$", + let pattern = context.options[0] || "^.+$", regexp = new RegExp(pattern); - var options = context.options[1] || {}, + let options = context.options[1] || {}, properties = !!options.properties, onlyDeclarations = !!options.onlyDeclarations; /** * Checks if a string matches the provided pattern - * @param {String} name The string to check. + * @param {string} name The string to check. * @returns {boolean} if the string is a match * @private */ @@ -59,7 +59,7 @@ module.exports = { * Verifies if we should report an error or not based on the effective * parent node and the identifier name. * @param {ASTNode} effectiveParent The effective parent node of the node to be reported - * @param {String} name The identifier name of the identifier node + * @param {string} name The identifier name of the identifier node * @returns {boolean} whether an error should be reported or not */ function shouldReport(effectiveParent, name) { @@ -84,7 +84,7 @@ module.exports = { return { Identifier: function(node) { - var name = node.name, + let name = node.name, parent = node.parent, effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent; @@ -122,7 +122,7 @@ module.exports = { } } else { - var isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator"; + let isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator"; if (onlyDeclarations && !isDeclaration) { return; diff --git a/tools/eslint/lib/rules/indent.js b/tools/eslint/lib/rules/indent.js index 3c0c9827d84..b24f942d1ae 100644 --- a/tools/eslint/lib/rules/indent.js +++ b/tools/eslint/lib/rules/indent.js @@ -11,8 +11,8 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -var util = require("util"); -var lodash = require("lodash"); +let util = require("util"); +let lodash = require("lodash"); module.exports = { meta: { @@ -71,6 +71,10 @@ module.exports = { outerIIFEBody: { type: "integer", minimum: 0 + }, + MemberExpression: { + type: "integer", + minimum: 0 } }, additionalProperties: false @@ -80,12 +84,12 @@ module.exports = { create: function(context) { - var MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}."; - var DEFAULT_VARIABLE_INDENT = 1; + let MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}."; + let DEFAULT_VARIABLE_INDENT = 1; - var indentType = "space"; - var indentSize = 4; - var options = { + let indentType = "space"; + let indentSize = 4; + let options = { SwitchCase: 0, VariableDeclarator: { var: DEFAULT_VARIABLE_INDENT, @@ -95,7 +99,7 @@ module.exports = { outerIIFEBody: null }; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); if (context.options.length) { if (context.options[0] === "tab") { @@ -107,10 +111,10 @@ module.exports = { } if (context.options[1]) { - var opts = context.options[1]; + let opts = context.options[1]; options.SwitchCase = opts.SwitchCase || 0; - var variableDeclaratorRules = opts.VariableDeclarator; + let variableDeclaratorRules = opts.VariableDeclarator; if (typeof variableDeclaratorRules === "number") { options.VariableDeclarator = { @@ -125,15 +129,19 @@ module.exports = { if (typeof opts.outerIIFEBody === "number") { options.outerIIFEBody = opts.outerIIFEBody; } + + if (typeof opts.MemberExpression === "number") { + options.MemberExpression = opts.MemberExpression; + } } } - var indentPattern = { + let indentPattern = { normal: indentType === "space" ? /^ +/ : /^\t+/, excludeCommas: indentType === "space" ? /^[ ,]+/ : /^[\t,]+/ }; - var caseIndentStore = {}; + let caseIndentStore = {}; /** * Reports a given indent violation and properly pluralizes the message @@ -145,13 +153,13 @@ module.exports = { * @returns {void} */ function report(node, needed, gotten, loc, isLastNodeCheck) { - var msgContext = { + let msgContext = { needed: needed, type: indentType, characters: needed === 1 ? "character" : "characters", gotten: gotten }; - var indentChar = indentType === "space" ? " " : "\t"; + let indentChar = indentType === "space" ? " " : "\t"; /** * Responsible for fixing the indentation issue fix @@ -159,10 +167,10 @@ module.exports = { * @private */ function getFixerFunction() { - var rangeToFix = []; + let rangeToFix = []; if (needed > gotten) { - var spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future + let spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future if (isLastNodeCheck === true) { rangeToFix = [ @@ -224,10 +232,10 @@ module.exports = { * @returns {int} Indent */ function getNodeIndent(node, byLastLine, excludeCommas) { - var token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node); - var src = sourceCode.getText(token, token.loc.start.column); - var regExp = excludeCommas ? indentPattern.excludeCommas : indentPattern.normal; - var indent = regExp.exec(src); + let token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node); + let src = sourceCode.getText(token, token.loc.start.column); + let regExp = excludeCommas ? indentPattern.excludeCommas : indentPattern.normal; + let indent = regExp.exec(src); return indent ? indent[0].length : 0; } @@ -239,7 +247,7 @@ module.exports = { * @returns {boolean} true if its the first in the its start line */ function isNodeFirstInLine(node, byEndLocation) { - var firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node), + let firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node), startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line, endLine = firstToken ? firstToken.loc.end.line : -1; @@ -254,7 +262,7 @@ module.exports = { * @returns {void} */ function checkNodeIndent(node, indent, excludeCommas) { - var nodeIndent = getNodeIndent(node, false, excludeCommas); + let nodeIndent = getNodeIndent(node, false, excludeCommas); if ( node.type !== "ArrayExpression" && node.type !== "ObjectExpression" && @@ -274,7 +282,7 @@ module.exports = { function checkNodesIndent(nodes, indent, excludeCommas) { nodes.forEach(function(node) { if (node.type === "IfStatement" && node.alternate) { - var elseToken = sourceCode.getTokenBefore(node.alternate); + let elseToken = sourceCode.getTokenBefore(node.alternate); checkNodeIndent(elseToken, indent, excludeCommas); } @@ -289,8 +297,8 @@ module.exports = { * @returns {void} */ function checkLastNodeLineIndent(node, lastLineIndent) { - var lastToken = sourceCode.getLastToken(node); - var endIndent = getNodeIndent(lastToken, true); + let lastToken = sourceCode.getLastToken(node); + let endIndent = getNodeIndent(lastToken, true); if (endIndent !== lastLineIndent && isNodeFirstInLine(node, true)) { report( @@ -310,7 +318,7 @@ module.exports = { * @returns {void} */ function checkFirstNodeLineIndent(node, firstLineIndent) { - var startIndent = getNodeIndent(node, false); + let startIndent = getNodeIndent(node, false); if (startIndent !== firstLineIndent && isNodeFirstInLine(node)) { report( @@ -323,19 +331,40 @@ module.exports = { } /** - * Returns the VariableDeclarator based on the current node + * Returns a parent node of given node based on a specified type * if not present then return null * @param {ASTNode} node node to examine + * @param {string} type type that is being looked for * @returns {ASTNode|void} if found then node otherwise null */ - function getVariableDeclaratorNode(node) { - var parent = node.parent; + function getParentNodeByType(node, type) { + let parent = node.parent; - while (parent.type !== "VariableDeclarator" && parent.type !== "Program") { + while (parent.type !== type && parent.type !== "Program") { parent = parent.parent; } - return parent.type === "VariableDeclarator" ? parent : null; + return parent.type === type ? parent : null; + } + + /** + * Returns the VariableDeclarator based on the current node + * if not present then return null + * @param {ASTNode} node node to examine + * @returns {ASTNode|void} if found then node otherwise null + */ + function getVariableDeclaratorNode(node) { + return getParentNodeByType(node, "VariableDeclarator"); + } + + /** + * Returns the ExpressionStatement based on the current node + * if not present then return null + * @param {ASTNode} node node to examine + * @returns {ASTNode|void} if found then node otherwise null + */ + function getAssignmentExpressionNode(node) { + return getParentNodeByType(node, "AssignmentExpression"); } /** @@ -358,7 +387,7 @@ module.exports = { * @returns {boolean} True if arguments are multi-line */ function isArgBeforeCalleeNodeMultiline(node) { - var parent = node.parent; + let parent = node.parent; if (parent.arguments.length >= 2 && parent.arguments[1] === node) { return parent.arguments[0].loc.end.line > parent.arguments[0].loc.start.line; @@ -367,19 +396,46 @@ module.exports = { return false; } - /** + /** * Check to see if the node is a file level IIFE * @param {ASTNode} node The function node to check. * @returns {boolean} True if the node is the outer IIFE */ function isOuterIIFE(node) { - var parent = node.parent; + let parent = node.parent; + let stmt = parent.parent; - return ( - parent.type === "CallExpression" && - parent.callee === node && - parent.parent.type === "ExpressionStatement" && - parent.parent.parent && parent.parent.parent.type === "Program" + /* + * Verify that the node is an IIEF + */ + if ( + parent.type !== "CallExpression" || + parent.callee !== node) { + + return false; + } + + /* + * Navigate legal ancestors to determine whether this IIEF is outer + */ + while ( + stmt.type === "UnaryExpression" && ( + stmt.operator === "!" || + stmt.operator === "~" || + stmt.operator === "+" || + stmt.operator === "-") || + stmt.type === "AssignmentExpression" || + stmt.type === "LogicalExpression" || + stmt.type === "SequenceExpression" || + stmt.type === "VariableDeclarator") { + + stmt = stmt.parent; + } + + return (( + stmt.type === "ExpressionStatement" || + stmt.type === "VariableDeclaration") && + stmt.parent && stmt.parent.type === "Program" ); } @@ -403,8 +459,8 @@ module.exports = { * * Looks for 'Models' */ - var calleeNode = node.parent; // FunctionExpression - var indent; + let calleeNode = node.parent; // FunctionExpression + let indent; if (calleeNode.parent && (calleeNode.parent.type === "Property" || @@ -419,7 +475,7 @@ module.exports = { } if (calleeNode.parent.type === "CallExpression") { - var calleeParent = calleeNode.parent; + let calleeParent = calleeNode.parent; if (calleeNode.type !== "FunctionExpression" && calleeNode.type !== "ArrowFunctionExpression") { if (calleeParent && calleeParent.loc.start.line < node.loc.start.line) { @@ -436,7 +492,7 @@ module.exports = { // function body indent should be indent + indent size, unless this // is the outer IIFE and that option is enabled. - var functionOffset = indentSize; + let functionOffset = indentSize; if (options.outerIIFEBody !== null && isOuterIIFE(calleeNode)) { functionOffset = options.outerIIFEBody * indentSize; @@ -444,7 +500,7 @@ module.exports = { indent += functionOffset; // check if the node is inside a variable - var parentVarNode = getVariableDeclaratorNode(node); + let parentVarNode = getVariableDeclaratorNode(node); if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) { indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind]; @@ -464,7 +520,7 @@ module.exports = { * @returns {boolean} Whether or not the block starts and ends on the same line. */ function isSingleLineNode(node) { - var lastToken = sourceCode.getLastToken(node), + let lastToken = sourceCode.getLastToken(node), startLine = node.loc.start.line, endLine = lastToken.loc.end.line; @@ -497,7 +553,7 @@ module.exports = { return; } - var elements = (node.type === "ArrayExpression") ? node.elements : node.properties; + let elements = (node.type === "ArrayExpression") ? node.elements : node.properties; // filter out empty elements example would be [ , 2] so remove first element as espree considers it as null elements = elements.filter(function(elem) { @@ -509,14 +565,14 @@ module.exports = { return; } - var nodeIndent; - var elementsIndent; - var parentVarNode = getVariableDeclaratorNode(node); + let nodeIndent; + let elementsIndent; + let parentVarNode = getVariableDeclaratorNode(node); // TODO - come up with a better strategy in future if (isNodeFirstInLine(node)) { - var parent = node.parent; - var effectiveParent = parent; + let parent = node.parent; + let effectiveParent = parent; if (parent.type === "MemberExpression") { if (isNodeFirstInLine(parent)) { @@ -605,14 +661,14 @@ module.exports = { return; } - var indent; - var nodesToCheck = []; + let indent; + let nodesToCheck = []; /* * For this statements we should check indent from statement beginning, * not from the beginning of the block. */ - var statementsWithProperties = [ + let statementsWithProperties = [ "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration" ]; @@ -647,7 +703,7 @@ module.exports = { */ function filterOutSameLineVars(node) { return node.declarations.reduce(function(finalCollection, elem) { - var lastElem = finalCollection[finalCollection.length - 1]; + let lastElem = finalCollection[finalCollection.length - 1]; if ((elem.loc.start.line !== node.loc.start.line && !lastElem) || (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) { @@ -664,11 +720,11 @@ module.exports = { * @returns {void} */ function checkIndentInVariableDeclarations(node) { - var elements = filterOutSameLineVars(node); - var nodeIndent = getNodeIndent(node); - var lastElement = elements[elements.length - 1]; + let elements = filterOutSameLineVars(node); + let nodeIndent = getNodeIndent(node); + let lastElement = elements[elements.length - 1]; - var elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind]; + let elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind]; // Comma can be placed before declaration checkNodesIndent(elements, elementsIndent, true); @@ -678,7 +734,7 @@ module.exports = { return; } - var tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement); + let tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement); if (tokenBeforeLastElement.value === ",") { @@ -708,8 +764,8 @@ module.exports = { * @returns {int} indent size */ function expectedCaseIndent(node, switchIndent) { - var switchNode = (node.type === "SwitchStatement") ? node : node.parent; - var caseIndent; + let switchNode = (node.type === "SwitchStatement") ? node : node.parent; + let caseIndent; if (caseIndentStore[switchNode.loc.start.line]) { return caseIndentStore[switchNode.loc.start.line]; @@ -772,11 +828,45 @@ module.exports = { checkIndentInArrayOrObjectBlock(node); }, + MemberExpression: function(node) { + if (typeof options.MemberExpression === "undefined") { + return; + } + + if (isSingleLineNode(node)) { + return; + } + + // The typical layout of variable declarations and assignments + // alter the expectation of correct indentation. Skip them. + // TODO: Add appropriate configuration options for variable + // declarations and assignments. + if (getVariableDeclaratorNode(node)) { + return; + } + + if (getAssignmentExpressionNode(node)) { + return; + } + + let propertyIndent = getNodeIndent(node) + indentSize * options.MemberExpression; + + let checkNodes = [node.property]; + + let dot = context.getTokenBefore(node.property); + + if (dot.type === "Punctuator" && dot.value === ".") { + checkNodes.push(dot); + } + + checkNodesIndent(checkNodes, propertyIndent); + }, + SwitchStatement: function(node) { // Switch is not a 'BlockStatement' - var switchIndent = getNodeIndent(node); - var caseIndent = expectedCaseIndent(node, switchIndent); + let switchIndent = getNodeIndent(node); + let caseIndent = expectedCaseIndent(node, switchIndent); checkNodesIndent(node.cases, caseIndent); @@ -790,7 +880,7 @@ module.exports = { if (isSingleLineNode(node)) { return; } - var caseIndent = expectedCaseIndent(node); + let caseIndent = expectedCaseIndent(node); checkNodesIndent(node.consequent, caseIndent + indentSize); } diff --git a/tools/eslint/lib/rules/init-declarations.js b/tools/eslint/lib/rules/init-declarations.js index 66b0a0aea43..e51596f7af5 100644 --- a/tools/eslint/lib/rules/init-declarations.js +++ b/tools/eslint/lib/rules/init-declarations.js @@ -26,8 +26,8 @@ function isForLoop(block) { * @returns {boolean} `true` when the node has its initializer. */ function isInitialized(node) { - var declaration = node.parent; - var block = declaration.parent; + let declaration = node.parent; + let block = declaration.parent; if (isForLoop(block)) { if (block.type === "ForStatement") { @@ -87,11 +87,11 @@ module.exports = { create: function(context) { - var MODE_ALWAYS = "always", + let MODE_ALWAYS = "always", MODE_NEVER = "never"; - var mode = context.options[0] || MODE_ALWAYS; - var params = context.options[1] || {}; + let mode = context.options[0] || MODE_ALWAYS; + let params = context.options[1] || {}; //-------------------------------------------------------------------------- // Public API @@ -100,11 +100,11 @@ module.exports = { return { "VariableDeclaration:exit": function(node) { - var kind = node.kind, + let kind = node.kind, declarations = node.declarations; - for (var i = 0; i < declarations.length; ++i) { - var declaration = declarations[i], + for (let i = 0; i < declarations.length; ++i) { + let declaration = declarations[i], id = declaration.id, initialized = isInitialized(declaration), isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent); diff --git a/tools/eslint/lib/rules/jsx-quotes.js b/tools/eslint/lib/rules/jsx-quotes.js index 6b3a2efef71..c3d87623cdf 100644 --- a/tools/eslint/lib/rules/jsx-quotes.js +++ b/tools/eslint/lib/rules/jsx-quotes.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var QUOTE_SETTINGS = { +let QUOTE_SETTINGS = { "prefer-double": { quote: "\"", description: "singlequote", @@ -54,7 +54,7 @@ module.exports = { }, create: function(context) { - var quoteOption = context.options[0] || "prefer-double", + let quoteOption = context.options[0] || "prefer-double", setting = QUOTE_SETTINGS[quoteOption]; /** @@ -69,7 +69,7 @@ module.exports = { return { JSXAttribute: function(node) { - var attributeValue = node.value; + let attributeValue = node.value; if (attributeValue && astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) { context.report({ diff --git a/tools/eslint/lib/rules/key-spacing.js b/tools/eslint/lib/rules/key-spacing.js index 1cf677865d2..25aba47ba00 100644 --- a/tools/eslint/lib/rules/key-spacing.js +++ b/tools/eslint/lib/rules/key-spacing.js @@ -34,7 +34,7 @@ function last(arr) { * @returns {boolean} True if the candidate property is part of the group. */ function continuesPropertyGroup(lastMember, candidate) { - var groupEndLine = lastMember.loc.start.line, + let groupEndLine = lastMember.loc.start.line, candidateStartLine = candidate.loc.start.line, comments, i; @@ -71,19 +71,15 @@ function isSingleLine(node) { return (node.loc.end.line === node.loc.start.line); } -/** Sets option values from the configured options with defaults +/** + * Initializes a single option property from the configuration with defaults for undefined values * @param {Object} toOptions Object to be initialized * @param {Object} fromOptions Object to be initialized from * @returns {Object} The object with correctly initialized options and values */ -function initOptions(toOptions, fromOptions) { +function initOptionProperty(toOptions, fromOptions) { toOptions.mode = fromOptions.mode || "strict"; - // Set align if exists - multiLine case - if (typeof fromOptions.align !== "undefined") { - toOptions.align = fromOptions.align; - } - // Set value of beforeColon if (typeof fromOptions.beforeColon !== "undefined") { toOptions.beforeColon = +fromOptions.beforeColon; @@ -98,6 +94,55 @@ function initOptions(toOptions, fromOptions) { toOptions.afterColon = 1; } + // Set align if exists + if (typeof fromOptions.align !== "undefined") { + if (typeof fromOptions.align === "object") { + toOptions.align = fromOptions.align; + } else { // "string" + toOptions.align = { + on: fromOptions.align, + mode: toOptions.mode, + beforeColon: toOptions.beforeColon, + afterColon: toOptions.afterColon + }; + } + } + + return toOptions; +} + +/** + * Initializes all the option values (singleLine, multiLine and align) from the configuration with defaults for undefined values + * @param {Object} toOptions Object to be initialized + * @param {Object} fromOptions Object to be initialized from + * @returns {Object} The object with correctly initialized options and values + */ +function initOptions(toOptions, fromOptions) { + if (typeof fromOptions.align === "object") { + + // Initialize the alignment configuration + toOptions.align = initOptionProperty({}, fromOptions.align); + toOptions.align.on = fromOptions.align.on || "colon"; + toOptions.align.mode = fromOptions.align.mode || "strict"; + + toOptions.multiLine = initOptionProperty({}, (fromOptions.multiLine || fromOptions)); + toOptions.singleLine = initOptionProperty({}, (fromOptions.singleLine || fromOptions)); + + } else { // string or undefined + toOptions.multiLine = initOptionProperty({}, (fromOptions.multiLine || fromOptions)); + toOptions.singleLine = initOptionProperty({}, (fromOptions.singleLine || fromOptions)); + + // If alignment options are defined in multiLine, pull them out into the general align configuration + if (toOptions.multiLine.align) { + toOptions.align = { + on: toOptions.multiLine.align.on, + mode: toOptions.multiLine.mode, + beforeColon: toOptions.multiLine.align.beforeColon, + afterColon: toOptions.multiLine.align.afterColon + }; + } + } + return toOptions; } @@ -105,7 +150,7 @@ function initOptions(toOptions, fromOptions) { // Rule Definition //------------------------------------------------------------------------------ -var messages = { +let messages = { key: "{{error}} space after {{computed}}key '{{key}}'.", value: "{{error}} space before value for {{computed}}key '{{key}}'." }; @@ -126,7 +171,29 @@ module.exports = { type: "object", properties: { align: { - enum: ["colon", "value"] + anyOf: [ + { + enum: ["colon", "value"] + }, + { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + on: { + enum: ["colon", "value"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + } + ] }, mode: { enum: ["strict", "minimum"] @@ -162,7 +229,29 @@ module.exports = { type: "object", properties: { align: { - enum: ["colon", "value"] + anyOf: [ + { + enum: ["colon", "value"] + }, + { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + on: { + enum: ["colon", "value"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + } + ] }, mode: { enum: ["strict", "minimum"] @@ -178,6 +267,57 @@ module.exports = { } }, additionalProperties: false + }, + { + type: "object", + properties: { + singleLine: { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + }, + multiLine: { + type: "object", + properties: { + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + }, + align: { + type: "object", + properties: { + mode: { + enum: ["strict", "minimum"] + }, + on: { + enum: ["colon", "value"] + }, + beforeColon: { + type: "boolean" + }, + afterColon: { + type: "boolean" + } + }, + additionalProperties: false + } + }, + additionalProperties: false } ] }] @@ -193,17 +333,18 @@ module.exports = { * align: "colon" // Optional, or "value" * } */ + let options = context.options[0] || {}, + ruleOptions = initOptions({}, options), + multiLineOptions = ruleOptions.multiLine, + singleLineOptions = ruleOptions.singleLine, + alignmentOptions = ruleOptions.align || null; - var options = context.options[0] || {}, - multiLineOptions = initOptions({}, (options.multiLine || options)), - singleLineOptions = initOptions({}, (options.singleLine || options)); - - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines if the given property is key-value property. * @param {ASTNode} property Property node to check. - * @returns {Boolean} Whether the property is a key-value property. + * @returns {boolean} Whether the property is a key-value property. */ function isKeyValueProperty(property) { return !( @@ -220,7 +361,7 @@ module.exports = { * @returns {ASTNode} The last token before a colon punctuator. */ function getLastTokenBeforeColon(node) { - var prevNode; + let prevNode; while (node && (node.type !== "Punctuator" || node.value !== ":")) { prevNode = node; @@ -251,7 +392,7 @@ module.exports = { * @returns {string} The property's key. */ function getKey(property) { - var key = property.key; + let key = property.key; if (property.computed) { return sourceCode.getText().slice(key.range[0], key.range[1]); @@ -271,7 +412,7 @@ module.exports = { * @returns {void} */ function report(property, side, whitespace, expected, mode) { - var diff = whitespace.length - expected, + let diff = whitespace.length - expected, nextColon = getNextColon(property.key), tokenBeforeColon = sourceCode.getTokenBefore(nextColon), tokenAfterColon = sourceCode.getTokenAfter(nextColon), @@ -335,7 +476,7 @@ module.exports = { * @returns {int} Width of the key. */ function getKeyWidth(property) { - var startToken, endToken; + let startToken, endToken; startToken = sourceCode.getFirstToken(property); endToken = getLastTokenBeforeColon(property.key); @@ -349,7 +490,7 @@ module.exports = { * @returns {Object} Whitespace before and after the property's colon. */ function getPropertyWhitespace(property) { - var whitespace = /(\s*):(\s*)/.exec(sourceCode.getText().slice( + let whitespace = /(\s*):(\s*)/.exec(sourceCode.getText().slice( property.key.range[1], property.value.range[0] )); @@ -373,7 +514,7 @@ module.exports = { } return node.properties.reduce(function(groups, property) { - var currentGroup = last(groups), + let currentGroup = last(groups), prev = last(currentGroup); if (!prev || continuesPropertyGroup(prev, property)) { @@ -394,14 +535,22 @@ module.exports = { * @returns {void} */ function verifyGroupAlignment(properties) { - var length = properties.length, + let length = properties.length, widths = properties.map(getKeyWidth), // Width of keys, including quotes targetWidth = Math.max.apply(null, widths), + align = alignmentOptions.on, // "value" or "colon" i, property, whitespace, width, - align = multiLineOptions.align, - beforeColon = multiLineOptions.beforeColon, - afterColon = multiLineOptions.afterColon, - mode = multiLineOptions.mode; + beforeColon, afterColon, mode; + + if (alignmentOptions && length > 1) { // When aligning values within a group, use the alignment configuration. + beforeColon = alignmentOptions.beforeColon; + afterColon = alignmentOptions.afterColon; + mode = alignmentOptions.mode; + } else { + beforeColon = multiLineOptions.beforeColon; + afterColon = multiLineOptions.afterColon; + mode = alignmentOptions.mode; + } // Conditionally include one space before or after colon targetWidth += (align === "colon" ? beforeColon : afterColon); @@ -441,7 +590,7 @@ module.exports = { * @returns {void} */ function verifySpacing(node, lineOptions) { - var actual = getPropertyWhitespace(node); + let actual = getPropertyWhitespace(node); if (actual) { // Object literal getters/setters lack colons report(node, "key", actual.beforeColon, lineOptions.beforeColon, lineOptions.mode); @@ -455,9 +604,9 @@ module.exports = { * @returns {void} */ function verifyListSpacing(properties) { - var length = properties.length; + let length = properties.length; - for (var i = 0; i < length; i++) { + for (let i = 0; i < length; i++) { verifySpacing(properties[i], singleLineOptions); } } @@ -466,7 +615,7 @@ module.exports = { // Public API //-------------------------------------------------------------------------- - if (multiLineOptions.align) { // Verify vertical alignment + if (alignmentOptions) { // Verify vertical alignment return { ObjectExpression: function(node) { diff --git a/tools/eslint/lib/rules/keyword-spacing.js b/tools/eslint/lib/rules/keyword-spacing.js index f771029a581..3c8d171ce86 100644 --- a/tools/eslint/lib/rules/keyword-spacing.js +++ b/tools/eslint/lib/rules/keyword-spacing.js @@ -9,26 +9,26 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"), +let astUtils = require("../ast-utils"), keywords = require("../util/keywords"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var PREV_TOKEN = /^[\)\]\}>]$/; -var NEXT_TOKEN = /^(?:[\(\[\{<~!]|\+\+?|--?)$/; -var PREV_TOKEN_M = /^[\)\]\}>*]$/; -var NEXT_TOKEN_M = /^[\{*]$/; -var TEMPLATE_OPEN_PAREN = /\$\{$/; -var TEMPLATE_CLOSE_PAREN = /^\}/; -var CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/; -var KEYS = keywords.concat(["as", "await", "from", "get", "let", "of", "set", "yield"]); +let PREV_TOKEN = /^[\)\]\}>]$/; +let NEXT_TOKEN = /^(?:[\(\[\{<~!]|\+\+?|--?)$/; +let PREV_TOKEN_M = /^[\)\]\}>*]$/; +let NEXT_TOKEN_M = /^[\{*]$/; +let TEMPLATE_OPEN_PAREN = /\$\{$/; +let TEMPLATE_CLOSE_PAREN = /^\}/; +let CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/; +let KEYS = keywords.concat(["as", "await", "from", "get", "let", "of", "set", "yield"]); // check duplications. (function() { KEYS.sort(); - for (var i = 1; i < KEYS.length; ++i) { + for (let i = 1; i < KEYS.length; ++i) { if (KEYS[i] === KEYS[i - 1]) { throw new Error("Duplication was found in the keyword list: " + KEYS[i]); } @@ -101,7 +101,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports a given token if there are not space(s) before the token. @@ -114,7 +114,7 @@ module.exports = { function expectSpaceBefore(token, pattern) { pattern = pattern || PREV_TOKEN; - var prevToken = sourceCode.getTokenBefore(token); + let prevToken = sourceCode.getTokenBefore(token); if (prevToken && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && @@ -144,7 +144,7 @@ module.exports = { function unexpectSpaceBefore(token, pattern) { pattern = pattern || PREV_TOKEN; - var prevToken = sourceCode.getTokenBefore(token); + let prevToken = sourceCode.getTokenBefore(token); if (prevToken && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && @@ -174,7 +174,7 @@ module.exports = { function expectSpaceAfter(token, pattern) { pattern = pattern || NEXT_TOKEN; - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); if (nextToken && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && @@ -204,7 +204,7 @@ module.exports = { function unexpectSpaceAfter(token, pattern) { pattern = pattern || NEXT_TOKEN; - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); if (nextToken && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && @@ -226,28 +226,28 @@ module.exports = { /** * Parses the option object and determines check methods for each keyword. * - * @param {object|undefined} options - The option object to parse. - * @returns {object} - Normalized option object. + * @param {Object|undefined} options - The option object to parse. + * @returns {Object} - Normalized option object. * Keys are keywords (there are for every keyword). * Values are instances of `{"before": function, "after": function}`. */ function parseOptions(options) { - var before = !options || options.before !== false; - var after = !options || options.after !== false; - var defaultValue = { + let before = !options || options.before !== false; + let after = !options || options.after !== false; + let defaultValue = { before: before ? expectSpaceBefore : unexpectSpaceBefore, after: after ? expectSpaceAfter : unexpectSpaceAfter }; - var overrides = (options && options.overrides) || {}; - var retv = Object.create(null); + let overrides = (options && options.overrides) || {}; + let retv = Object.create(null); - for (var i = 0; i < KEYS.length; ++i) { - var key = KEYS[i]; - var override = overrides[key]; + for (let i = 0; i < KEYS.length; ++i) { + let key = KEYS[i]; + let override = overrides[key]; if (override) { - var thisBefore = ("before" in override) ? override.before : before; - var thisAfter = ("after" in override) ? override.after : after; + let thisBefore = ("before" in override) ? override.before : before; + let thisAfter = ("after" in override) ? override.after : after; retv[key] = { before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore, @@ -261,7 +261,7 @@ module.exports = { return retv; } - var checkMethodMap = parseOptions(context.options[0]); + let checkMethodMap = parseOptions(context.options[0]); /** * Reports a given token if usage of spacing followed by the token is @@ -308,7 +308,7 @@ module.exports = { * @returns {void} */ function checkSpacingAroundFirstToken(node) { - var firstToken = node && sourceCode.getFirstToken(node); + let firstToken = node && sourceCode.getFirstToken(node); if (firstToken && firstToken.type === "Keyword") { checkSpacingAround(firstToken); @@ -326,7 +326,7 @@ module.exports = { * @returns {void} */ function checkSpacingBeforeFirstToken(node) { - var firstToken = node && sourceCode.getFirstToken(node); + let firstToken = node && sourceCode.getFirstToken(node); if (firstToken && firstToken.type === "Keyword") { checkSpacingBefore(firstToken); @@ -342,7 +342,7 @@ module.exports = { */ function checkSpacingAroundTokenBefore(node) { if (node) { - var token = sourceCode.getTokenBefore(node); + let token = sourceCode.getTokenBefore(node); while (token.type !== "Keyword") { token = sourceCode.getTokenBefore(token); @@ -424,7 +424,7 @@ module.exports = { checkSpacingAroundFirstToken(node); // `of` is not a keyword token. - var token = sourceCode.getTokenBefore(node.right); + let token = sourceCode.getTokenBefore(node.right); while (token.value !== "of") { token = sourceCode.getTokenBefore(token); @@ -445,13 +445,13 @@ module.exports = { * @returns {void} */ function checkSpacingForModuleDeclaration(node) { - var firstToken = sourceCode.getFirstToken(node); + let firstToken = sourceCode.getFirstToken(node); checkSpacingBefore(firstToken, PREV_TOKEN_M); checkSpacingAfter(firstToken, NEXT_TOKEN_M); if (node.source) { - var fromToken = sourceCode.getTokenBefore(node.source); + let fromToken = sourceCode.getTokenBefore(node.source); checkSpacingBefore(fromToken, PREV_TOKEN_M); checkSpacingAfter(fromToken, NEXT_TOKEN_M); @@ -466,7 +466,7 @@ module.exports = { * @returns {void} */ function checkSpacingForImportNamespaceSpecifier(node) { - var asToken = sourceCode.getFirstToken(node, 1); + let asToken = sourceCode.getFirstToken(node, 1); checkSpacingBefore(asToken, PREV_TOKEN_M); } @@ -483,7 +483,7 @@ module.exports = { checkSpacingAroundFirstToken(node); } if (node.kind === "get" || node.kind === "set") { - var token = sourceCode.getFirstToken( + let token = sourceCode.getFirstToken( node, node.static ? 1 : 0 ); diff --git a/tools/eslint/lib/rules/linebreak-style.js b/tools/eslint/lib/rules/linebreak-style.js index 5e6b819f3fe..a8a5e4ed884 100644 --- a/tools/eslint/lib/rules/linebreak-style.js +++ b/tools/eslint/lib/rules/linebreak-style.js @@ -28,10 +28,10 @@ module.exports = { create: function(context) { - var EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.", + let EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.", EXPECTED_CRLF_MSG = "Expected linebreaks to be 'CRLF' but found 'LF'."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -41,7 +41,7 @@ module.exports = { * Builds a fix function that replaces text at the specified range in the source text. * @param {int[]} range The range to replace * @param {string} text The text to insert. - * @returns {function} Fixer function + * @returns {Function} Fixer function * @private */ function createFix(range, text) { @@ -56,7 +56,7 @@ module.exports = { return { Program: function checkForlinebreakStyle(node) { - var linebreakStyle = context.options[0] || "unix", + let linebreakStyle = context.options[0] || "unix", expectedLF = linebreakStyle === "unix", expectedLFChars = expectedLF ? "\n" : "\r\n", source = sourceCode.getText(), @@ -65,7 +65,7 @@ module.exports = { index, range; - var i = 0; + let i = 0; while ((match = pattern.exec(source)) !== null) { i++; diff --git a/tools/eslint/lib/rules/lines-around-comment.js b/tools/eslint/lib/rules/lines-around-comment.js index a227fe4184f..70775b42132 100644 --- a/tools/eslint/lib/rules/lines-around-comment.js +++ b/tools/eslint/lib/rules/lines-around-comment.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ @@ -21,7 +21,7 @@ var lodash = require("lodash"), * @returns {Array} An array of line numbers. */ function getEmptyLineNums(lines) { - var emptyLines = lines.map(function(line, i) { + let emptyLines = lines.map(function(line, i) { return { code: line.trim(), num: i + 1 @@ -41,11 +41,11 @@ function getEmptyLineNums(lines) { * @returns {Array} An array of line numbers. */ function getCommentLineNums(comments) { - var lines = []; + let lines = []; comments.forEach(function(token) { - var start = token.loc.start.line; - var end = token.loc.end.line; + let start = token.loc.start.line; + let end = token.loc.end.line; lines.push(start, end); }); @@ -108,7 +108,7 @@ module.exports = { create: function(context) { - var options = context.options[0] ? lodash.assign({}, context.options[0]) : {}; + let options = context.options[0] ? lodash.assign({}, context.options[0]) : {}; options.beforeLineComment = options.beforeLineComment || false; options.afterLineComment = options.afterLineComment || false; @@ -117,9 +117,9 @@ module.exports = { options.allowBlockStart = options.allowBlockStart || false; options.allowBlockEnd = options.allowBlockEnd || false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var lines = sourceCode.lines, + let lines = sourceCode.lines, numLines = lines.length + 1, comments = sourceCode.getAllComments(), commentLines = getCommentLineNums(comments), @@ -141,7 +141,7 @@ module.exports = { * @returns {boolean} True if the comment is not alone. */ function codeAroundComment(node) { - var token; + let token; token = node; do { @@ -184,8 +184,8 @@ module.exports = { * @returns {boolean} True if the comment is at parent start. */ function isCommentAtParentStart(node, nodeType) { - var ancestors = context.getAncestors(); - var parent; + let ancestors = context.getAncestors(); + let parent; if (ancestors.length) { parent = ancestors.pop(); @@ -202,8 +202,8 @@ module.exports = { * @returns {boolean} True if the comment is at parent end. */ function isCommentAtParentEnd(node, nodeType) { - var ancestors = context.getAncestors(); - var parent; + let ancestors = context.getAncestors(); + let parent; if (ancestors.length) { parent = ancestors.pop(); @@ -271,27 +271,27 @@ module.exports = { * Checks if a comment node has lines around it (ignores inline comments) * @param {ASTNode} node The Comment node. * @param {Object} opts Options to determine the newline. - * @param {Boolean} opts.after Should have a newline after this line. - * @param {Boolean} opts.before Should have a newline before this line. + * @param {boolean} opts.after Should have a newline after this line. + * @param {boolean} opts.before Should have a newline before this line. * @returns {void} */ function checkForEmptyLine(node, opts) { - var after = opts.after, + let after = opts.after, before = opts.before; - var prevLineNum = node.loc.start.line - 1, + let prevLineNum = node.loc.start.line - 1, nextLineNum = node.loc.end.line + 1, commentIsNotAlone = codeAroundComment(node); - var blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node), + let blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node), blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(node), objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(node), objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(node), arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(node), arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(node); - var exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed; - var exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed; + let exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed; + let exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed; // ignore top of the file and bottom of the file if (prevLineNum < 1) { @@ -306,14 +306,14 @@ module.exports = { return; } - var previousTokenOrComment = sourceCode.getTokenOrCommentBefore(node); - var nextTokenOrComment = sourceCode.getTokenOrCommentAfter(node); + let previousTokenOrComment = sourceCode.getTokenOrCommentBefore(node); + let nextTokenOrComment = sourceCode.getTokenOrCommentAfter(node); // check for newline before if (!exceptionStartAllowed && before && !lodash.includes(commentAndEmptyLines, prevLineNum) && !(isCommentNodeType(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, node))) { - var lineStart = node.range[0] - node.loc.start.column; - var range = [lineStart, lineStart]; + let lineStart = node.range[0] - node.loc.start.column; + let range = [lineStart, lineStart]; context.report({ node: node, diff --git a/tools/eslint/lib/rules/max-depth.js b/tools/eslint/lib/rules/max-depth.js index 317f06c68f3..dbc1f6d48c5 100644 --- a/tools/eslint/lib/rules/max-depth.js +++ b/tools/eslint/lib/rules/max-depth.js @@ -49,7 +49,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var functionStack = [], + let functionStack = [], option = context.options[0], maxDepth = 4; @@ -88,7 +88,7 @@ module.exports = { * @private */ function pushBlock(node) { - var len = ++functionStack[functionStack.length - 1]; + let len = ++functionStack[functionStack.length - 1]; if (len > maxDepth) { context.report(node, "Blocks are nested too deeply ({{depth}}).", diff --git a/tools/eslint/lib/rules/max-len.js b/tools/eslint/lib/rules/max-len.js index b5813bbfaa7..1bb63990d80 100644 --- a/tools/eslint/lib/rules/max-len.js +++ b/tools/eslint/lib/rules/max-len.js @@ -9,7 +9,7 @@ // Constants //------------------------------------------------------------------------------ -var OPTIONS_SCHEMA = { +let OPTIONS_SCHEMA = { type: "object", properties: { code: { @@ -40,7 +40,7 @@ var OPTIONS_SCHEMA = { additionalProperties: false }; -var OPTIONS_OR_INTEGER_SCHEMA = { +let OPTIONS_OR_INTEGER_SCHEMA = { anyOf: [ OPTIONS_SCHEMA, { @@ -79,9 +79,9 @@ module.exports = { * too many false positives * - We don't care about matching the entire URL, any small segment is fine */ - var URL_REGEXP = /[^:/?#]:\/\/[^?#]/; + let URL_REGEXP = /[^:/?#]:\/\/[^?#]/; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Computes the length of a line that may contain tabs. The width of each @@ -92,10 +92,10 @@ module.exports = { * @private */ function computeLineLength(line, tabWidth) { - var extraCharacterCount = 0; + let extraCharacterCount = 0; line.replace(/\t/g, function(match, offset) { - var totalOffset = offset + extraCharacterCount, + let totalOffset = offset + extraCharacterCount, previousTabStopOffset = tabWidth ? totalOffset % tabWidth : 0, spaceCount = tabWidth - previousTabStopOffset; @@ -105,8 +105,8 @@ module.exports = { } // The options object must be the last option specified… - var lastOption = context.options[context.options.length - 1]; - var options = typeof lastOption === "object" ? Object.create(lastOption) : {}; + let lastOption = context.options[context.options.length - 1]; + let options = typeof lastOption === "object" ? Object.create(lastOption) : {}; // …but max code length… if (typeof context.options[0] === "number") { @@ -118,7 +118,7 @@ module.exports = { options.tabWidth = context.options[1]; } - var maxLength = options.code || 80, + let maxLength = options.code || 80, tabWidth = options.tabWidth || 4, ignorePattern = options.ignorePattern || null, ignoreComments = options.ignoreComments || false, @@ -156,7 +156,7 @@ module.exports = { * @returns {boolean} If the comment covers the entire line */ function isFullLineComment(line, lineNumber, comment) { - var start = comment.loc.start, + let start = comment.loc.start, end = comment.loc.end, isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim(); @@ -188,7 +188,7 @@ module.exports = { function checkProgramForMaxLength(node) { // split (honors line-ending) - var lines = sourceCode.lines, + let lines = sourceCode.lines, // list of comments to ignore comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : [], @@ -199,23 +199,24 @@ module.exports = { lines.forEach(function(line, i) { // i is zero-indexed, line numbers are one-indexed - var lineNumber = i + 1; + let lineNumber = i + 1; /* * if we're checking comment length; we need to know whether this * line is a comment */ - var lineIsComment = false; + let lineIsComment = false; /* * We can short-circuit the comment checks if we're already out of * comments to check. */ if (commentsIndex < comments.length) { + let comment = null; // iterate over comments until we find one past the current line do { - var comment = comments[++commentsIndex]; + comment = comments[++commentsIndex]; } while (comment && comment.loc.start.line <= lineNumber); // and step back by one @@ -234,7 +235,7 @@ module.exports = { return; } - var lineLength = computeLineLength(line, tabWidth); + let lineLength = computeLineLength(line, tabWidth); if (lineIsComment && ignoreComments) { return; diff --git a/tools/eslint/lib/rules/max-lines.js b/tools/eslint/lib/rules/max-lines.js index 751310e81da..1e311eaffbc 100644 --- a/tools/eslint/lib/rules/max-lines.js +++ b/tools/eslint/lib/rules/max-lines.js @@ -8,8 +8,8 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); -var astUtils = require("../ast-utils"); +let lodash = require("lodash"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -52,7 +52,7 @@ module.exports = { }, create: function(context) { - var option = context.options[0], + let option = context.options[0], max = 300; if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") { @@ -63,10 +63,10 @@ module.exports = { max = option; } - var skipComments = option && option.skipComments; - var skipBlankLines = option && option.skipBlankLines; + let skipComments = option && option.skipComments; + let skipBlankLines = option && option.skipBlankLines; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Returns whether or not a token is a comment node type @@ -83,10 +83,10 @@ module.exports = { * @returns {int[]} The line numbers */ function getLinesWithoutCode(comment) { - var start = comment.loc.start.line; - var end = comment.loc.end.line; + let start = comment.loc.start.line; + let end = comment.loc.end.line; - var token; + let token; token = comment; do { @@ -114,7 +114,7 @@ module.exports = { return { "Program:exit": function() { - var lines = sourceCode.lines.map(function(text, i) { + let lines = sourceCode.lines.map(function(text, i) { return { lineNumber: i + 1, text: text }; }); @@ -125,9 +125,9 @@ module.exports = { } if (skipComments) { - var comments = sourceCode.getAllComments(); + let comments = sourceCode.getAllComments(); - var commentLines = lodash.flatten(comments.map(function(comment) { + let commentLines = lodash.flatten(comments.map(function(comment) { return getLinesWithoutCode(comment); })); @@ -139,7 +139,7 @@ module.exports = { if (lines.length > max) { context.report({ loc: { line: 1, column: 0 }, - message: "File must be at most " + max + " lines long" + message: "File must be at most " + max + " lines long." }); } } diff --git a/tools/eslint/lib/rules/max-nested-callbacks.js b/tools/eslint/lib/rules/max-nested-callbacks.js index 06554127c63..a1145c1f1a6 100644 --- a/tools/eslint/lib/rules/max-nested-callbacks.js +++ b/tools/eslint/lib/rules/max-nested-callbacks.js @@ -48,7 +48,7 @@ module.exports = { //-------------------------------------------------------------------------- // Constants //-------------------------------------------------------------------------- - var option = context.options[0], + let option = context.options[0], THRESHOLD = 10; if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { @@ -65,7 +65,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var callbackStack = []; + let callbackStack = []; /** * Checks a given function node for too many callbacks. @@ -74,14 +74,14 @@ module.exports = { * @private */ function checkFunction(node) { - var parent = node.parent; + let parent = node.parent; if (parent.type === "CallExpression") { callbackStack.push(node); } if (callbackStack.length > THRESHOLD) { - var opts = {num: callbackStack.length, max: THRESHOLD}; + let opts = {num: callbackStack.length, max: THRESHOLD}; context.report(node, "Too many nested callbacks ({{num}}). Maximum allowed is {{max}}.", opts); } diff --git a/tools/eslint/lib/rules/max-params.js b/tools/eslint/lib/rules/max-params.js index 5d9d64fac10..9fb922392b6 100644 --- a/tools/eslint/lib/rules/max-params.js +++ b/tools/eslint/lib/rules/max-params.js @@ -45,7 +45,7 @@ module.exports = { create: function(context) { - var option = context.options[0], + let option = context.options[0], numParams = 3; if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { diff --git a/tools/eslint/lib/rules/max-statements-per-line.js b/tools/eslint/lib/rules/max-statements-per-line.js index 55f09746c30..165c6dd1375 100644 --- a/tools/eslint/lib/rules/max-statements-per-line.js +++ b/tools/eslint/lib/rules/max-statements-per-line.js @@ -32,7 +32,7 @@ module.exports = { create: function(context) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), options = context.options[0] || {}, lastStatementLine = 0, numberOfStatementsOnThisLine = 0, @@ -43,7 +43,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/; + let SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/; /** * Gets the actual last token of a given node. @@ -52,7 +52,7 @@ module.exports = { * @returns {Token} The actual last token. */ function getActualLastToken(node) { - var lastToken = sourceCode.getLastToken(node); + let lastToken = sourceCode.getLastToken(node); if (lastToken.value === ";") { lastToken = sourceCode.getTokenBefore(lastToken); @@ -68,7 +68,7 @@ module.exports = { * @returns {void} */ function enterStatement(node) { - var line = node.loc.start.line; + let line = node.loc.start.line; // Skip to allow non-block statements if this is direct child of control statements. // `if (a) foo();` is counted as 1. @@ -100,7 +100,7 @@ module.exports = { * @returns {void} */ function leaveStatement(node) { - var line = getActualLastToken(node).loc.end.line; + let line = getActualLastToken(node).loc.end.line; // Update state. if (line !== lastStatementLine) { diff --git a/tools/eslint/lib/rules/max-statements.js b/tools/eslint/lib/rules/max-statements.js index 72904c64bad..6708be3a12e 100644 --- a/tools/eslint/lib/rules/max-statements.js +++ b/tools/eslint/lib/rules/max-statements.js @@ -58,7 +58,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var functionStack = [], + let functionStack = [], option = context.options[0], maxStatements = 10, ignoreTopLevelFunctions = context.options[1] && context.options[1].ignoreTopLevelFunctions || false, @@ -107,7 +107,7 @@ module.exports = { * @private */ function endFunction(node) { - var count = functionStack.pop(); + let count = functionStack.pop(); if (ignoreTopLevelFunctions && functionStack.length === 0) { topLevelFunctions.push({ node: node, count: count}); @@ -147,8 +147,8 @@ module.exports = { } topLevelFunctions.forEach(function(element) { - var count = element.count; - var node = element.node; + let count = element.count; + let node = element.node; reportIfTooManyStatements(node, count, maxStatements); }); diff --git a/tools/eslint/lib/rules/multiline-ternary.js b/tools/eslint/lib/rules/multiline-ternary.js new file mode 100644 index 00000000000..469eb134ded --- /dev/null +++ b/tools/eslint/lib/rules/multiline-ternary.js @@ -0,0 +1,66 @@ +/** + * @fileoverview Enforce newlines between operands of ternary expressions + * @author Kai Cataldo + */ + +"use strict"; + +let astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "enforce newlines between operands of ternary expressions", + category: "Stylistic Issues", + recommended: false + }, + schema: [] + }, + + create: function(context) { + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Tests whether node is preceded by supplied tokens + * @param {ASTNode} node - node to check + * @param {ASTNode} parentNode - parent of node to report + * @returns {void} + * @private + */ + function reportError(node, parentNode) { + context.report({ + node: node, + message: "Expected newline between {{typeOfError}} of ternary expression.", + data: { + typeOfError: node === parentNode.test ? "test and consequent" : "consequent and alternate" + } + }); + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + ConditionalExpression: function(node) { + let areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(node.test, node.consequent); + let areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(node.consequent, node.alternate); + + if (areTestAndConsequentOnSameLine) { + reportError(node.test, node); + } + + if (areConsequentAndAlternateOnSameLine) { + reportError(node.consequent, node); + } + } + }; + } +}; diff --git a/tools/eslint/lib/rules/new-cap.js b/tools/eslint/lib/rules/new-cap.js index 2dabb30a655..5e1baa540cc 100644 --- a/tools/eslint/lib/rules/new-cap.js +++ b/tools/eslint/lib/rules/new-cap.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var CAPS_ALLOWED = [ +let CAPS_ALLOWED = [ "Array", "Boolean", "Date", @@ -61,7 +61,7 @@ function invert(map, key) { * @returns {Object} Object with cap is new exceptions. */ function calculateCapIsNewExceptions(config) { - var capIsNewExceptions = checkArray(config, "capIsNewExceptions", CAPS_ALLOWED); + let capIsNewExceptions = checkArray(config, "capIsNewExceptions", CAPS_ALLOWED); if (capIsNewExceptions !== CAPS_ALLOWED) { capIsNewExceptions = capIsNewExceptions.concat(CAPS_ALLOWED); @@ -115,19 +115,19 @@ module.exports = { create: function(context) { - var config = context.options[0] ? lodash.assign({}, context.options[0]) : {}; + let config = context.options[0] ? lodash.assign({}, context.options[0]) : {}; config.newIsCap = config.newIsCap !== false; config.capIsNew = config.capIsNew !== false; - var skipProperties = config.properties === false; + let skipProperties = config.properties === false; - var newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {}); + let newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {}); - var capIsNewExceptions = calculateCapIsNewExceptions(config); + let capIsNewExceptions = calculateCapIsNewExceptions(config); - var listeners = {}; + let listeners = {}; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -140,7 +140,7 @@ module.exports = { */ function extractNameFromExpression(node) { - var name = "", + let name = "", property; if (node.callee.type === "MemberExpression") { @@ -164,10 +164,10 @@ module.exports = { * @returns {string} capitalization state: "non-alpha", "lower", or "upper" */ function getCap(str) { - var firstChar = str.charAt(0); + let firstChar = str.charAt(0); - var firstCharLower = firstChar.toLowerCase(); - var firstCharUpper = firstChar.toUpperCase(); + let firstCharLower = firstChar.toLowerCase(); + let firstCharUpper = firstChar.toUpperCase(); if (firstCharLower === firstCharUpper) { @@ -185,7 +185,7 @@ module.exports = { * @param {Object} allowedMap Object mapping calleeName to a Boolean * @param {ASTNode} node CallExpression node * @param {string} calleeName Capitalized callee name from a CallExpression - * @returns {Boolean} Returns true if the callee may be capitalized + * @returns {boolean} Returns true if the callee may be capitalized */ function isCapAllowed(allowedMap, node, calleeName) { if (allowedMap[calleeName] || allowedMap[sourceCode.getText(node.callee)]) { @@ -209,7 +209,7 @@ module.exports = { * @returns {void} */ function report(node, message) { - var callee = node.callee; + let callee = node.callee; if (callee.type === "MemberExpression") { callee = callee.property; @@ -225,11 +225,11 @@ module.exports = { if (config.newIsCap) { listeners.NewExpression = function(node) { - var constructorName = extractNameFromExpression(node); + let constructorName = extractNameFromExpression(node); if (constructorName) { - var capitalization = getCap(constructorName); - var isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName); + let capitalization = getCap(constructorName); + let isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName); if (!isAllowed) { report(node, "A constructor name should not start with a lowercase letter."); @@ -241,11 +241,11 @@ module.exports = { if (config.capIsNew) { listeners.CallExpression = function(node) { - var calleeName = extractNameFromExpression(node); + let calleeName = extractNameFromExpression(node); if (calleeName) { - var capitalization = getCap(calleeName); - var isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName); + let capitalization = getCap(calleeName); + let isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName); if (!isAllowed) { report(node, "A function with a name starting with an uppercase letter should only be used as a constructor."); diff --git a/tools/eslint/lib/rules/new-parens.js b/tools/eslint/lib/rules/new-parens.js index ec6106647af..7ebd144b7ee 100644 --- a/tools/eslint/lib/rules/new-parens.js +++ b/tools/eslint/lib/rules/new-parens.js @@ -21,18 +21,18 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { NewExpression: function(node) { - var tokens = sourceCode.getTokens(node); - var prenticesTokens = tokens.filter(function(token) { + let tokens = sourceCode.getTokens(node); + let prenticesTokens = tokens.filter(function(token) { return token.value === "(" || token.value === ")"; }); if (prenticesTokens.length < 2) { - context.report(node, "Missing '()' invoking a constructor"); + context.report(node, "Missing '()' invoking a constructor."); } } }; diff --git a/tools/eslint/lib/rules/newline-after-var.js b/tools/eslint/lib/rules/newline-after-var.js index 8801407c0bf..cb06c6f2614 100644 --- a/tools/eslint/lib/rules/newline-after-var.js +++ b/tools/eslint/lib/rules/newline-after-var.js @@ -26,16 +26,16 @@ module.exports = { create: function(context) { - var ALWAYS_MESSAGE = "Expected blank line after variable declarations.", + let ALWAYS_MESSAGE = "Expected blank line after variable declarations.", NEVER_MESSAGE = "Unexpected blank line after variable declarations."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); // Default `mode` to "always". - var mode = context.options[0] === "never" ? "never" : "always"; + let mode = context.options[0] === "never" ? "never" : "always"; // Cache starting and ending line numbers of comments for faster lookup - var commentEndLine = sourceCode.getAllComments().reduce(function(result, token) { + let commentEndLine = sourceCode.getAllComments().reduce(function(result, token) { result[token.loc.start.line] = token.loc.end.line; return result; }, {}); @@ -83,7 +83,7 @@ module.exports = { * @returns {boolean} True if `node` is last of their parent block. */ function isLastNode(node) { - var token = sourceCode.getTokenAfter(node); + let token = sourceCode.getTokenAfter(node); return !token || (token.type === "Punctuator" && token.value === "}"); } @@ -95,7 +95,7 @@ module.exports = { * @returns {boolean} True if `token` does not start immediately after a comment */ function hasBlankLineAfterComment(token, commentStartLine) { - var commentEnd = commentEndLine[commentStartLine]; + let commentEnd = commentEndLine[commentStartLine]; // If there's another comment, repeat check for blank line if (commentEndLine[commentEnd + 1]) { @@ -114,7 +114,7 @@ module.exports = { * @returns {void} */ function checkForBlankLine(node) { - var lastToken = sourceCode.getLastToken(node), + let lastToken = sourceCode.getLastToken(node), nextToken = sourceCode.getTokenAfter(node), nextLineNum = lastToken.loc.end.line + 1, noNextLineToken, diff --git a/tools/eslint/lib/rules/newline-before-return.js b/tools/eslint/lib/rules/newline-before-return.js index 5c8a139358c..966ddb9193b 100644 --- a/tools/eslint/lib/rules/newline-before-return.js +++ b/tools/eslint/lib/rules/newline-before-return.js @@ -20,7 +20,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -34,7 +34,7 @@ module.exports = { * @private */ function isPrecededByTokens(node, testTokens) { - var tokenBefore = sourceCode.getTokenBefore(node); + let tokenBefore = sourceCode.getTokenBefore(node); return testTokens.some(function(token) { return tokenBefore.value === token; @@ -48,7 +48,7 @@ module.exports = { * @private */ function isFirstNode(node) { - var parentType = node.parent.type; + let parentType = node.parent.type; if (node.parent.body) { return Array.isArray(node.parent.body) @@ -75,7 +75,7 @@ module.exports = { * @private */ function calcCommentLines(node, lineNumTokenBefore) { - var comments = sourceCode.getComments(node).leading, + let comments = sourceCode.getComments(node).leading, numLinesComments = 0; if (!comments.length) { @@ -109,7 +109,7 @@ module.exports = { * @private */ function hasNewlineBefore(node) { - var tokenBefore = sourceCode.getTokenBefore(node), + let tokenBefore = sourceCode.getTokenBefore(node), lineNumNode = node.loc.start.line, lineNumTokenBefore, commentLines; diff --git a/tools/eslint/lib/rules/newline-per-chained-call.js b/tools/eslint/lib/rules/newline-per-chained-call.js index c412d53e994..068e7b97ae9 100644 --- a/tools/eslint/lib/rules/newline-per-chained-call.js +++ b/tools/eslint/lib/rules/newline-per-chained-call.js @@ -33,10 +33,10 @@ module.exports = { create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, ignoreChainWithDepth = options.ignoreChainWithDepth || 2; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Gets the property text of a given MemberExpression node. @@ -46,9 +46,9 @@ module.exports = { * @returns {string} The property text of the node. */ function getPropertyText(node) { - var prefix = node.computed ? "[" : "."; - var lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g); - var suffix = node.computed && lines.length === 1 ? "]" : ""; + let prefix = node.computed ? "[" : "."; + let lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g); + let suffix = node.computed && lines.length === 1 ? "]" : ""; return prefix + lines[0] + suffix; } @@ -59,9 +59,9 @@ module.exports = { return; } - var callee = node.callee; - var parent = callee.object; - var depth = 1; + let callee = node.callee; + let parent = callee.object; + let depth = 1; while (parent && parent.callee) { depth += 1; diff --git a/tools/eslint/lib/rules/no-alert.js b/tools/eslint/lib/rules/no-alert.js index e491dfefc55..1ff04a3b687 100644 --- a/tools/eslint/lib/rules/no-alert.js +++ b/tools/eslint/lib/rules/no-alert.js @@ -51,7 +51,7 @@ function getPropertyName(memberExpressionNode) { * @returns {Reference|null} Returns the found reference or null if none were found. */ function findReference(scope, node) { - var references = scope.references.filter(function(reference) { + let references = scope.references.filter(function(reference) { return reference.identifier.range[0] === node.range[0] && reference.identifier.range[1] === node.range[1]; }); @@ -70,7 +70,7 @@ function findReference(scope, node) { * @returns {boolean} Whether or not the name is shadowed. */ function isShadowed(scope, globalScope, node) { - var reference = findReference(scope, node); + let reference = findReference(scope, node); return reference && reference.resolved && reference.resolved.defs.length > 0; } @@ -108,7 +108,7 @@ module.exports = { }, create: function(context) { - var globalScope; + let globalScope; return { @@ -117,7 +117,7 @@ module.exports = { }, CallExpression: function(node) { - var callee = node.callee, + let callee = node.callee, identifierName, currentScope = context.getScope(); diff --git a/tools/eslint/lib/rules/no-bitwise.js b/tools/eslint/lib/rules/no-bitwise.js index 0294998ecc1..bfb6c180da4 100644 --- a/tools/eslint/lib/rules/no-bitwise.js +++ b/tools/eslint/lib/rules/no-bitwise.js @@ -8,7 +8,7 @@ // // Set of bitwise operators. // -var BITWISE_OPERATORS = [ +let BITWISE_OPERATORS = [ "^", "|", "&", "<<", ">>", ">>>", "^=", "|=", "&=", "<<=", ">>=", ">>>=", "~" @@ -47,9 +47,9 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var allowed = options.allow || []; - var int32Hint = options.int32Hint === true; + let options = context.options[0] || {}; + let allowed = options.allow || []; + let int32Hint = options.int32Hint === true; /** * Reports an unexpected use of a bitwise operator. diff --git a/tools/eslint/lib/rules/no-caller.js b/tools/eslint/lib/rules/no-caller.js index 0405fdaeb90..75cfb63f65c 100644 --- a/tools/eslint/lib/rules/no-caller.js +++ b/tools/eslint/lib/rules/no-caller.js @@ -25,7 +25,7 @@ module.exports = { return { MemberExpression: function(node) { - var objectName = node.object.name, + let objectName = node.object.name, propertyName = node.property.name; if (objectName === "arguments" && !node.computed && propertyName && propertyName.match(/^calle[er]$/)) { diff --git a/tools/eslint/lib/rules/no-case-declarations.js b/tools/eslint/lib/rules/no-case-declarations.js index 8ef202538ec..6538674d41e 100644 --- a/tools/eslint/lib/rules/no-case-declarations.js +++ b/tools/eslint/lib/rules/no-case-declarations.js @@ -40,8 +40,8 @@ module.exports = { return { SwitchCase: function(node) { - for (var i = 0; i < node.consequent.length; i++) { - var statement = node.consequent[i]; + for (let i = 0; i < node.consequent.length; i++) { + let statement = node.consequent[i]; if (isLexicalDeclaration(statement)) { context.report({ diff --git a/tools/eslint/lib/rules/no-catch-shadow.js b/tools/eslint/lib/rules/no-catch-shadow.js index 4a206833c08..919ad3bc37d 100644 --- a/tools/eslint/lib/rules/no-catch-shadow.js +++ b/tools/eslint/lib/rules/no-catch-shadow.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -34,7 +34,7 @@ module.exports = { /** * Check if the parameters are been shadowed - * @param {object} scope current scope + * @param {Object} scope current scope * @param {string} name parameter name * @returns {boolean} True is its been shadowed */ @@ -49,7 +49,7 @@ module.exports = { return { CatchClause: function(node) { - var scope = context.getScope(); + let scope = context.getScope(); // When blockBindings is enabled, CatchClause creates its own scope // so start from one upper scope to exclude the current node diff --git a/tools/eslint/lib/rules/no-class-assign.js b/tools/eslint/lib/rules/no-class-assign.js index 1e4d3243d8b..e12d3a065a6 100644 --- a/tools/eslint/lib/rules/no-class-assign.js +++ b/tools/eslint/lib/rules/no-class-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-cond-assign.js b/tools/eslint/lib/rules/no-cond-assign.js index e0979ddaf29..5cba25e8c78 100644 --- a/tools/eslint/lib/rules/no-cond-assign.js +++ b/tools/eslint/lib/rules/no-cond-assign.js @@ -4,7 +4,7 @@ */ "use strict"; -var NODE_DESCRIPTIONS = { +let NODE_DESCRIPTIONS = { DoWhileStatement: "a 'do...while' statement", ForStatement: "a 'for' statement", IfStatement: "an 'if' statement", @@ -32,9 +32,9 @@ module.exports = { create: function(context) { - var prohibitAssign = (context.options[0] || "except-parens"); + let prohibitAssign = (context.options[0] || "except-parens"); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check whether an AST node is the test expression for a conditional statement. @@ -53,7 +53,7 @@ module.exports = { * @returns {?Object} The closest ancestor node that represents a conditional statement. */ function findConditionalAncestor(node) { - var currentAncestor = node; + let currentAncestor = node; do { if (isConditionalTestExpression(currentAncestor)) { @@ -70,7 +70,7 @@ module.exports = { * @returns {boolean} `true` if the code is enclosed in parentheses; otherwise, `false`. */ function isParenthesised(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return previousToken.value === "(" && previousToken.range[1] <= node.range[0] && @@ -83,7 +83,7 @@ module.exports = { * @returns {boolean} `true` if the code is enclosed in two sets of parentheses; otherwise, `false`. */ function isParenthesisedTwice(node) { - var previousToken = sourceCode.getTokenBefore(node, 1), + let previousToken = sourceCode.getTokenBefore(node, 1), nextToken = sourceCode.getTokenAfter(node, 1); return isParenthesised(node) && @@ -120,7 +120,7 @@ module.exports = { * @returns {void} */ function testForConditionalAncestor(node) { - var ancestor = findConditionalAncestor(node); + let ancestor = findConditionalAncestor(node); if (ancestor) { context.report(ancestor, "Unexpected assignment within {{type}}.", { diff --git a/tools/eslint/lib/rules/no-confusing-arrow.js b/tools/eslint/lib/rules/no-confusing-arrow.js index 1f18aa35677..42d1f865e27 100644 --- a/tools/eslint/lib/rules/no-confusing-arrow.js +++ b/tools/eslint/lib/rules/no-confusing-arrow.js @@ -6,7 +6,7 @@ "use strict"; -var astUtils = require("../ast-utils.js"); +let astUtils = require("../ast-utils.js"); //------------------------------------------------------------------------------ // Helpers @@ -43,8 +43,8 @@ module.exports = { }, create: function(context) { - var config = context.options[0] || {}; - var sourceCode = context.getSourceCode(); + let config = context.options[0] || {}; + let sourceCode = context.getSourceCode(); /** * Reports if an arrow function contains an ambiguous conditional. @@ -52,7 +52,7 @@ module.exports = { * @returns {void} */ function checkArrowFunc(node) { - var body = node.body; + let body = node.body; if (isConditional(body) && !(config.allowParens && astUtils.isParenthesised(sourceCode, body))) { context.report(node, "Arrow function used ambiguously with a conditional expression."); diff --git a/tools/eslint/lib/rules/no-console.js b/tools/eslint/lib/rules/no-console.js index 18a897409f6..553fc724607 100644 --- a/tools/eslint/lib/rules/no-console.js +++ b/tools/eslint/lib/rules/no-console.js @@ -42,12 +42,12 @@ module.exports = { MemberExpression: function(node) { if (node.object.name === "console") { - var blockConsole = true; + let blockConsole = true; if (context.options.length > 0) { - var allowedProperties = context.options[0].allow; - var passedProperty = node.property.name; - var propertyIsAllowed = (allowedProperties.indexOf(passedProperty) > -1); + let allowedProperties = context.options[0].allow; + let passedProperty = node.property.name; + let propertyIsAllowed = (allowedProperties.indexOf(passedProperty) > -1); if (propertyIsAllowed) { blockConsole = false; diff --git a/tools/eslint/lib/rules/no-const-assign.js b/tools/eslint/lib/rules/no-const-assign.js index 344e05a644e..8015225dbd8 100644 --- a/tools/eslint/lib/rules/no-const-assign.js +++ b/tools/eslint/lib/rules/no-const-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-constant-condition.js b/tools/eslint/lib/rules/no-constant-condition.js index 7c4ede7f78c..b2d3b647386 100644 --- a/tools/eslint/lib/rules/no-constant-condition.js +++ b/tools/eslint/lib/rules/no-constant-condition.js @@ -32,7 +32,7 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, checkLoops = options.checkLoops !== false; //-------------------------------------------------------------------------- @@ -85,13 +85,16 @@ module.exports = { return isConstant(node.left, false) && isConstant(node.right, false) && node.operator !== "in"; - case "LogicalExpression": - var isLeftConstant = isConstant(node.left, inBooleanPosition); - var isRightConstant = isConstant(node.right, inBooleanPosition); - var isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator)); - var isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator)); + + case "LogicalExpression": { + const isLeftConstant = isConstant(node.left, inBooleanPosition); + const isRightConstant = isConstant(node.right, inBooleanPosition); + const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator)); + const isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator)); return (isLeftConstant && isRightConstant) || isLeftShortCircuit || isRightShortCircuit; + } + case "AssignmentExpression": return (node.operator === "=") && isConstant(node.right, inBooleanPosition); diff --git a/tools/eslint/lib/rules/no-continue.js b/tools/eslint/lib/rules/no-continue.js index 246df89ebe4..5e8c059b0ef 100644 --- a/tools/eslint/lib/rules/no-continue.js +++ b/tools/eslint/lib/rules/no-continue.js @@ -24,7 +24,7 @@ module.exports = { return { ContinueStatement: function(node) { - context.report(node, "Unexpected use of continue statement"); + context.report(node, "Unexpected use of continue statement."); } }; diff --git a/tools/eslint/lib/rules/no-control-regex.js b/tools/eslint/lib/rules/no-control-regex.js index 74e03f03c56..4032fb2af77 100644 --- a/tools/eslint/lib/rules/no-control-regex.js +++ b/tools/eslint/lib/rules/no-control-regex.js @@ -33,7 +33,7 @@ module.exports = { return node.value; } else if (typeof node.value === "string") { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); if ((parent.type === "NewExpression" || parent.type === "CallExpression") && parent.callee.type === "Identifier" && parent.callee.name === "RegExp" @@ -53,22 +53,22 @@ module.exports = { /** * Check if given regex string has control characters in it - * @param {String} regexStr regex as string to check - * @returns {Boolean} returns true if finds control characters on given string + * @param {string} regexStr regex as string to check + * @returns {boolean} returns true if finds control characters on given string * @private */ function hasControlCharacters(regexStr) { // check control characters, if RegExp object used - var hasControlChars = /[\x00-\x1f]/.test(regexStr); // eslint-disable-line no-control-regex + let hasControlChars = /[\x00-\x1f]/.test(regexStr); // eslint-disable-line no-control-regex // check substr, if regex literal used - var subStrIndex = regexStr.search(/\\x[01][0-9a-f]/i); + let subStrIndex = regexStr.search(/\\x[01][0-9a-f]/i); if (!hasControlChars && subStrIndex > -1) { // is it escaped, check backslash count - var possibleEscapeCharacters = regexStr.substr(0, subStrIndex).match(/\\+$/gi); + let possibleEscapeCharacters = regexStr.substr(0, subStrIndex).match(/\\+$/gi); hasControlChars = possibleEscapeCharacters === null || !(possibleEscapeCharacters[0].length % 2); } @@ -78,7 +78,7 @@ module.exports = { return { Literal: function(node) { - var computedValue, + let computedValue, regex = getRegExp(node); if (regex) { diff --git a/tools/eslint/lib/rules/no-div-regex.js b/tools/eslint/lib/rules/no-div-regex.js index 75a60855957..f54a534b226 100644 --- a/tools/eslint/lib/rules/no-div-regex.js +++ b/tools/eslint/lib/rules/no-div-regex.js @@ -21,12 +21,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Literal: function(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); if (token.type === "RegularExpression" && token.value[1] === "=") { context.report(node, "A regular expression literal can be confused with '/='."); diff --git a/tools/eslint/lib/rules/no-dupe-args.js b/tools/eslint/lib/rules/no-dupe-args.js index e927ce2b3a8..f63fab5bb24 100644 --- a/tools/eslint/lib/rules/no-dupe-args.js +++ b/tools/eslint/lib/rules/no-dupe-args.js @@ -42,13 +42,13 @@ module.exports = { * @private */ function checkParams(node) { - var variables = context.getDeclaredVariables(node); + let variables = context.getDeclaredVariables(node); - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; // Checks and reports duplications. - var defs = variable.defs.filter(isParameter); + let defs = variable.defs.filter(isParameter); if (defs.length >= 2) { context.report({ diff --git a/tools/eslint/lib/rules/no-dupe-class-members.js b/tools/eslint/lib/rules/no-dupe-class-members.js index 883020bdfe5..102072b8bbe 100644 --- a/tools/eslint/lib/rules/no-dupe-class-members.js +++ b/tools/eslint/lib/rules/no-dupe-class-members.js @@ -21,20 +21,20 @@ module.exports = { }, create: function(context) { - var stack = []; + let stack = []; /** * Gets state of a given member name. * @param {string} name - A name of a member. * @param {boolean} isStatic - A flag which specifies that is a static member. - * @returns {object} A state of a given member name. + * @returns {Object} A state of a given member name. * - retv.init {boolean} A flag which shows the name is declared as normal member. * - retv.get {boolean} A flag which shows the name is declared as getter. * - retv.set {boolean} A flag which shows the name is declared as setter. */ function getState(name, isStatic) { - var stateMap = stack[stack.length - 1]; - var key = "$" + name; // to avoid "__proto__". + let stateMap = stack[stack.length - 1]; + let key = "$" + name; // to avoid "__proto__". if (!stateMap[key]) { stateMap[key] = { @@ -85,9 +85,9 @@ module.exports = { return; } - var name = getName(node.key); - var state = getState(name, node.static); - var isDuplicate = false; + let name = getName(node.key); + let state = getState(name, node.static); + let isDuplicate = false; if (node.kind === "get") { isDuplicate = (state.init || state.get); diff --git a/tools/eslint/lib/rules/no-dupe-keys.js b/tools/eslint/lib/rules/no-dupe-keys.js index 26f009b3bfe..d2a3fc67738 100644 --- a/tools/eslint/lib/rules/no-dupe-keys.js +++ b/tools/eslint/lib/rules/no-dupe-keys.js @@ -28,7 +28,7 @@ module.exports = { // Object that will be a map of properties--safe because we will // prefix all of the keys. - var nodeProps = Object.create(null); + let nodeProps = Object.create(null); node.properties.forEach(function(property) { @@ -36,7 +36,7 @@ module.exports = { return; } - var keyName = property.key.name || property.key.value, + let keyName = property.key.name || property.key.value, key = property.kind + "-" + keyName, checkProperty = (!property.computed || property.key.type === "Literal"); diff --git a/tools/eslint/lib/rules/no-duplicate-case.js b/tools/eslint/lib/rules/no-duplicate-case.js index 8c877ed4e82..9e9b8b5cd8b 100644 --- a/tools/eslint/lib/rules/no-duplicate-case.js +++ b/tools/eslint/lib/rules/no-duplicate-case.js @@ -22,14 +22,14 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { SwitchStatement: function(node) { - var mapping = {}; + let mapping = {}; node.cases.forEach(function(switchCase) { - var key = sourceCode.getText(switchCase.test); + let key = sourceCode.getText(switchCase.test); if (mapping[key]) { context.report(switchCase, "Duplicate case label."); diff --git a/tools/eslint/lib/rules/no-duplicate-imports.js b/tools/eslint/lib/rules/no-duplicate-imports.js index 44432f48635..8594541b14a 100644 --- a/tools/eslint/lib/rules/no-duplicate-imports.js +++ b/tools/eslint/lib/rules/no-duplicate-imports.js @@ -60,7 +60,7 @@ function checkAndReport(context, node, value, array, message) { */ function handleImports(context, includeExports, importsInFile, exportsInFile) { return function(node) { - var value = getValue(node); + let value = getValue(node); if (value) { checkAndReport(context, node, value, importsInFile, "import is duplicated."); @@ -85,7 +85,7 @@ function handleImports(context, includeExports, importsInFile, exportsInFile) { */ function handleExports(context, importsInFile, exportsInFile) { return function(node) { - var value = getValue(node); + let value = getValue(node); if (value) { checkAndReport(context, node, value, exportsInFile, "export is duplicated."); @@ -116,11 +116,11 @@ module.exports = { }, create: function(context) { - var includeExports = (context.options[0] || {}).includeExports, + let includeExports = (context.options[0] || {}).includeExports, importsInFile = [], exportsInFile = []; - var handlers = { + let handlers = { ImportDeclaration: handleImports(context, includeExports, importsInFile, exportsInFile) }; diff --git a/tools/eslint/lib/rules/no-else-return.js b/tools/eslint/lib/rules/no-else-return.js index 528d4ca566d..05ead21586b 100644 --- a/tools/eslint/lib/rules/no-else-return.js +++ b/tools/eslint/lib/rules/no-else-return.js @@ -56,7 +56,7 @@ module.exports = { */ function naiveHasReturn(node) { if (node.type === "BlockStatement") { - var body = node.body, + let body = node.body, lastChildNode = body[body.length - 1]; return lastChildNode && checkForReturn(lastChildNode); @@ -128,7 +128,7 @@ module.exports = { return { IfStatement: function(node) { - var parent = context.getAncestors().pop(), + let parent = context.getAncestors().pop(), consequents, alternate; diff --git a/tools/eslint/lib/rules/no-empty-character-class.js b/tools/eslint/lib/rules/no-empty-character-class.js index 34ef78a396f..4a1ae8f92f6 100644 --- a/tools/eslint/lib/rules/no-empty-character-class.js +++ b/tools/eslint/lib/rules/no-empty-character-class.js @@ -21,7 +21,7 @@ plain-English description of the following regexp: 4. `[gimuy]*`: optional regexp flags 5. `$`: fix the match at the end of the string */ -var regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimuy]*$/; +let regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimuy]*$/; //------------------------------------------------------------------------------ // Rule Definition @@ -39,12 +39,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Literal: function(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); if (token.type === "RegularExpression" && !regex.test(token.value)) { context.report(node, "Empty class."); diff --git a/tools/eslint/lib/rules/no-empty-function.js b/tools/eslint/lib/rules/no-empty-function.js index 0102acff516..d7d8c2e886c 100644 --- a/tools/eslint/lib/rules/no-empty-function.js +++ b/tools/eslint/lib/rules/no-empty-function.js @@ -9,7 +9,7 @@ // Helpers //------------------------------------------------------------------------------ -var ALLOW_OPTIONS = Object.freeze([ +let ALLOW_OPTIONS = Object.freeze([ "functions", "arrowFunctions", "generatorFunctions", @@ -19,7 +19,7 @@ var ALLOW_OPTIONS = Object.freeze([ "setters", "constructors" ]); -var SHOW_KIND = Object.freeze({ +let SHOW_KIND = Object.freeze({ functions: "function", arrowFunctions: "arrow function", generatorFunctions: "generator function", @@ -44,8 +44,8 @@ var SHOW_KIND = Object.freeze({ * "constructors". */ function getKind(node) { - var parent = node.parent; - var kind = ""; + let parent = node.parent; + let kind = ""; if (node.type === "ArrowFunctionExpression") { return "arrowFunctions"; @@ -78,7 +78,7 @@ function getKind(node) { } // Detects prefix. - var prefix = ""; + let prefix = ""; if (node.generator) { prefix = "generator"; @@ -118,10 +118,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var allowed = options.allow || []; + let options = context.options[0] || {}; + let allowed = options.allow || []; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports a given function node if the node matches the following patterns. @@ -136,7 +136,7 @@ module.exports = { * @returns {void} */ function reportIfEmpty(node) { - var kind = getKind(node); + let kind = getKind(node); if (allowed.indexOf(kind) === -1 && node.body.type === "BlockStatement" && diff --git a/tools/eslint/lib/rules/no-empty.js b/tools/eslint/lib/rules/no-empty.js index 1302a907533..8897cce02b3 100644 --- a/tools/eslint/lib/rules/no-empty.js +++ b/tools/eslint/lib/rules/no-empty.js @@ -5,10 +5,14 @@ "use strict"; //------------------------------------------------------------------------------ -// Rule Definition +// Requirements //------------------------------------------------------------------------------ -var FUNCTION_TYPE = /^(?:ArrowFunctionExpression|Function(?:Declaration|Expression))$/; +let astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ module.exports = { meta: { @@ -32,10 +36,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, allowEmptyCatch = options.allowEmptyCatch || false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { BlockStatement: function(node) { @@ -46,7 +50,7 @@ module.exports = { } // a function is generally allowed to be empty - if (FUNCTION_TYPE.test(node.parent.type)) { + if (astUtils.isFunction(node.parent)) { return; } diff --git a/tools/eslint/lib/rules/no-eq-null.js b/tools/eslint/lib/rules/no-eq-null.js index da039bb9d7d..743f2908035 100644 --- a/tools/eslint/lib/rules/no-eq-null.js +++ b/tools/eslint/lib/rules/no-eq-null.js @@ -26,7 +26,7 @@ module.exports = { return { BinaryExpression: function(node) { - var badOperator = node.operator === "==" || node.operator === "!="; + let badOperator = node.operator === "==" || node.operator === "!="; if (node.right.type === "Literal" && node.right.raw === "null" && badOperator || node.left.type === "Literal" && node.left.raw === "null" && badOperator) { diff --git a/tools/eslint/lib/rules/no-eval.js b/tools/eslint/lib/rules/no-eval.js index 04db4b96b47..67ac1017cf4 100644 --- a/tools/eslint/lib/rules/no-eval.js +++ b/tools/eslint/lib/rules/no-eval.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var candidatesOfGlobalObject = Object.freeze([ +let candidatesOfGlobalObject = Object.freeze([ "global", "window" ]); @@ -94,12 +94,12 @@ module.exports = { }, create: function(context) { - var allowIndirect = Boolean( + let allowIndirect = Boolean( context.options[0] && context.options[0].allowIndirect ); - var sourceCode = context.getSourceCode(); - var funcInfo = null; + let sourceCode = context.getSourceCode(); + let funcInfo = null; /** * Pushs a variable scope (Program or Function) information to the stack. @@ -112,7 +112,7 @@ module.exports = { * @returns {void} */ function enterVarScope(node) { - var strict = context.getScope().isStrict; + let strict = context.getScope().isStrict; funcInfo = { upper: funcInfo, @@ -146,8 +146,8 @@ module.exports = { * @returns {void} */ function report(node) { - var locationNode = node; - var parent = node.parent; + let locationNode = node; + let parent = node.parent; if (node.type === "MemberExpression") { locationNode = node.property; @@ -170,19 +170,19 @@ module.exports = { * @returns {void} */ function reportAccessingEvalViaGlobalObject(globalScope) { - for (var i = 0; i < candidatesOfGlobalObject.length; ++i) { - var name = candidatesOfGlobalObject[i]; - var variable = astUtils.getVariableByName(globalScope, name); + for (let i = 0; i < candidatesOfGlobalObject.length; ++i) { + let name = candidatesOfGlobalObject[i]; + let variable = astUtils.getVariableByName(globalScope, name); if (!variable) { continue; } - var references = variable.references; + let references = variable.references; - for (var j = 0; j < references.length; ++j) { - var identifier = references[j].identifier; - var node = identifier.parent; + for (let j = 0; j < references.length; ++j) { + let identifier = references[j].identifier; + let node = identifier.parent; // To detect code like `window.window.eval`. while (isMember(node, name)) { @@ -204,17 +204,17 @@ module.exports = { * @returns {void} */ function reportAccessingEval(globalScope) { - var variable = astUtils.getVariableByName(globalScope, "eval"); + let variable = astUtils.getVariableByName(globalScope, "eval"); if (!variable) { return; } - var references = variable.references; + let references = variable.references; - for (var i = 0; i < references.length; ++i) { - var reference = references[i]; - var id = reference.identifier; + for (let i = 0; i < references.length; ++i) { + let reference = references[i]; + let id = reference.identifier; if (id.name === "eval" && !astUtils.isCallee(id)) { @@ -229,7 +229,7 @@ module.exports = { // Checks only direct calls to eval. It's simple! return { "CallExpression:exit": function(node) { - var callee = node.callee; + let callee = node.callee; if (isIdentifier(callee, "eval")) { report(callee); @@ -240,7 +240,7 @@ module.exports = { return { "CallExpression:exit": function(node) { - var callee = node.callee; + let callee = node.callee; if (isIdentifier(callee, "eval")) { report(callee); @@ -248,7 +248,7 @@ module.exports = { }, Program: function(node) { - var scope = context.getScope(), + let scope = context.getScope(), features = context.parserOptions.ecmaFeatures || {}, strict = scope.isStrict || @@ -265,7 +265,7 @@ module.exports = { }, "Program:exit": function() { - var globalScope = context.getScope(); + let globalScope = context.getScope(); exitVarScope(); reportAccessingEval(globalScope); diff --git a/tools/eslint/lib/rules/no-ex-assign.js b/tools/eslint/lib/rules/no-ex-assign.js index bf3afc6cd3f..42aea52723c 100644 --- a/tools/eslint/lib/rules/no-ex-assign.js +++ b/tools/eslint/lib/rules/no-ex-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-extend-native.js b/tools/eslint/lib/rules/no-extend-native.js index 69d4931ab6e..c58e5c35540 100644 --- a/tools/eslint/lib/rules/no-extend-native.js +++ b/tools/eslint/lib/rules/no-extend-native.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var globals = require("globals"); +let globals = require("globals"); //------------------------------------------------------------------------------ // Rule Definition @@ -42,9 +42,9 @@ module.exports = { create: function(context) { - var config = context.options[0] || {}; - var exceptions = config.exceptions || []; - var modifiedBuiltins = Object.keys(globals.builtin).filter(function(builtin) { + let config = context.options[0] || {}; + let exceptions = config.exceptions || []; + let modifiedBuiltins = Object.keys(globals.builtin).filter(function(builtin) { return builtin[0].toUpperCase() === builtin[0]; }); @@ -58,7 +58,7 @@ module.exports = { // handle the Array.prototype.extra style case AssignmentExpression: function(node) { - var lhs = node.left, + let lhs = node.left, affectsProto; if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") { @@ -83,7 +83,7 @@ module.exports = { // handle the Object.definePropert[y|ies](Array.prototype) case CallExpression: function(node) { - var callee = node.callee, + let callee = node.callee, subject, object; diff --git a/tools/eslint/lib/rules/no-extra-bind.js b/tools/eslint/lib/rules/no-extra-bind.js index f75e2fcc257..bdafaf040f1 100644 --- a/tools/eslint/lib/rules/no-extra-bind.js +++ b/tools/eslint/lib/rules/no-extra-bind.js @@ -20,7 +20,7 @@ module.exports = { }, create: function(context) { - var scopeInfo = null; + let scopeInfo = null; /** * Reports a given function node. @@ -73,8 +73,8 @@ module.exports = { * @returns {boolean} `true` if the node is the callee of `.bind()` method. */ function isCalleeOfBindMethod(node) { - var parent = node.parent; - var grandparent = parent.parent; + let parent = node.parent; + let grandparent = parent.parent; return ( grandparent && diff --git a/tools/eslint/lib/rules/no-extra-boolean-cast.js b/tools/eslint/lib/rules/no-extra-boolean-cast.js index f14da0821db..890f7cb6051 100644 --- a/tools/eslint/lib/rules/no-extra-boolean-cast.js +++ b/tools/eslint/lib/rules/no-extra-boolean-cast.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { // Node types which have a test which will coerce values to booleans. - var BOOLEAN_NODE_TYPES = [ + let BOOLEAN_NODE_TYPES = [ "IfStatement", "DoWhileStatement", "WhileStatement", @@ -36,7 +36,7 @@ module.exports = { * * @param {Object} node The node * @param {Object} parent Its parent - * @returns {Boolean} If it is in a boolean context + * @returns {boolean} If it is in a boolean context */ function isInBooleanContext(node, parent) { return ( @@ -52,7 +52,7 @@ module.exports = { return { UnaryExpression: function(node) { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), parent = ancestors.pop(), grandparent = ancestors.pop(); @@ -74,7 +74,7 @@ module.exports = { } }, CallExpression: function(node) { - var parent = node.parent; + let parent = node.parent; if (node.callee.type !== "Identifier" || node.callee.name !== "Boolean") { return; diff --git a/tools/eslint/lib/rules/no-extra-label.js b/tools/eslint/lib/rules/no-extra-label.js index f1a48e3688e..5b72209bf2d 100644 --- a/tools/eslint/lib/rules/no-extra-label.js +++ b/tools/eslint/lib/rules/no-extra-label.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var scopeInfo = null; + let scopeInfo = null; /** * Creates a new scope with a breakable statement. @@ -98,9 +98,9 @@ module.exports = { return; } - var labelNode = node.label; - var label = labelNode.name; - var info = scopeInfo; + let labelNode = node.label; + let label = labelNode.name; + let info = scopeInfo; while (info) { if (info.breakable || info.label === label) { diff --git a/tools/eslint/lib/rules/no-extra-parens.js b/tools/eslint/lib/rules/no-extra-parens.js index c33a64920ff..86ef6ddc0f8 100644 --- a/tools/eslint/lib/rules/no-extra-parens.js +++ b/tools/eslint/lib/rules/no-extra-parens.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils.js"); +let astUtils = require("../ast-utils.js"); module.exports = { meta: { @@ -54,14 +54,14 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode); - var precedence = astUtils.getPrecedence; - var ALL_NODES = context.options[0] !== "functions"; - var EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false; - var NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false; - var EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false; + let isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode); + let precedence = astUtils.getPrecedence; + let ALL_NODES = context.options[0] !== "functions"; + let EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false; + let NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false; + let EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false; /** * Determines if this rule should be enforced for a node given the current configuration. @@ -80,7 +80,7 @@ module.exports = { * @private */ function isParenthesisedTwice(node) { - var previousToken = sourceCode.getTokenBefore(node, 1), + let previousToken = sourceCode.getTokenBefore(node, 1), nextToken = sourceCode.getTokenAfter(node, 1); return isParenthesised(node) && previousToken && nextToken && @@ -199,7 +199,7 @@ module.exports = { * @returns {boolean} `true` if the node is located at the head of ExpressionStatement. */ function isHeadOfExpressionStatement(node) { - var parent = node.parent; + let parent = node.parent; while (parent) { switch (parent.type) { @@ -263,7 +263,7 @@ module.exports = { * @private */ function report(node) { - var previousToken = sourceCode.getTokenBefore(node); + let previousToken = sourceCode.getTokenBefore(node); context.report(node, previousToken.loc.start, "Gratuitous parentheses around expression."); } @@ -317,7 +317,7 @@ module.exports = { */ function dryBinaryLogical(node) { if (!NESTED_BINARY) { - var prec = precedence(node); + let prec = precedence(node); if (hasExcessParens(node.left) && precedence(node.left) >= prec) { report(node.left); @@ -394,7 +394,7 @@ module.exports = { }, ExpressionStatement: function(node) { - var firstToken, secondToken, firstTokens; + let firstToken, secondToken, firstTokens; if (hasExcessParens(node.expression)) { firstTokens = sourceCode.getFirstTokens(node.expression, 2); @@ -484,7 +484,7 @@ module.exports = { ObjectExpression: function(node) { [].forEach.call(node.properties, function(e) { - var v = e.value; + let v = e.value; if (v && hasExcessParens(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) { report(v); @@ -493,7 +493,7 @@ module.exports = { }, ReturnStatement: function(node) { - var returnToken = sourceCode.getFirstToken(node); + let returnToken = sourceCode.getFirstToken(node); if (isReturnAssignException(node)) { return; @@ -529,7 +529,7 @@ module.exports = { }, ThrowStatement: function(node) { - var throwToken = sourceCode.getFirstToken(node); + let throwToken = sourceCode.getFirstToken(node); if (hasExcessParensNoLineTerminator(throwToken, node.argument)) { report(node.argument); @@ -562,7 +562,7 @@ module.exports = { }, YieldExpression: function(node) { - var yieldToken; + let yieldToken; if (node.argument) { yieldToken = sourceCode.getFirstToken(node); diff --git a/tools/eslint/lib/rules/no-extra-semi.js b/tools/eslint/lib/rules/no-extra-semi.js index 679a16641b7..37f2253c26a 100644 --- a/tools/eslint/lib/rules/no-extra-semi.js +++ b/tools/eslint/lib/rules/no-extra-semi.js @@ -22,7 +22,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Reports an unnecessary semicolon error. @@ -47,7 +47,7 @@ module.exports = { * @returns {void} */ function checkForPartOfClassBody(firstToken) { - for (var token = firstToken; + for (let token = firstToken; token.type === "Punctuator" && token.value !== "}"; token = sourceCode.getTokenAfter(token) ) { @@ -65,7 +65,7 @@ module.exports = { * @returns {void} */ EmptyStatement: function(node) { - var parent = node.parent, + let parent = node.parent, allowedParentTypes = [ "ForStatement", "ForInStatement", diff --git a/tools/eslint/lib/rules/no-fallthrough.js b/tools/eslint/lib/rules/no-fallthrough.js index 2edb4972baf..24f3642fa16 100644 --- a/tools/eslint/lib/rules/no-fallthrough.js +++ b/tools/eslint/lib/rules/no-fallthrough.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/i; +let DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/i; /** * Checks whether or not a given node has a fallthrough comment. @@ -24,8 +24,8 @@ var DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/i; * @returns {boolean} `true` if the node has a valid fallthrough comment. */ function hasFallthroughComment(node, context, fallthroughCommentPattern) { - var sourceCode = context.getSourceCode(); - var comment = lodash.last(sourceCode.getComments(node).leading); + let sourceCode = context.getSourceCode(); + let comment = lodash.last(sourceCode.getComments(node).leading); return Boolean(comment && fallthroughCommentPattern.test(comment.value)); } @@ -75,16 +75,16 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var currentCodePath = null; - var sourceCode = context.getSourceCode(); + let options = context.options[0] || {}; + let currentCodePath = null; + let sourceCode = context.getSourceCode(); /* * We need to use leading comments of the next SwitchCase node because * trailing comments is wrong if semicolons are omitted. */ - var fallthroughCase = null; - var fallthroughCommentPattern = null; + let fallthroughCase = null; + let fallthroughCommentPattern = null; if (options.commentPattern) { fallthroughCommentPattern = new RegExp(options.commentPattern); @@ -117,7 +117,7 @@ module.exports = { }, "SwitchCase:exit": function(node) { - var nextToken = sourceCode.getTokenAfter(node); + let nextToken = sourceCode.getTokenAfter(node); /* * `reachable` meant fall through because statements preceded by diff --git a/tools/eslint/lib/rules/no-func-assign.js b/tools/eslint/lib/rules/no-func-assign.js index ac3afe55c05..2266a044fc3 100644 --- a/tools/eslint/lib/rules/no-func-assign.js +++ b/tools/eslint/lib/rules/no-func-assign.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition diff --git a/tools/eslint/lib/rules/no-implicit-coercion.js b/tools/eslint/lib/rules/no-implicit-coercion.js index 113c205855e..ee11bd00876 100644 --- a/tools/eslint/lib/rules/no-implicit-coercion.js +++ b/tools/eslint/lib/rules/no-implicit-coercion.js @@ -9,13 +9,13 @@ // Helpers //------------------------------------------------------------------------------ -var INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/; -var ALLOWABLE_OPERATORS = ["~", "!!", "+", "*"]; +let INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/; +let ALLOWABLE_OPERATORS = ["~", "!!", "+", "*"]; /** * Parses and normalizes an option object. - * @param {object} options - An option object to parse. - * @returns {object} The parsed and normalized option object. + * @param {Object} options - An option object to parse. + * @returns {Object} The parsed and normalized option object. */ function parseOptions(options) { options = options || {}; @@ -91,7 +91,7 @@ function isNumeric(node) { * @returns {ASTNode|null} The first non-numeric item in the BinaryExpression tree or null */ function getNonNumericOperand(node) { - var left = node.left, + let left = node.left, right = node.right; if (right.type !== "BinaryExpression" && !isNumeric(right)) { @@ -176,10 +176,10 @@ module.exports = { }, create: function(context) { - var options = parseOptions(context.options[0]), + let options = parseOptions(context.options[0]), operatorAllowed = false; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { UnaryExpression: function(node) { @@ -220,7 +220,7 @@ module.exports = { // 1 * foo operatorAllowed = options.allow.indexOf("*") >= 0; - var nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && getNonNumericOperand(node); + let nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && getNonNumericOperand(node); if (nonNumericOperand) { context.report( diff --git a/tools/eslint/lib/rules/no-implicit-globals.js b/tools/eslint/lib/rules/no-implicit-globals.js index c2768ea1a09..9f8180394f1 100644 --- a/tools/eslint/lib/rules/no-implicit-globals.js +++ b/tools/eslint/lib/rules/no-implicit-globals.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { return { Program: function() { - var scope = context.getScope(); + let scope = context.getScope(); scope.variables.forEach(function(variable) { if (variable.writeable) { @@ -38,7 +38,7 @@ module.exports = { }); scope.implicit.variables.forEach(function(variable) { - var scopeVariable = scope.set.get(variable.name); + let scopeVariable = scope.set.get(variable.name); if (scopeVariable && scopeVariable.writeable) { return; diff --git a/tools/eslint/lib/rules/no-implied-eval.js b/tools/eslint/lib/rules/no-implied-eval.js index 7c1ed2fb6eb..ec660fa08f3 100644 --- a/tools/eslint/lib/rules/no-implied-eval.js +++ b/tools/eslint/lib/rules/no-implied-eval.js @@ -21,13 +21,13 @@ module.exports = { }, create: function(context) { - var CALLEE_RE = /set(?:Timeout|Interval)|execScript/; + let CALLEE_RE = /set(?:Timeout|Interval)|execScript/; /* * Figures out if we should inspect a given binary expression. Is a stack * of stacks, where the first element in each substack is a CallExpression. */ - var impliedEvalAncestorsStack = []; + let impliedEvalAncestorsStack = []; //-------------------------------------------------------------------------- // Helpers @@ -50,7 +50,7 @@ module.exports = { * @private */ function isImpliedEvalMemberExpression(node) { - var object = node.object, + let object = node.object, property = node.property, hasImpliedEvalName = CALLEE_RE.test(property.name) || CALLEE_RE.test(property.value); @@ -67,7 +67,7 @@ module.exports = { * @private */ function isImpliedEvalCallExpression(node) { - var isMemberExpression = (node.callee.type === "MemberExpression"), + let isMemberExpression = (node.callee.type === "MemberExpression"), isIdentifier = (node.callee.type === "Identifier"), isImpliedEvalCallee = (isIdentifier && CALLEE_RE.test(node.callee.name)) || @@ -103,7 +103,7 @@ module.exports = { if (hasImpliedEvalParent(node)) { // remove the entire substack, to avoid duplicate reports - var substack = impliedEvalAncestorsStack.pop(); + let substack = impliedEvalAncestorsStack.pop(); context.report(substack[0], "Implied eval. Consider passing a function instead of a string."); } diff --git a/tools/eslint/lib/rules/no-inline-comments.js b/tools/eslint/lib/rules/no-inline-comments.js index e313eac06f0..87039d46971 100644 --- a/tools/eslint/lib/rules/no-inline-comments.js +++ b/tools/eslint/lib/rules/no-inline-comments.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -22,7 +22,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Will check that comments are not on lines starting with or ending with code @@ -33,16 +33,16 @@ module.exports = { function testCodeAroundComment(node) { // Get the whole line and cut it off at the start of the comment - var startLine = String(sourceCode.lines[node.loc.start.line - 1]); - var endLine = String(sourceCode.lines[node.loc.end.line - 1]); + let startLine = String(sourceCode.lines[node.loc.start.line - 1]); + let endLine = String(sourceCode.lines[node.loc.end.line - 1]); - var preamble = startLine.slice(0, node.loc.start.column).trim(); + let preamble = startLine.slice(0, node.loc.start.column).trim(); // Also check after the comment - var postamble = endLine.slice(node.loc.end.column).trim(); + let postamble = endLine.slice(node.loc.end.column).trim(); // Check that this comment isn't an ESLint directive - var isDirective = astUtils.isDirectiveComment(node); + let isDirective = astUtils.isDirectiveComment(node); // Should be empty if there was only whitespace around the comment if (!isDirective && (preamble || postamble)) { diff --git a/tools/eslint/lib/rules/no-inner-declarations.js b/tools/eslint/lib/rules/no-inner-declarations.js index 3471ce8cc73..3e21385a59b 100644 --- a/tools/eslint/lib/rules/no-inner-declarations.js +++ b/tools/eslint/lib/rules/no-inner-declarations.js @@ -31,7 +31,7 @@ module.exports = { * @returns {Object} Ancestor's type and distance from node. */ function nearestBody() { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), ancestor = ancestors.pop(), generation = 1; @@ -58,7 +58,7 @@ module.exports = { * @returns {void} */ function check(node) { - var body = nearestBody(node), + let body = nearestBody(node), valid = ((body.type === "Program" && body.distance === 1) || body.distance === 2); diff --git a/tools/eslint/lib/rules/no-invalid-regexp.js b/tools/eslint/lib/rules/no-invalid-regexp.js index 6f8b8673786..eb693c55c6c 100644 --- a/tools/eslint/lib/rules/no-invalid-regexp.js +++ b/tools/eslint/lib/rules/no-invalid-regexp.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var espree = require("espree"); +let espree = require("espree"); //------------------------------------------------------------------------------ // Rule Definition @@ -38,7 +38,7 @@ module.exports = { create: function(context) { - var options = context.options[0], + let options = context.options[0], allowedFlags = ""; if (options && options.allowConstructorFlags) { @@ -63,7 +63,7 @@ module.exports = { */ function check(node) { if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0])) { - var flags = isString(node.arguments[1]) ? node.arguments[1].value : ""; + let flags = isString(node.arguments[1]) ? node.arguments[1].value : ""; if (allowedFlags) { flags = flags.replace(new RegExp("[" + allowedFlags + "]", "gi"), ""); @@ -72,7 +72,7 @@ module.exports = { try { void new RegExp(node.arguments[0].value); } catch (e) { - context.report(node, e.message); + context.report(node, e.message + "."); } if (flags) { @@ -80,7 +80,7 @@ module.exports = { try { espree.parse("/./" + flags, context.parserOptions); } catch (ex) { - context.report(node, "Invalid flags supplied to RegExp constructor '" + flags + "'"); + context.report(node, "Invalid flags supplied to RegExp constructor '" + flags + "'."); } } diff --git a/tools/eslint/lib/rules/no-invalid-this.js b/tools/eslint/lib/rules/no-invalid-this.js index 198bfd706ad..e41c4746991 100644 --- a/tools/eslint/lib/rules/no-invalid-this.js +++ b/tools/eslint/lib/rules/no-invalid-this.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -27,7 +27,7 @@ module.exports = { }, create: function(context) { - var stack = [], + let stack = [], sourceCode = context.getSourceCode(); /** @@ -40,7 +40,7 @@ module.exports = { * an object which has a flag that whether or not `this` keyword is valid. */ stack.getCurrent = function() { - var current = this[this.length - 1]; + let current = this[this.length - 1]; if (!current.init) { current.init = true; @@ -86,7 +86,7 @@ module.exports = { * Modules is always strict mode. */ Program: function(node) { - var scope = context.getScope(), + let scope = context.getScope(), features = context.parserOptions.ecmaFeatures || {}; stack.push({ @@ -111,7 +111,7 @@ module.exports = { // Reports if `this` of the current context is invalid. ThisExpression: function(node) { - var current = stack.getCurrent(); + let current = stack.getCurrent(); if (current && !current.valid) { context.report(node, "Unexpected 'this'."); diff --git a/tools/eslint/lib/rules/no-irregular-whitespace.js b/tools/eslint/lib/rules/no-irregular-whitespace.js index 032dd96c113..0049de3dde9 100644 --- a/tools/eslint/lib/rules/no-irregular-whitespace.js +++ b/tools/eslint/lib/rules/no-irregular-whitespace.js @@ -10,10 +10,10 @@ // Constants //------------------------------------------------------------------------------ -var ALL_IRREGULARS = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]/; -var IRREGULAR_WHITESPACE = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg; -var IRREGULAR_LINE_TERMINATORS = /[\u2028\u2029]/mg; -var LINE_BREAK = /\r\n|\r|\n|\u2028|\u2029/g; +let ALL_IRREGULARS = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]/; +let IRREGULAR_WHITESPACE = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg; +let IRREGULAR_LINE_TERMINATORS = /[\u2028\u2029]/mg; +let LINE_BREAK = /\r\n|\r|\n|\u2028|\u2029/g; //------------------------------------------------------------------------------ // Rule Definition @@ -52,19 +52,19 @@ module.exports = { create: function(context) { // Module store of errors that we have found - var errors = []; + let errors = []; // Comment nodes. We accumulate these as we go, so we can be sure to trigger them after the whole `Program` entity is parsed, even for top-of-file comments. - var commentNodes = []; + let commentNodes = []; // Lookup the `skipComments` option, which defaults to `false`. - var options = context.options[0] || {}; - var skipComments = !!options.skipComments; - var skipStrings = options.skipStrings !== false; - var skipRegExps = !!options.skipRegExps; - var skipTemplates = !!options.skipTemplates; + let options = context.options[0] || {}; + let skipComments = !!options.skipComments; + let skipStrings = options.skipStrings !== false; + let skipRegExps = !!options.skipRegExps; + let skipTemplates = !!options.skipTemplates; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Removes errors that occur inside a string node @@ -73,11 +73,11 @@ module.exports = { * @private */ function removeWhitespaceError(node) { - var locStart = node.loc.start; - var locEnd = node.loc.end; + let locStart = node.loc.start; + let locEnd = node.loc.end; errors = errors.filter(function(error) { - var errorLoc = error[1]; + let errorLoc = error[1]; if (errorLoc.line >= locStart.line && errorLoc.line <= locEnd.line) { if (errorLoc.column >= locStart.column && (errorLoc.column <= locEnd.column || errorLoc.line < locEnd.line)) { @@ -95,8 +95,8 @@ module.exports = { * @private */ function removeInvalidNodeErrorsInIdentifierOrLiteral(node) { - var shouldCheckStrings = skipStrings && (typeof node.value === "string"); - var shouldCheckRegExps = skipRegExps && (node.value instanceof RegExp); + let shouldCheckStrings = skipStrings && (typeof node.value === "string"); + let shouldCheckRegExps = skipRegExps && (node.value instanceof RegExp); if (shouldCheckStrings || shouldCheckRegExps) { @@ -140,10 +140,10 @@ module.exports = { * @private */ function checkForIrregularWhitespace(node) { - var sourceLines = sourceCode.lines; + let sourceLines = sourceCode.lines; sourceLines.forEach(function(sourceLine, lineIndex) { - var lineNumber = lineIndex + 1, + let lineNumber = lineIndex + 1, location, match; @@ -153,7 +153,7 @@ module.exports = { column: match.index }; - errors.push([node, location, "Irregular whitespace not allowed"]); + errors.push([node, location, "Irregular whitespace not allowed."]); } }); } @@ -165,7 +165,7 @@ module.exports = { * @private */ function checkForIrregularLineTerminators(node) { - var source = sourceCode.getText(), + let source = sourceCode.getText(), sourceLines = sourceCode.lines, linebreaks = source.match(LINE_BREAK), lastLineIndex = -1, @@ -181,7 +181,7 @@ module.exports = { column: sourceLines[lineIndex].length }; - errors.push([node, location, "Irregular whitespace not allowed"]); + errors.push([node, location, "Irregular whitespace not allowed."]); lastLineIndex = lineIndex; } } @@ -203,7 +203,7 @@ module.exports = { */ function noop() {} - var nodes = {}; + let nodes = {}; if (ALL_IRREGULARS.test(sourceCode.getText())) { nodes.Program = function(node) { diff --git a/tools/eslint/lib/rules/no-label-var.js b/tools/eslint/lib/rules/no-label-var.js index 7c6d56f3552..a203324f147 100644 --- a/tools/eslint/lib/rules/no-label-var.js +++ b/tools/eslint/lib/rules/no-label-var.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -34,7 +34,7 @@ module.exports = { /** * Check if the identifier is present inside current scope - * @param {object} scope current scope + * @param {Object} scope current scope * @param {string} name To evaluate * @returns {boolean} True if its present * @private @@ -52,7 +52,7 @@ module.exports = { LabeledStatement: function(node) { // Fetch the innermost scope. - var scope = context.getScope(); + let scope = context.getScope(); // Recursively find the identifier walking up the scope, starting // with the innermost scope. diff --git a/tools/eslint/lib/rules/no-labels.js b/tools/eslint/lib/rules/no-labels.js index da0cd8e7426..adc5bc0f81b 100644 --- a/tools/eslint/lib/rules/no-labels.js +++ b/tools/eslint/lib/rules/no-labels.js @@ -5,10 +5,10 @@ "use strict"; //------------------------------------------------------------------------------ -// Constants +// Requirements //------------------------------------------------------------------------------ -var LOOP_TYPES = /^(?:While|DoWhile|For|ForIn|ForOf)Statement$/; +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -39,10 +39,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0]; - var allowLoop = Boolean(options && options.allowLoop); - var allowSwitch = Boolean(options && options.allowSwitch); - var scopeInfo = null; + let options = context.options[0]; + let allowLoop = Boolean(options && options.allowLoop); + let allowSwitch = Boolean(options && options.allowSwitch); + let scopeInfo = null; /** * Gets the kind of a given node. @@ -51,12 +51,10 @@ module.exports = { * @returns {string} The kind of the node. */ function getBodyKind(node) { - var type = node.type; - - if (LOOP_TYPES.test(type)) { + if (astUtils.isLoop(node)) { return "loop"; } - if (type === "SwitchStatement") { + if (node.type === "SwitchStatement") { return "switch"; } return "other"; @@ -83,7 +81,7 @@ module.exports = { * @returns {boolean} `true` if the name is a label of a loop. */ function getKind(label) { - var info = scopeInfo; + let info = scopeInfo; while (info) { if (info.label === label) { diff --git a/tools/eslint/lib/rules/no-lone-blocks.js b/tools/eslint/lib/rules/no-lone-blocks.js index 113cd89b937..e93f1d0809b 100644 --- a/tools/eslint/lib/rules/no-lone-blocks.js +++ b/tools/eslint/lib/rules/no-lone-blocks.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { // A stack of lone blocks to be checked for block-level bindings - var loneBlocks = [], + let loneBlocks = [], ruleDef; /** @@ -32,7 +32,7 @@ module.exports = { * @returns {void} */ function report(node) { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); context.report(node, parent.type === "Program" ? "Block is redundant." : @@ -45,7 +45,7 @@ module.exports = { * @returns {boolean} True if the current node is a lone block. */ function isLoneBlock() { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); return parent.type === "BlockStatement" || parent.type === "Program"; } @@ -60,7 +60,7 @@ module.exports = { return; } - var block = context.getAncestors().pop(); + let block = context.getAncestors().pop(); if (loneBlocks[loneBlocks.length - 1] === block) { loneBlocks.pop(); diff --git a/tools/eslint/lib/rules/no-lonely-if.js b/tools/eslint/lib/rules/no-lonely-if.js index 1efd1acc018..4c99bca8389 100644 --- a/tools/eslint/lib/rules/no-lonely-if.js +++ b/tools/eslint/lib/rules/no-lonely-if.js @@ -23,7 +23,7 @@ module.exports = { return { IfStatement: function(node) { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), parent = ancestors.pop(), grandparent = ancestors.pop(); diff --git a/tools/eslint/lib/rules/no-loop-func.js b/tools/eslint/lib/rules/no-loop-func.js index 247dc52cd47..e9409338961 100644 --- a/tools/eslint/lib/rules/no-loop-func.js +++ b/tools/eslint/lib/rules/no-loop-func.js @@ -20,7 +20,7 @@ * `null`. */ function getContainingLoopNode(node) { - var parent = node.parent; + let parent = node.parent; while (parent) { switch (parent.type) { @@ -73,8 +73,8 @@ function getContainingLoopNode(node) { * @returns {ASTNode} The most outer loop node. */ function getTopLoopNode(node, excludedNode) { - var retv = node; - var border = excludedNode ? excludedNode.range[1] : 0; + let retv = node; + let border = excludedNode ? excludedNode.range[1] : 0; while (node && node.range[0] >= border) { retv = node; @@ -94,10 +94,10 @@ function getTopLoopNode(node, excludedNode) { * @returns {boolean} `true` if the reference is safe or not. */ function isSafe(funcNode, loopNode, reference) { - var variable = reference.resolved; - var definition = variable && variable.defs[0]; - var declaration = definition && definition.parent; - var kind = (declaration && declaration.type === "VariableDeclaration") + let variable = reference.resolved; + let definition = variable && variable.defs[0]; + let declaration = definition && definition.parent; + let kind = (declaration && declaration.type === "VariableDeclaration") ? declaration.kind : ""; @@ -117,7 +117,7 @@ function isSafe(funcNode, loopNode, reference) { // WriteReferences which exist after this border are unsafe because those // can modify the variable. - var border = getTopLoopNode( + let border = getTopLoopNode( loopNode, (kind === "let") ? declaration : null ).range[0]; @@ -135,7 +135,7 @@ function isSafe(funcNode, loopNode, reference) { * @returns {boolean} `true` if the reference is safe. */ function isSafeReference(upperRef) { - var id = upperRef.identifier; + let id = upperRef.identifier; return ( !upperRef.isWrite() || @@ -174,18 +174,18 @@ module.exports = { * @returns {boolean} Whether or not the node is within a loop. */ function checkForLoops(node) { - var loopNode = getContainingLoopNode(node); + let loopNode = getContainingLoopNode(node); if (!loopNode) { return; } - var references = context.getScope().through; + let references = context.getScope().through; if (references.length > 0 && !references.every(isSafe.bind(null, node, loopNode)) ) { - context.report(node, "Don't make functions within a loop"); + context.report(node, "Don't make functions within a loop."); } } diff --git a/tools/eslint/lib/rules/no-magic-numbers.js b/tools/eslint/lib/rules/no-magic-numbers.js index 2e7434c1a58..76d71c1e6ce 100644 --- a/tools/eslint/lib/rules/no-magic-numbers.js +++ b/tools/eslint/lib/rules/no-magic-numbers.js @@ -42,7 +42,7 @@ module.exports = { }, create: function(context) { - var config = context.options[0] || {}, + let config = context.options[0] || {}, detectObjects = !!config.detectObjects, enforceConst = !!config.enforceConst, ignore = config.ignore || [], @@ -100,7 +100,7 @@ module.exports = { return { Literal: function(node) { - var parent = node.parent, + let parent = node.parent, value = node.value, raw = node.raw, okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"]; @@ -128,14 +128,14 @@ module.exports = { if (enforceConst && parent.parent.kind !== "const") { context.report({ node: node, - message: "Number constants declarations must use 'const'" + message: "Number constants declarations must use 'const'." }); } } else if (okTypes.indexOf(parent.type) === -1 || (parent.type === "AssignmentExpression" && parent.operator !== "=")) { context.report({ node: node, - message: "No magic number: " + raw + message: "No magic number: " + raw + "." }); } } diff --git a/tools/eslint/lib/rules/no-mixed-operators.js b/tools/eslint/lib/rules/no-mixed-operators.js index 9a8b1c39251..f6e686521df 100644 --- a/tools/eslint/lib/rules/no-mixed-operators.js +++ b/tools/eslint/lib/rules/no-mixed-operators.js @@ -9,43 +9,43 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils.js"); +let astUtils = require("../ast-utils.js"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var ARITHMETIC_OPERATORS = ["+", "-", "*", "/", "%", "**"]; -var BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"]; -var COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="]; -var LOGICAL_OPERATORS = ["&&", "||"]; -var RELATIONAL_OPERATORS = ["in", "instanceof"]; -var ALL_OPERATORS = [].concat( +let ARITHMETIC_OPERATORS = ["+", "-", "*", "/", "%", "**"]; +let BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"]; +let COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="]; +let LOGICAL_OPERATORS = ["&&", "||"]; +let RELATIONAL_OPERATORS = ["in", "instanceof"]; +let ALL_OPERATORS = [].concat( ARITHMETIC_OPERATORS, BITWISE_OPERATORS, COMPARISON_OPERATORS, LOGICAL_OPERATORS, RELATIONAL_OPERATORS ); -var DEFAULT_GROUPS = [ +let DEFAULT_GROUPS = [ ARITHMETIC_OPERATORS, BITWISE_OPERATORS, COMPARISON_OPERATORS, LOGICAL_OPERATORS, RELATIONAL_OPERATORS ]; -var TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/; +let TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/; /** * Normalizes options. * - * @param {object|undefined} options - A options object to normalize. - * @returns {object} Normalized option object. + * @param {Object|undefined} options - A options object to normalize. + * @returns {Object} Normalized option object. */ function normalizeOptions(options) { - var hasGroups = (options && options.groups && options.groups.length > 0); - var groups = hasGroups ? options.groups : DEFAULT_GROUPS; - var allowSamePrecedence = (options && options.allowSamePrecedence) !== false; + let hasGroups = (options && options.groups && options.groups.length > 0); + let groups = hasGroups ? options.groups : DEFAULT_GROUPS; + let allowSamePrecedence = (options && options.allowSamePrecedence) !== false; return { groups: groups, @@ -102,8 +102,8 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var options = normalizeOptions(context.options[0]); + let sourceCode = context.getSourceCode(); + let options = normalizeOptions(context.options[0]); /** * Checks whether a given node should be ignored by options or not. @@ -114,8 +114,8 @@ module.exports = { * @returns {boolean} `true` if the node should be ignored. */ function shouldIgnore(node) { - var a = node; - var b = node.parent; + let a = node; + let b = node.parent; return ( !includesBothInAGroup(options.groups, a.operator, b.operator) || @@ -150,7 +150,7 @@ module.exports = { * @returns {Token} The operator token of the node. */ function getOperatorToken(node) { - var token = sourceCode.getTokenAfter(node.left); + let token = sourceCode.getTokenAfter(node.left); while (token.value === ")") { token = sourceCode.getTokenAfter(token); @@ -169,10 +169,10 @@ module.exports = { * @returns {void} */ function reportBothOperators(node) { - var parent = node.parent; - var left = (parent.left === node) ? node : parent; - var right = (parent.left !== node) ? node : parent; - var message = + let parent = node.parent; + let left = (parent.left === node) ? node : parent; + let right = (parent.left !== node) ? node : parent; + let message = "Unexpected mix of '" + left.operator + "' and '" + right.operator + "'."; diff --git a/tools/eslint/lib/rules/no-mixed-requires.js b/tools/eslint/lib/rules/no-mixed-requires.js index b6d365a9dbb..68ce51f56fc 100644 --- a/tools/eslint/lib/rules/no-mixed-requires.js +++ b/tools/eslint/lib/rules/no-mixed-requires.js @@ -42,7 +42,7 @@ module.exports = { create: function(context) { - var grouping = false, + let grouping = false, allowCall = false, options = context.options[0]; @@ -74,13 +74,13 @@ module.exports = { ]; } - var BUILTIN_MODULES = getBuiltinModules(); + let BUILTIN_MODULES = getBuiltinModules(); - var DECL_REQUIRE = "require", + let DECL_REQUIRE = "require", DECL_UNINITIALIZED = "uninitialized", DECL_OTHER = "other"; - var REQ_CORE = "core", + let REQ_CORE = "core", REQ_FILE = "file", REQ_MODULE = "module", REQ_COMPUTED = "computed"; @@ -137,7 +137,7 @@ module.exports = { return REQ_COMPUTED; } - var arg = initExpression.arguments[0]; + let arg = initExpression.arguments[0]; if (arg.type !== "Literal" || typeof arg.value !== "string") { @@ -167,10 +167,10 @@ module.exports = { * @returns {boolean} True if the declarations are mixed, false if not. */ function isMixed(declarations) { - var contains = {}; + let contains = {}; declarations.forEach(function(declaration) { - var type = getDeclarationType(declaration.init); + let type = getDeclarationType(declaration.init); contains[type] = true; }); @@ -188,7 +188,7 @@ module.exports = { * @returns {boolean} True if the declarations are grouped, false if not. */ function isGrouped(declarations) { - var found = {}; + let found = {}; declarations.forEach(function(declaration) { if (getDeclarationType(declaration.init) === DECL_REQUIRE) { diff --git a/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js b/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js index 74553f65115..19734b1b5d5 100644 --- a/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js +++ b/tools/eslint/lib/rules/no-mixed-spaces-and-tabs.js @@ -24,9 +24,9 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var smartTabs, + let smartTabs, ignoredLocs = []; switch (context.options[0]) { @@ -85,7 +85,7 @@ module.exports = { * or the reverse before non-tab/-space * characters begin. */ - var regex = /^(?=[\t ]*(\t | \t))/, + let regex = /^(?=[\t ]*(\t | \t))/, match, lines = sourceCode.lines, comments = sourceCode.getAllComments(); @@ -119,10 +119,10 @@ module.exports = { match = regex.exec(line); if (match) { - var lineNumber = i + 1, + let lineNumber = i + 1, column = match.index + 1; - for (var j = 0; j < ignoredLocs.length; j++) { + for (let j = 0; j < ignoredLocs.length; j++) { if (beforeLoc(ignoredLocs[j], lineNumber, column)) { continue; } diff --git a/tools/eslint/lib/rules/no-multi-spaces.js b/tools/eslint/lib/rules/no-multi-spaces.js index 2fd89ef4dc0..78d600c8848 100644 --- a/tools/eslint/lib/rules/no-multi-spaces.js +++ b/tools/eslint/lib/rules/no-multi-spaces.js @@ -41,7 +41,7 @@ module.exports = { create: function(context) { // the index of the last comment that was checked - var exceptions = { Property: true }, + let exceptions = { Property: true }, hasExceptions = true, options = context.options[0], lastCommentIndex = 0; @@ -69,7 +69,7 @@ module.exports = { */ function isIndexInComment(index, comments) { - var comment; + let comment; while (lastCommentIndex < comments.length) { @@ -95,7 +95,7 @@ module.exports = { return { Program: function() { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), source = sourceCode.getText(), allComments = sourceCode.getAllComments(), pattern = /[^\n\r\u2028\u2029\t ].? {2,}/g, // note: repeating space @@ -108,7 +108,7 @@ module.exports = { * Creates a fix function that removes the multiple spaces between the two tokens * @param {RuleFixer} leftToken left token * @param {RuleFixer} rightToken right token - * @returns {function} fix function + * @returns {Function} fix function * @private */ function createFix(leftToken, rightToken) { diff --git a/tools/eslint/lib/rules/no-multi-str.js b/tools/eslint/lib/rules/no-multi-str.js index fe7fee4a60a..1d880104591 100644 --- a/tools/eslint/lib/rules/no-multi-str.js +++ b/tools/eslint/lib/rules/no-multi-str.js @@ -39,7 +39,7 @@ module.exports = { return { Literal: function(node) { - var lineBreak = /\n/; + let lineBreak = /\n/; if (lineBreak.test(node.raw) && !isJSXElement(node.parent)) { context.report(node, "Multiline support is limited to browsers supporting ES5 only."); diff --git a/tools/eslint/lib/rules/no-multiple-empty-lines.js b/tools/eslint/lib/rules/no-multiple-empty-lines.js index 7508164d38e..cede2d5e78a 100644 --- a/tools/eslint/lib/rules/no-multiple-empty-lines.js +++ b/tools/eslint/lib/rules/no-multiple-empty-lines.js @@ -45,12 +45,12 @@ module.exports = { create: function(context) { // Use options.max or 2 as default - var max = 2, + let max = 2, maxEOF, maxBOF; // store lines that appear empty but really aren't - var notEmpty = []; + let notEmpty = []; if (context.options.length) { max = context.options[0].max; @@ -58,7 +58,7 @@ module.exports = { maxBOF = typeof context.options[0].maxBOF !== "undefined" ? context.options[0].maxBOF : max; } - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Public @@ -67,8 +67,8 @@ module.exports = { return { TemplateLiteral: function(node) { - var start = node.loc.start.line; - var end = node.loc.end.line; + let start = node.loc.start.line; + let end = node.loc.end.line; while (start <= end) { notEmpty.push(start); @@ -77,7 +77,7 @@ module.exports = { }, "Program:exit": function checkBlankLines(node) { - var lines = sourceCode.lines, + let lines = sourceCode.lines, fullLines = sourceCode.text.match(/.*(\r\n|\r|\n|\u2028|\u2029)/g) || [], firstNonBlankLine = -1, trimmedLines = [], @@ -98,7 +98,7 @@ module.exports = { linesRangeStart.push(0); lines.forEach(function(str, i) { - var length = i < fullLines.length ? fullLines[i].length : 0, + let length = i < fullLines.length ? fullLines[i].length : 0, trimmed = str.trim(); if ((firstNonBlankLine === -1) && (trimmed !== "")) { diff --git a/tools/eslint/lib/rules/no-native-reassign.js b/tools/eslint/lib/rules/no-native-reassign.js index 8b75f022a07..aa8314dda67 100644 --- a/tools/eslint/lib/rules/no-native-reassign.js +++ b/tools/eslint/lib/rules/no-native-reassign.js @@ -33,8 +33,8 @@ module.exports = { }, create: function(context) { - var config = context.options[0]; - var exceptions = (config && config.exceptions) || []; + let config = context.options[0]; + let exceptions = (config && config.exceptions) || []; /** * Reports write references. @@ -44,7 +44,7 @@ module.exports = { * @returns {void} */ function checkReference(reference, index, references) { - var identifier = reference.identifier; + let identifier = reference.identifier; if (reference.init === false && reference.isWrite() && @@ -74,7 +74,7 @@ module.exports = { return { Program: function() { - var globalScope = context.getScope(); + let globalScope = context.getScope(); globalScope.variables.forEach(checkVariable); } diff --git a/tools/eslint/lib/rules/no-negated-in-lhs.js b/tools/eslint/lib/rules/no-negated-in-lhs.js index 891b75dd2f4..46f6c1cad43 100644 --- a/tools/eslint/lib/rules/no-negated-in-lhs.js +++ b/tools/eslint/lib/rules/no-negated-in-lhs.js @@ -26,7 +26,7 @@ module.exports = { BinaryExpression: function(node) { if (node.operator === "in" && node.left.type === "UnaryExpression" && node.left.operator === "!") { - context.report(node, "The 'in' expression's left operand is negated"); + context.report(node, "The 'in' expression's left operand is negated."); } } }; diff --git a/tools/eslint/lib/rules/no-nested-ternary.js b/tools/eslint/lib/rules/no-nested-ternary.js index 34f9eaaa8db..d28ee693cf0 100644 --- a/tools/eslint/lib/rules/no-nested-ternary.js +++ b/tools/eslint/lib/rules/no-nested-ternary.js @@ -26,7 +26,7 @@ module.exports = { ConditionalExpression: function(node) { if (node.alternate.type === "ConditionalExpression" || node.consequent.type === "ConditionalExpression") { - context.report(node, "Do not nest ternary expressions"); + context.report(node, "Do not nest ternary expressions."); } } }; diff --git a/tools/eslint/lib/rules/no-new-symbol.js b/tools/eslint/lib/rules/no-new-symbol.js index c7c524641ee..d4c4e67b17b 100644 --- a/tools/eslint/lib/rules/no-new-symbol.js +++ b/tools/eslint/lib/rules/no-new-symbol.js @@ -24,12 +24,12 @@ module.exports = { return { "Program:exit": function() { - var globalScope = context.getScope(); - var variable = globalScope.set.get("Symbol"); + let globalScope = context.getScope(); + let variable = globalScope.set.get("Symbol"); if (variable && variable.defs.length === 0) { variable.references.forEach(function(ref) { - var node = ref.identifier; + let node = ref.identifier; if (node.parent && node.parent.type === "NewExpression") { context.report(node, "`Symbol` cannot be called as a constructor."); diff --git a/tools/eslint/lib/rules/no-new-wrappers.js b/tools/eslint/lib/rules/no-new-wrappers.js index eec774fdcad..756ee80076f 100644 --- a/tools/eslint/lib/rules/no-new-wrappers.js +++ b/tools/eslint/lib/rules/no-new-wrappers.js @@ -25,7 +25,7 @@ module.exports = { return { NewExpression: function(node) { - var wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"]; + let wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"]; if (wrapperObjects.indexOf(node.callee.name) > -1) { context.report(node, "Do not use {{fn}} as a constructor.", { fn: node.callee.name }); diff --git a/tools/eslint/lib/rules/no-obj-calls.js b/tools/eslint/lib/rules/no-obj-calls.js index 0f58ab93dbd..ba1c45a31fe 100644 --- a/tools/eslint/lib/rules/no-obj-calls.js +++ b/tools/eslint/lib/rules/no-obj-calls.js @@ -26,7 +26,7 @@ module.exports = { CallExpression: function(node) { if (node.callee.type === "Identifier") { - var name = node.callee.name; + let name = node.callee.name; if (name === "Math" || name === "JSON") { context.report(node, "'{{name}}' is not a function.", { name: name }); diff --git a/tools/eslint/lib/rules/no-octal-escape.js b/tools/eslint/lib/rules/no-octal-escape.js index 3ca01324b5e..cf5953a986f 100644 --- a/tools/eslint/lib/rules/no-octal-escape.js +++ b/tools/eslint/lib/rules/no-octal-escape.js @@ -29,7 +29,7 @@ module.exports = { return; } - var match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/), + let match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/), octalDigit; if (match) { diff --git a/tools/eslint/lib/rules/no-param-reassign.js b/tools/eslint/lib/rules/no-param-reassign.js index fad61fc0c1e..3a59106a2d5 100644 --- a/tools/eslint/lib/rules/no-param-reassign.js +++ b/tools/eslint/lib/rules/no-param-reassign.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/; +let stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/; module.exports = { meta: { @@ -30,7 +30,7 @@ module.exports = { }, create: function(context) { - var props = context.options[0] && Boolean(context.options[0].props); + let props = context.options[0] && Boolean(context.options[0].props); /** * Checks whether or not the reference modifies properties of its variable. @@ -38,8 +38,8 @@ module.exports = { * @returns {boolean} Whether or not the reference modifies properties of its variable. */ function isModifyingProp(reference) { - var node = reference.identifier; - var parent = node.parent; + let node = reference.identifier; + let parent = node.parent; while (parent && !stopNodePattern.test(parent.type)) { switch (parent.type) { @@ -92,7 +92,7 @@ module.exports = { * @returns {void} */ function checkReference(reference, index, references) { - var identifier = reference.identifier; + let identifier = reference.identifier; if (identifier && !reference.init && diff --git a/tools/eslint/lib/rules/no-path-concat.js b/tools/eslint/lib/rules/no-path-concat.js index 1412c6c32e3..f13d9426745 100644 --- a/tools/eslint/lib/rules/no-path-concat.js +++ b/tools/eslint/lib/rules/no-path-concat.js @@ -21,7 +21,7 @@ module.exports = { create: function(context) { - var MATCHER = /^__(?:dir|file)name$/; + let MATCHER = /^__(?:dir|file)name$/; //-------------------------------------------------------------------------- // Public @@ -31,7 +31,7 @@ module.exports = { BinaryExpression: function(node) { - var left = node.left, + let left = node.left, right = node.right; if (node.operator === "+" && diff --git a/tools/eslint/lib/rules/no-plusplus.js b/tools/eslint/lib/rules/no-plusplus.js index 159a42be2c1..34e54001ae5 100644 --- a/tools/eslint/lib/rules/no-plusplus.js +++ b/tools/eslint/lib/rules/no-plusplus.js @@ -33,7 +33,7 @@ module.exports = { create: function(context) { - var config = context.options[0], + let config = context.options[0], allowInForAfterthought = false; if (typeof config === "object") { diff --git a/tools/eslint/lib/rules/no-process-env.js b/tools/eslint/lib/rules/no-process-env.js index af48c780298..d1bf15a245d 100644 --- a/tools/eslint/lib/rules/no-process-env.js +++ b/tools/eslint/lib/rules/no-process-env.js @@ -24,7 +24,7 @@ module.exports = { return { MemberExpression: function(node) { - var objectName = node.object.name, + let objectName = node.object.name, propertyName = node.property.name; if (objectName === "process" && !node.computed && propertyName && propertyName === "env") { diff --git a/tools/eslint/lib/rules/no-process-exit.js b/tools/eslint/lib/rules/no-process-exit.js index 6d8674418bb..045214e7e74 100644 --- a/tools/eslint/lib/rules/no-process-exit.js +++ b/tools/eslint/lib/rules/no-process-exit.js @@ -28,7 +28,7 @@ module.exports = { return { CallExpression: function(node) { - var callee = node.callee; + let callee = node.callee; if (callee.type === "MemberExpression" && callee.object.name === "process" && callee.property.name === "exit" diff --git a/tools/eslint/lib/rules/no-prototype-builtins.js b/tools/eslint/lib/rules/no-prototype-builtins.js index febb1459be6..08b0b6dcf9a 100644 --- a/tools/eslint/lib/rules/no-prototype-builtins.js +++ b/tools/eslint/lib/rules/no-prototype-builtins.js @@ -14,11 +14,13 @@ module.exports = { description: "disallow calling some `Object.prototype` methods directly on objects", category: "Possible Errors", recommended: false - } + }, + + schema: [] }, create: function(context) { - var DISALLOWED_PROPS = [ + let DISALLOWED_PROPS = [ "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable" @@ -33,7 +35,7 @@ module.exports = { if (node.callee.type !== "MemberExpression" || node.callee.computed) { return; } - var propName = node.callee.property.name; + let propName = node.callee.property.name; if (DISALLOWED_PROPS.indexOf(propName) > -1) { context.report({ diff --git a/tools/eslint/lib/rules/no-redeclare.js b/tools/eslint/lib/rules/no-redeclare.js index 4253cc85334..8a1540ff79f 100644 --- a/tools/eslint/lib/rules/no-redeclare.js +++ b/tools/eslint/lib/rules/no-redeclare.js @@ -29,7 +29,7 @@ module.exports = { }, create: function(context) { - var options = { + let options = { builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals) }; @@ -41,18 +41,18 @@ module.exports = { */ function findVariablesInScope(scope) { scope.variables.forEach(function(variable) { - var hasBuiltin = options.builtinGlobals && "writeable" in variable; - var count = (hasBuiltin ? 1 : 0) + variable.identifiers.length; + let hasBuiltin = options.builtinGlobals && "writeable" in variable; + let count = (hasBuiltin ? 1 : 0) + variable.identifiers.length; if (count >= 2) { variable.identifiers.sort(function(a, b) { return a.range[1] - b.range[1]; }); - for (var i = (hasBuiltin ? 0 : 1), l = variable.identifiers.length; i < l; i++) { + for (let i = (hasBuiltin ? 0 : 1), l = variable.identifiers.length; i < l; i++) { context.report( variable.identifiers[i], - "'{{a}}' is already defined", + "'{{a}}' is already defined.", {a: variable.name}); } } @@ -67,7 +67,7 @@ module.exports = { * @private */ function checkForGlobal(node) { - var scope = context.getScope(), + let scope = context.getScope(), parserOptions = context.parserOptions, ecmaFeatures = parserOptions.ecmaFeatures || {}; diff --git a/tools/eslint/lib/rules/no-regex-spaces.js b/tools/eslint/lib/rules/no-regex-spaces.js index a2f1d48f716..de179894b36 100644 --- a/tools/eslint/lib/rules/no-regex-spaces.js +++ b/tools/eslint/lib/rules/no-regex-spaces.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Validate regular expressions @@ -31,7 +31,7 @@ module.exports = { * @private */ function checkRegex(node, value) { - var multipleSpacesRegex = /( {2,})+?/, + let multipleSpacesRegex = /( {2,})+?/, regexResults = multipleSpacesRegex.exec(value); if (regexResults !== null) { @@ -46,7 +46,7 @@ module.exports = { * @private */ function checkLiteral(node) { - var token = sourceCode.getFirstToken(node), + let token = sourceCode.getFirstToken(node), nodeType = token.type, nodeValue = token.value; diff --git a/tools/eslint/lib/rules/no-restricted-globals.js b/tools/eslint/lib/rules/no-restricted-globals.js index 3292705b13b..19bd6a94aec 100644 --- a/tools/eslint/lib/rules/no-restricted-globals.js +++ b/tools/eslint/lib/rules/no-restricted-globals.js @@ -26,7 +26,7 @@ module.exports = { }, create: function(context) { - var restrictedGlobals = context.options; + let restrictedGlobals = context.options; // if no globals are restricted we don't need to check if (restrictedGlobals.length === 0) { @@ -40,7 +40,7 @@ module.exports = { * @private */ function reportReference(reference) { - context.report(reference.identifier, "Unexpected use of '{{name}}'", { + context.report(reference.identifier, "Unexpected use of '{{name}}'.", { name: reference.identifier.name }); } @@ -57,7 +57,7 @@ module.exports = { return { Program: function() { - var scope = context.getScope(); + let scope = context.getScope(); // Report variables declared elsewhere (ex: variables defined as "global" by eslint) scope.variables.forEach(function(variable) { @@ -77,4 +77,3 @@ module.exports = { }; } }; - diff --git a/tools/eslint/lib/rules/no-restricted-imports.js b/tools/eslint/lib/rules/no-restricted-imports.js index 3129ce72784..da768c135c7 100644 --- a/tools/eslint/lib/rules/no-restricted-imports.js +++ b/tools/eslint/lib/rules/no-restricted-imports.js @@ -26,7 +26,7 @@ module.exports = { }, create: function(context) { - var restrictedImports = context.options; + let restrictedImports = context.options; // if no imports are restricted we don"t need to check if (restrictedImports.length === 0) { @@ -37,7 +37,7 @@ module.exports = { ImportDeclaration: function(node) { if (node && node.source && node.source.value) { - var value = node.source.value.trim(); + let value = node.source.value.trim(); if (restrictedImports.indexOf(value) !== -1) { context.report(node, "'{{importName}}' import is restricted from being used.", { diff --git a/tools/eslint/lib/rules/no-restricted-modules.js b/tools/eslint/lib/rules/no-restricted-modules.js index 43e53915628..eeb6bf270d3 100644 --- a/tools/eslint/lib/rules/no-restricted-modules.js +++ b/tools/eslint/lib/rules/no-restricted-modules.js @@ -28,7 +28,7 @@ module.exports = { create: function(context) { // trim restricted module names - var restrictedModules = context.options; + let restrictedModules = context.options; // if no modules are restricted we don't need to check the CallExpressions if (restrictedModules.length === 0) { @@ -56,14 +56,14 @@ module.exports = { /** * Function to check if a node has an argument that is an restricted module and return its name. * @param {ASTNode} node The node to check - * @returns {undefined|String} restricted module name or undefined if node argument isn't restricted. + * @returns {undefined|string} restricted module name or undefined if node argument isn't restricted. */ function getRestrictedModuleName(node) { - var moduleName; + let moduleName; // node has arguments and first argument is string if (node.arguments.length && isString(node.arguments[0])) { - var argumentValue = node.arguments[0].value.trim(); + let argumentValue = node.arguments[0].value.trim(); // check if argument value is in restricted modules array if (restrictedModules.indexOf(argumentValue) !== -1) { @@ -77,7 +77,7 @@ module.exports = { return { CallExpression: function(node) { if (isRequireCall(node)) { - var restrictedModuleName = getRestrictedModuleName(node); + let restrictedModuleName = getRestrictedModuleName(node); if (restrictedModuleName) { context.report(node, "'{{moduleName}}' module is restricted from being used.", { diff --git a/tools/eslint/lib/rules/no-restricted-syntax.js b/tools/eslint/lib/rules/no-restricted-syntax.js index cd9eb603f98..84c62d63ac0 100644 --- a/tools/eslint/lib/rules/no-restricted-syntax.js +++ b/tools/eslint/lib/rules/no-restricted-syntax.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var nodeTypes = require("espree").Syntax; +let nodeTypes = require("espree").Syntax; module.exports = { meta: { diff --git a/tools/eslint/lib/rules/no-return-assign.js b/tools/eslint/lib/rules/no-return-assign.js index 38fc1cb0ebb..54935060710 100644 --- a/tools/eslint/lib/rules/no-return-assign.js +++ b/tools/eslint/lib/rules/no-return-assign.js @@ -8,7 +8,7 @@ // Helpers //------------------------------------------------------------------------------ -var SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/; +let SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/; /** * Checks whether or not a node is enclosed in parentheses. @@ -17,8 +17,8 @@ var SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExp * @returns {boolean} Whether or not the node is enclosed in parentheses. */ function isEnclosedInParens(node, sourceCode) { - var prevToken = sourceCode.getTokenBefore(node); - var nextToken = sourceCode.getTokenAfter(node); + let prevToken = sourceCode.getTokenBefore(node); + let nextToken = sourceCode.getTokenAfter(node); return prevToken && prevToken.value === "(" && nextToken && nextToken.value === ")"; } @@ -43,8 +43,8 @@ module.exports = { }, create: function(context) { - var always = (context.options[0] || "except-parens") !== "except-parens"; - var sourceCode = context.getSourceCode(); + let always = (context.options[0] || "except-parens") !== "except-parens"; + let sourceCode = context.getSourceCode(); return { AssignmentExpression: function(node) { @@ -52,7 +52,7 @@ module.exports = { return; } - var parent = node.parent; + let parent = node.parent; // Find ReturnStatement or ArrowFunctionExpression in ancestors. while (parent && !SENTINEL_TYPE.test(parent.type)) { diff --git a/tools/eslint/lib/rules/no-script-url.js b/tools/eslint/lib/rules/no-script-url.js index 1985cf3b95f..1c12490b433 100644 --- a/tools/eslint/lib/rules/no-script-url.js +++ b/tools/eslint/lib/rules/no-script-url.js @@ -28,7 +28,7 @@ module.exports = { Literal: function(node) { - var value; + let value; if (node.value && typeof node.value === "string") { value = node.value.toLowerCase(); diff --git a/tools/eslint/lib/rules/no-self-assign.js b/tools/eslint/lib/rules/no-self-assign.js index bcccc3d8380..e3dc35e81e7 100644 --- a/tools/eslint/lib/rules/no-self-assign.js +++ b/tools/eslint/lib/rules/no-self-assign.js @@ -16,11 +16,11 @@ * a Property. * @param {ASTNode|null} right - A right node to traverse. This is a Pattern or * a Property. - * @param {function} report - A callback function to report. + * @param {Function} report - A callback function to report. * @returns {void} */ function eachSelfAssignment(left, right, report) { - var i, j; + let i, j; if (!left || !right) { @@ -35,10 +35,10 @@ function eachSelfAssignment(left, right, report) { left.type === "ArrayPattern" && right.type === "ArrayExpression" ) { - var end = Math.min(left.elements.length, right.elements.length); + let end = Math.min(left.elements.length, right.elements.length); for (i = 0; i < end; ++i) { - var rightElement = right.elements[i]; + let rightElement = right.elements[i]; eachSelfAssignment(left.elements[i], rightElement, report); @@ -60,7 +60,7 @@ function eachSelfAssignment(left, right, report) { // Gets the index of the last spread property. // It's possible to overwrite properties followed by it. - var startJ = 0; + let startJ = 0; for (i = right.properties.length - 1; i >= 0; --i) { if (right.properties[i].type === "ExperimentalSpreadProperty") { diff --git a/tools/eslint/lib/rules/no-self-compare.js b/tools/eslint/lib/rules/no-self-compare.js index eef05080b75..c677e56ffdb 100644 --- a/tools/eslint/lib/rules/no-self-compare.js +++ b/tools/eslint/lib/rules/no-self-compare.js @@ -26,7 +26,7 @@ module.exports = { return { BinaryExpression: function(node) { - var operators = ["===", "==", "!==", "!=", ">", "<", ">=", "<="]; + let operators = ["===", "==", "!==", "!=", ">", "<", ">=", "<="]; if (operators.indexOf(node.operator) > -1 && (node.left.type === "Identifier" && node.right.type === "Identifier" && node.left.name === node.right.name || diff --git a/tools/eslint/lib/rules/no-sequences.js b/tools/eslint/lib/rules/no-sequences.js index b0d318c7d08..51c3b8e8080 100644 --- a/tools/eslint/lib/rules/no-sequences.js +++ b/tools/eslint/lib/rules/no-sequences.js @@ -21,12 +21,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Parts of the grammar that are required to have parens. */ - var parenthesized = { + let parenthesized = { DoWhileStatement: "test", IfStatement: "test", SwitchStatement: "discriminant", @@ -57,7 +57,7 @@ module.exports = { * @returns {boolean} True if the node has a paren on each side. */ function isParenthesised(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return previousToken && nextToken && @@ -71,7 +71,7 @@ module.exports = { * @returns {boolean} True if two parens surround the node on each side. */ function isParenthesisedTwice(node) { - var previousToken = sourceCode.getTokenBefore(node, 1), + let previousToken = sourceCode.getTokenBefore(node, 1), nextToken = sourceCode.getTokenAfter(node, 1); return isParenthesised(node) && previousToken && nextToken && @@ -99,7 +99,7 @@ module.exports = { } } - var child = sourceCode.getTokenAfter(node.expressions[0]); + let child = sourceCode.getTokenAfter(node.expressions[0]); context.report(node, child.loc.start, "Unexpected use of comma operator."); } diff --git a/tools/eslint/lib/rules/no-shadow-restricted-names.js b/tools/eslint/lib/rules/no-shadow-restricted-names.js index b7731d9d676..d932363d6f7 100644 --- a/tools/eslint/lib/rules/no-shadow-restricted-names.js +++ b/tools/eslint/lib/rules/no-shadow-restricted-names.js @@ -21,7 +21,7 @@ module.exports = { create: function(context) { - var RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"]; + let RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"]; /** * Check if the node name is present inside the restricted list diff --git a/tools/eslint/lib/rules/no-shadow.js b/tools/eslint/lib/rules/no-shadow.js index ee0dd69f3a5..62f75047807 100644 --- a/tools/eslint/lib/rules/no-shadow.js +++ b/tools/eslint/lib/rules/no-shadow.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -43,7 +43,7 @@ module.exports = { create: function(context) { - var options = { + let options = { builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals), hoist: (context.options[0] && context.options[0].hoist) || "functions", allow: (context.options[0] && context.options[0].allow) || [] @@ -69,7 +69,7 @@ module.exports = { * @returns {boolean} Whether or not the variable of the class name in the class scope of ClassDeclaration. */ function isDuplicatedClassNameVariable(variable) { - var block = variable.scope.block; + let block = variable.scope.block; return block.type === "ClassDeclaration" && block.id === variable.identifiers[0]; } @@ -85,12 +85,12 @@ module.exports = { * @returns {boolean} Whether or not the variable is inside initializer of scopeVar. */ function isOnInitializer(variable, scopeVar) { - var outerScope = scopeVar.scope; - var outerDef = scopeVar.defs[0]; - var outer = outerDef && outerDef.parent && outerDef.parent.range; - var innerScope = variable.scope; - var innerDef = variable.defs[0]; - var inner = innerDef && innerDef.name.range; + let outerScope = scopeVar.scope; + let outerDef = scopeVar.defs[0]; + let outer = outerDef && outerDef.parent && outerDef.parent.range; + let innerScope = variable.scope; + let innerDef = variable.defs[0]; + let inner = innerDef && innerDef.name.range; return ( outer && @@ -108,7 +108,7 @@ module.exports = { * @returns {Array|undefined} The range of the variable's identifier node. */ function getNameRange(variable) { - var def = variable.defs[0]; + let def = variable.defs[0]; return def && def.name.range; } @@ -120,9 +120,9 @@ module.exports = { * @returns {boolean} Whether or not the variable is in TDZ of scopeVar. */ function isInTdz(variable, scopeVar) { - var outerDef = scopeVar.defs[0]; - var inner = getNameRange(variable); - var outer = getNameRange(scopeVar); + let outerDef = scopeVar.defs[0]; + let inner = getNameRange(variable); + let outer = getNameRange(scopeVar); return ( inner && @@ -140,10 +140,10 @@ module.exports = { * @returns {void} */ function checkForShadows(scope) { - var variables = scope.variables; + let variables = scope.variables; - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; // Skips "arguments" or variables of a class name in the class scope of ClassDeclaration. if (variable.identifiers.length === 0 || @@ -154,7 +154,7 @@ module.exports = { } // Gets shadowed variable. - var shadowed = astUtils.getVariableByName(scope.upper, variable.name); + let shadowed = astUtils.getVariableByName(scope.upper, variable.name); if (shadowed && (shadowed.identifiers.length > 0 || (options.builtinGlobals && "writeable" in shadowed)) && @@ -172,9 +172,9 @@ module.exports = { return { "Program:exit": function() { - var globalScope = context.getScope(); - var stack = globalScope.childScopes.slice(); - var scope; + let globalScope = context.getScope(); + let stack = globalScope.childScopes.slice(); + let scope; while (stack.length) { scope = stack.pop(); diff --git a/tools/eslint/lib/rules/no-spaced-func.js b/tools/eslint/lib/rules/no-spaced-func.js index f0a16121136..90765645e87 100644 --- a/tools/eslint/lib/rules/no-spaced-func.js +++ b/tools/eslint/lib/rules/no-spaced-func.js @@ -23,7 +23,7 @@ module.exports = { create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check if open space is present in a function name @@ -32,7 +32,7 @@ module.exports = { * @private */ function detectOpenSpaces(node) { - var lastCalleeToken = sourceCode.getLastToken(node.callee), + let lastCalleeToken = sourceCode.getLastToken(node.callee), prevToken = lastCalleeToken, parenToken = sourceCode.getTokenAfter(lastCalleeToken); diff --git a/tools/eslint/lib/rules/no-sparse-arrays.js b/tools/eslint/lib/rules/no-sparse-arrays.js index b1ae0ba7403..4d4bfd9944c 100644 --- a/tools/eslint/lib/rules/no-sparse-arrays.js +++ b/tools/eslint/lib/rules/no-sparse-arrays.js @@ -30,7 +30,7 @@ module.exports = { ArrayExpression: function(node) { - var emptySpot = node.elements.indexOf(null) > -1; + let emptySpot = node.elements.indexOf(null) > -1; if (emptySpot) { context.report(node, "Unexpected comma in middle of array."); diff --git a/tools/eslint/lib/rules/no-sync.js b/tools/eslint/lib/rules/no-sync.js index be6860e75af..ddd1f9484b9 100644 --- a/tools/eslint/lib/rules/no-sync.js +++ b/tools/eslint/lib/rules/no-sync.js @@ -27,7 +27,7 @@ module.exports = { return { MemberExpression: function(node) { - var propertyName = node.property.name, + let propertyName = node.property.name, syncRegex = /.*Sync$/; if (syncRegex.exec(propertyName) !== null) { diff --git a/tools/eslint/lib/rules/no-tabs.js b/tools/eslint/lib/rules/no-tabs.js new file mode 100644 index 00000000000..ef873db2bdb --- /dev/null +++ b/tools/eslint/lib/rules/no-tabs.js @@ -0,0 +1,47 @@ +/** + * @fileoverview Rule to check for tabs inside a file + * @author Gyandeep Singh + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ +const regex = /\t/; + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: "Disallow tabs in file", + category: "Stylistic Issues", + recommended: false + }, + schema: [] + }, + + create(context) { + return { + Program(node) { + context.getSourceLines().forEach((line, index) => { + const match = regex.exec(line); + + if (match) { + context.report( + node, + { + line: index + 1, + column: match.index + 1 + }, + "Unexpected tab character." + ); + } + }); + } + }; + } +}; diff --git a/tools/eslint/lib/rules/no-this-before-super.js b/tools/eslint/lib/rules/no-this-before-super.js index fb172f47f3a..82eda02160a 100644 --- a/tools/eslint/lib/rules/no-this-before-super.js +++ b/tools/eslint/lib/rules/no-this-before-super.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -55,7 +55,7 @@ module.exports = { * - scope: The scope of the owner class. * - codePath: The code path of this constructor. */ - var funcInfo = null; + let funcInfo = null; /* * Information for each code path segment. @@ -64,7 +64,7 @@ module.exports = { * - superCalled: The flag which shows `super()` called in all code paths. * - invalidNodes: The array of invalid ThisExpression and Super nodes. */ - var segInfoMap = Object.create(null); + let segInfoMap = Object.create(null); /** * Gets whether or not `super()` is called in a given code path segment. @@ -101,10 +101,10 @@ module.exports = { * @returns {void} */ function setInvalid(node) { - var segments = funcInfo.codePath.currentSegments; + let segments = funcInfo.codePath.currentSegments; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { segInfoMap[segment.id].invalidNodes.push(node); @@ -117,10 +117,10 @@ module.exports = { * @returns {void} */ function setSuperCalled() { - var segments = funcInfo.codePath.currentSegments; + let segments = funcInfo.codePath.currentSegments; - for (var i = 0; i < segments.length; ++i) { - var segment = segments[i]; + for (let i = 0; i < segments.length; ++i) { + let segment = segments[i]; if (segment.reachable) { segInfoMap[segment.id].superCalled = true; @@ -140,7 +140,7 @@ module.exports = { if (isConstructorFunction(node)) { // Class > ClassBody > MethodDefinition > FunctionExpression - var classNode = node.parent.parent.parent; + let classNode = node.parent.parent.parent; funcInfo = { upper: funcInfo, @@ -172,7 +172,7 @@ module.exports = { * @returns {void} */ onCodePathEnd: function(codePath) { - var isDerivedClass = funcInfo.hasExtends; + let isDerivedClass = funcInfo.hasExtends; funcInfo = funcInfo.upper; if (!isDerivedClass) { @@ -180,10 +180,10 @@ module.exports = { } codePath.traverseSegments(function(segment, controller) { - var info = segInfoMap[segment.id]; + let info = segInfoMap[segment.id]; - for (var i = 0; i < info.invalidNodes.length; ++i) { - var invalidNode = info.invalidNodes[i]; + for (let i = 0; i < info.invalidNodes.length; ++i) { + let invalidNode = info.invalidNodes[i]; context.report({ message: "'{{kind}}' is not allowed before 'super()'.", @@ -238,7 +238,7 @@ module.exports = { funcInfo.codePath.traverseSegments( {first: toSegment, last: fromSegment}, function(segment, controller) { - var info = segInfoMap[segment.id]; + let info = segInfoMap[segment.id]; if (info.superCalled) { info.invalidNodes = []; diff --git a/tools/eslint/lib/rules/no-throw-literal.js b/tools/eslint/lib/rules/no-throw-literal.js index bedf94379e8..69eda1c7654 100644 --- a/tools/eslint/lib/rules/no-throw-literal.js +++ b/tools/eslint/lib/rules/no-throw-literal.js @@ -27,10 +27,11 @@ function couldBeError(node) { case "AssignmentExpression": return couldBeError(node.right); - case "SequenceExpression": - var exprs = node.expressions; + case "SequenceExpression": { + const exprs = node.expressions; return exprs.length !== 0 && couldBeError(exprs[exprs.length - 1]); + } case "LogicalExpression": return couldBeError(node.left) || couldBeError(node.right); diff --git a/tools/eslint/lib/rules/no-trailing-spaces.js b/tools/eslint/lib/rules/no-trailing-spaces.js index a08907fc95f..6b82cfc38cd 100644 --- a/tools/eslint/lib/rules/no-trailing-spaces.js +++ b/tools/eslint/lib/rules/no-trailing-spaces.js @@ -32,13 +32,13 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]", + let BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]", SKIP_BLANK = "^" + BLANK_CLASS + "*$", NONBLANK = BLANK_CLASS + "+$"; - var options = context.options[0] || {}, + let options = context.options[0] || {}, skipBlankLines = options.skipBlankLines || false; /** @@ -78,7 +78,7 @@ module.exports = { // Let's hack. Since Espree does not return whitespace nodes, // fetch the source code and do matching via regexps. - var re = new RegExp(NONBLANK), + let re = new RegExp(NONBLANK), skipMatch = new RegExp(SKIP_BLANK), matches, lines = sourceCode.lines, @@ -90,14 +90,14 @@ module.exports = { fixRange = [], containingNode; - for (var i = 0, ii = lines.length; i < ii; i++) { + for (let i = 0, ii = lines.length; i < ii; i++) { matches = re.exec(lines[i]); // Always add linebreak length to line length to accommodate for line break (\n or \r\n) // Because during the fix time they also reserve one spot in the array. // Usually linebreak length is 2 for \r\n (CRLF) and 1 for \n (LF) - var linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1; - var lineLength = lines[i].length + linebreakLength; + let linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1; + let lineLength = lines[i].length + linebreakLength; if (matches) { location = { diff --git a/tools/eslint/lib/rules/no-undef-init.js b/tools/eslint/lib/rules/no-undef-init.js index 8622e45701f..2683f61e8aa 100644 --- a/tools/eslint/lib/rules/no-undef-init.js +++ b/tools/eslint/lib/rules/no-undef-init.js @@ -25,7 +25,7 @@ module.exports = { return { VariableDeclarator: function(node) { - var name = node.id.name, + let name = node.id.name, init = node.init && node.init.name; if (init === "undefined" && node.parent.kind !== "const") { diff --git a/tools/eslint/lib/rules/no-undef.js b/tools/eslint/lib/rules/no-undef.js index b76ce4bb5bf..da9437157ce 100644 --- a/tools/eslint/lib/rules/no-undef.js +++ b/tools/eslint/lib/rules/no-undef.js @@ -14,7 +14,7 @@ * @returns {boolean} Whether or not the node is the argument of a typeof operator. */ function hasTypeOfOperator(node) { - var parent = node.parent; + let parent = node.parent; return parent.type === "UnaryExpression" && parent.operator === "typeof"; } @@ -45,15 +45,15 @@ module.exports = { }, create: function(context) { - var options = context.options[0]; - var considerTypeOf = options && options.typeof === true || false; + let options = context.options[0]; + let considerTypeOf = options && options.typeof === true || false; return { "Program:exit": function(/* node */) { - var globalScope = context.getScope(); + let globalScope = context.getScope(); globalScope.through.forEach(function(ref) { - var identifier = ref.identifier; + let identifier = ref.identifier; if (!considerTypeOf && hasTypeOfOperator(identifier)) { return; diff --git a/tools/eslint/lib/rules/no-undefined.js b/tools/eslint/lib/rules/no-undefined.js index 3ad2128b4ef..a34d665203f 100644 --- a/tools/eslint/lib/rules/no-undefined.js +++ b/tools/eslint/lib/rules/no-undefined.js @@ -25,7 +25,7 @@ module.exports = { Identifier: function(node) { if (node.name === "undefined") { - var parent = context.getAncestors().pop(); + let parent = context.getAncestors().pop(); if (!parent || parent.type !== "MemberExpression" || node !== parent.property || parent.computed) { context.report(node, "Unexpected use of undefined."); diff --git a/tools/eslint/lib/rules/no-underscore-dangle.js b/tools/eslint/lib/rules/no-underscore-dangle.js index 4217f8adc53..a6a3b174fc2 100644 --- a/tools/eslint/lib/rules/no-underscore-dangle.js +++ b/tools/eslint/lib/rules/no-underscore-dangle.js @@ -29,6 +29,9 @@ module.exports = { }, allowAfterThis: { type: "boolean" + }, + allowAfterSuper: { + type: "boolean" } }, additionalProperties: false @@ -38,9 +41,10 @@ module.exports = { create: function(context) { - var options = context.options[0] || {}; - var ALLOWED_VARIABLES = options.allow ? options.allow : []; - var allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false; + let options = context.options[0] || {}; + let ALLOWED_VARIABLES = options.allow ? options.allow : []; + let allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false; + let allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false; //------------------------------------------------------------------------- // Helpers @@ -65,7 +69,7 @@ module.exports = { * @private */ function hasTrailingUnderscore(identifier) { - var len = identifier.length; + let len = identifier.length; return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_"); } @@ -100,7 +104,7 @@ module.exports = { */ function checkForTrailingUnderscoreInFunctionDeclaration(node) { if (node.id) { - var identifier = node.id.name; + let identifier = node.id.name; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) { context.report(node, "Unexpected dangling '_' in '" + identifier + "'."); @@ -115,7 +119,7 @@ module.exports = { * @private */ function checkForTrailingUnderscoreInVariableExpression(node) { - var identifier = node.id.name; + let identifier = node.id.name; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) { @@ -130,11 +134,13 @@ module.exports = { * @private */ function checkForTrailingUnderscoreInMemberExpression(node) { - var identifier = node.property.name, - isMemberOfThis = node.object.type === "ThisExpression"; + let identifier = node.property.name, + isMemberOfThis = node.object.type === "ThisExpression", + isMemberOfSuper = node.object.type === "Super"; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !(isMemberOfThis && allowAfterThis) && + !(isMemberOfSuper && allowAfterSuper) && !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) { context.report(node, "Unexpected dangling '_' in '" + identifier + "'."); } diff --git a/tools/eslint/lib/rules/no-unexpected-multiline.js b/tools/eslint/lib/rules/no-unexpected-multiline.js index af0beb2c4dd..6fcb8c681a9 100644 --- a/tools/eslint/lib/rules/no-unexpected-multiline.js +++ b/tools/eslint/lib/rules/no-unexpected-multiline.js @@ -20,11 +20,11 @@ module.exports = { create: function(context) { - var FUNCTION_MESSAGE = "Unexpected newline between function and ( of function call."; - var PROPERTY_MESSAGE = "Unexpected newline between object and [ of property access."; - var TAGGED_TEMPLATE_MESSAGE = "Unexpected newline between template tag and template literal."; + let FUNCTION_MESSAGE = "Unexpected newline between function and ( of function call."; + let PROPERTY_MESSAGE = "Unexpected newline between object and [ of property access."; + let TAGGED_TEMPLATE_MESSAGE = "Unexpected newline between template tag and template literal."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check to see if there is a newline between the node and the following open bracket @@ -35,8 +35,8 @@ module.exports = { * @private */ function checkForBreakAfter(node, msg) { - var nodeExpressionEnd = node; - var openParen = sourceCode.getTokenAfter(node); + let nodeExpressionEnd = node; + let openParen = sourceCode.getTokenAfter(node); // Move along until the end of the wrapped expression while (openParen.value === ")") { diff --git a/tools/eslint/lib/rules/no-unmodified-loop-condition.js b/tools/eslint/lib/rules/no-unmodified-loop-condition.js index ed49b5996ef..099dd5f955e 100644 --- a/tools/eslint/lib/rules/no-unmodified-loop-condition.js +++ b/tools/eslint/lib/rules/no-unmodified-loop-condition.js @@ -9,27 +9,26 @@ // Requirements //------------------------------------------------------------------------------ -var Map = require("es6-map"), - Traverser = require("../util/traverser"), +let Traverser = require("../util/traverser"), astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var pushAll = Function.apply.bind(Array.prototype.push); -var SENTINEL_PATTERN = /(?:(?:Call|Class|Function|Member|New|Yield)Expression|Statement|Declaration)$/; -var LOOP_PATTERN = /^(?:DoWhile|For|While)Statement$/; -var GROUP_PATTERN = /^(?:BinaryExpression|ConditionalExpression)$/; -var SKIP_PATTERN = /^(?:ArrowFunction|Class|Function)Expression$/; -var DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/; +let pushAll = Function.apply.bind(Array.prototype.push); +let SENTINEL_PATTERN = /(?:(?:Call|Class|Function|Member|New|Yield)Expression|Statement|Declaration)$/; +let LOOP_PATTERN = /^(?:DoWhile|For|While)Statement$/; // for-in/of statements don't have `test` property. +let GROUP_PATTERN = /^(?:BinaryExpression|ConditionalExpression)$/; +let SKIP_PATTERN = /^(?:ArrowFunction|Class|Function)Expression$/; +let DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/; /** - * @typedef {object} LoopConditionInfo + * @typedef {Object} LoopConditionInfo * @property {escope.Reference} reference - The reference. * @property {ASTNode} group - BinaryExpression or ConditionalExpression nodes * that the reference is belonging to. - * @property {function} isInLoop - The predicate which checks a given reference + * @property {Function} isInLoop - The predicate which checks a given reference * is in this loop. * @property {boolean} modified - The flag that the reference is modified in * this loop. @@ -43,7 +42,7 @@ var DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/; */ function isWriteReference(reference) { if (reference.init) { - var def = reference.resolved && reference.resolved.defs[0]; + let def = reference.resolved && reference.resolved.defs[0]; if (!def || def.type !== "Variable" || def.parent.kind !== "var") { return false; @@ -82,8 +81,8 @@ function isUnmodifiedAndNotBelongToGroup(condition) { * @returns {boolean} `true` if the reference is inside of the node. */ function isInRange(node, reference) { - var or = node.range; - var ir = reference.identifier.range; + let or = node.range; + let ir = reference.identifier.range; return or[0] <= ir[0] && ir[1] <= or[1]; } @@ -96,7 +95,7 @@ function isInRange(node, reference) { * @returns {boolean} `true` if the reference is inside of the loop node's * condition. */ -var isInLoop = { +let isInLoop = { WhileStatement: isInRange, DoWhileStatement: isInRange, ForStatement: function(node, reference) { @@ -115,7 +114,7 @@ var isInLoop = { * @returns {boolean} `true` if the node is dynamic. */ function hasDynamicExpressions(root) { - var retv = false, + let retv = false, traverser = new Traverser(); traverser.traverse(root, { @@ -143,9 +142,9 @@ function toLoopCondition(reference) { return null; } - var group = null; - var child = reference.identifier; - var node = child.parent; + let group = null; + let child = reference.identifier; + let node = child.parent; while (node) { if (SENTINEL_PATTERN.test(node.type)) { @@ -193,7 +192,7 @@ function toLoopCondition(reference) { * @returns {ASTNode|null} The function node or null. */ function getEncloseFunctionDeclaration(reference) { - var node = reference.identifier; + let node = reference.identifier; while (node) { if (node.type === "FunctionDeclaration") { @@ -214,13 +213,13 @@ function getEncloseFunctionDeclaration(reference) { * @returns {void} */ function updateModifiedFlag(conditions, modifiers) { - var funcNode, funcVar; + let funcNode, funcVar; - for (var i = 0; i < conditions.length; ++i) { - var condition = conditions[i]; + for (let i = 0; i < conditions.length; ++i) { + let condition = conditions[i]; - for (var j = 0; !condition.modified && j < modifiers.length; ++j) { - var modifier = modifiers[j], + for (let j = 0; !condition.modified && j < modifiers.length; ++j) { + let modifier = modifiers[j], inLoop; /* @@ -255,7 +254,7 @@ module.exports = { }, create: function(context) { - var groupMap = null; + let groupMap = null; /** * Reports a given condition info. @@ -264,7 +263,7 @@ module.exports = { * @returns {void} */ function report(condition) { - var node = condition.reference.identifier; + let node = condition.reference.identifier; context.report({ node: node, @@ -281,11 +280,11 @@ module.exports = { * @returns {void} */ function registerConditionsToGroup(conditions) { - for (var i = 0; i < conditions.length; ++i) { - var condition = conditions[i]; + for (let i = 0; i < conditions.length; ++i) { + let condition = conditions[i]; if (condition.group) { - var group = groupMap.get(condition.group); + let group = groupMap.get(condition.group); if (!group) { group = []; @@ -318,7 +317,7 @@ module.exports = { function checkReferences(variable) { // Gets references that exist in loop conditions. - var conditions = variable + let conditions = variable .references .map(toLoopCondition) .filter(Boolean); @@ -331,7 +330,7 @@ module.exports = { registerConditionsToGroup(conditions); // Check the conditions are modified. - var modifiers = variable.references.filter(isWriteReference); + let modifiers = variable.references.filter(isWriteReference); if (modifiers.length > 0) { updateModifiedFlag(conditions, modifiers); @@ -348,11 +347,11 @@ module.exports = { return { "Program:exit": function() { - var queue = [context.getScope()]; + let queue = [context.getScope()]; groupMap = new Map(); - var scope; + let scope; while ((scope = queue.pop())) { pushAll(queue, scope.childScopes); diff --git a/tools/eslint/lib/rules/no-unneeded-ternary.js b/tools/eslint/lib/rules/no-unneeded-ternary.js index 1c344a42e61..64c767ed0eb 100644 --- a/tools/eslint/lib/rules/no-unneeded-ternary.js +++ b/tools/eslint/lib/rules/no-unneeded-ternary.js @@ -31,8 +31,8 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var defaultAssignment = options.defaultAssignment !== false; + let options = context.options[0] || {}; + let defaultAssignment = options.defaultAssignment !== false; /** * Test if the node is a boolean literal @@ -60,9 +60,9 @@ module.exports = { ConditionalExpression: function(node) { if (isBooleanLiteral(node.alternate) && isBooleanLiteral(node.consequent)) { - context.report(node, node.consequent.loc.start, "Unnecessary use of boolean literals in conditional expression"); + context.report(node, node.consequent.loc.start, "Unnecessary use of boolean literals in conditional expression."); } else if (!defaultAssignment && matchesDefaultAssignment(node)) { - context.report(node, node.consequent.loc.start, "Unnecessary use of conditional expression for default assignment"); + context.report(node, node.consequent.loc.start, "Unnecessary use of conditional expression for default assignment."); } } }; diff --git a/tools/eslint/lib/rules/no-unreachable.js b/tools/eslint/lib/rules/no-unreachable.js index c28a6d2f2fa..d52b9f3517b 100644 --- a/tools/eslint/lib/rules/no-unreachable.js +++ b/tools/eslint/lib/rules/no-unreachable.js @@ -26,6 +26,75 @@ function isUnreachable(segment) { return !segment.reachable; } +/** + * The class to distinguish consecutive unreachable statements. + */ +class ConsecutiveRange { + constructor(sourceCode) { + this.sourceCode = sourceCode; + this.startNode = null; + this.endNode = null; + } + + /** + * The location object of this range. + * @type {Object} + */ + get location() { + return { + start: this.startNode.loc.start, + end: this.endNode.loc.end + }; + } + + /** + * `true` if this range is empty. + * @type {boolean} + */ + get isEmpty() { + return !(this.startNode && this.endNode); + } + + /** + * Checks whether the given node is inside of this range. + * @param {ASTNode|Token} node - The node to check. + * @returns {boolean} `true` if the node is inside of this range. + */ + contains(node) { + return ( + node.range[0] >= this.startNode.range[0] && + node.range[1] <= this.endNode.range[1] + ); + } + + /** + * Checks whether the given node is consecutive to this range. + * @param {ASTNode} node - The node to check. + * @returns {boolean} `true` if the node is consecutive to this range. + */ + isConsecutive(node) { + return this.contains(this.sourceCode.getTokenBefore(node)); + } + + /** + * Merges the given node to this range. + * @param {ASTNode} node - The node to merge. + * @returns {void} + */ + merge(node) { + this.endNode = node; + } + + /** + * Resets this range by the given node or null. + * @param {ASTNode|null} node - The node to reset, or null. + * @returns {void} + */ + reset(node) { + this.startNode = this.endNode = node; + } +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -42,7 +111,9 @@ module.exports = { }, create: function(context) { - var currentCodePath = null; + let currentCodePath = null; + + const range = new ConsecutiveRange(context.getSourceCode()); /** * Reports a given node if it's unreachable. @@ -50,9 +121,42 @@ module.exports = { * @returns {void} */ function reportIfUnreachable(node) { - if (currentCodePath.currentSegments.every(isUnreachable)) { - context.report({message: "Unreachable code.", node: node}); + let nextNode = null; + + if (node && currentCodePath.currentSegments.every(isUnreachable)) { + + // Store this statement to distinguish consecutive statements. + if (range.isEmpty) { + range.reset(node); + return; + } + + // Skip if this statement is inside of the current range. + if (range.contains(node)) { + return; + } + + // Merge if this statement is consecutive to the current range. + if (range.isConsecutive(node)) { + range.merge(node); + return; + } + + nextNode = node; + } + + // Report the current range since this statement is reachable or is + // not consecutive to the current range. + if (!range.isEmpty) { + context.report({ + message: "Unreachable code.", + loc: range.location, + node: range.startNode + }); } + + // Update the current range. + range.reset(nextNode); } return { @@ -96,7 +200,11 @@ module.exports = { WithStatement: reportIfUnreachable, ExportNamedDeclaration: reportIfUnreachable, ExportDefaultDeclaration: reportIfUnreachable, - ExportAllDeclaration: reportIfUnreachable + ExportAllDeclaration: reportIfUnreachable, + + "Program:exit": function() { + reportIfUnreachable(); + } }; } }; diff --git a/tools/eslint/lib/rules/no-unsafe-finally.js b/tools/eslint/lib/rules/no-unsafe-finally.js index 8c3815459c1..305cce28ad1 100644 --- a/tools/eslint/lib/rules/no-unsafe-finally.js +++ b/tools/eslint/lib/rules/no-unsafe-finally.js @@ -9,9 +9,9 @@ // Helpers //------------------------------------------------------------------------------ -var SENTINEL_NODE_TYPE_RETURN_THROW = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression)$/; -var SENTINEL_NODE_TYPE_BREAK = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement|SwitchStatement)$/; -var SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement)$/; +let SENTINEL_NODE_TYPE_RETURN_THROW = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression)$/; +let SENTINEL_NODE_TYPE_BREAK = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement|SwitchStatement)$/; +let SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement)$/; //------------------------------------------------------------------------------ @@ -24,7 +24,9 @@ module.exports = { description: "disallow control flow statements in `finally` blocks", category: "Possible Errors", recommended: true - } + }, + + schema: [] }, create: function(context) { @@ -32,7 +34,7 @@ module.exports = { * Checks if the node is the finalizer of a TryStatement * * @param {ASTNode} node - node to check. - * @returns {Boolean} - true if the node is the finalizer of a TryStatement + * @returns {boolean} - true if the node is the finalizer of a TryStatement */ function isFinallyBlock(node) { return node.parent.type === "TryStatement" && node.parent.finalizer === node; @@ -42,12 +44,12 @@ module.exports = { * Climbs up the tree if the node is not a sentinel node * * @param {ASTNode} node - node to check. - * @param {String} label - label of the break or continue statement - * @returns {Boolean} - return whether the node is a finally block or a sentinel node + * @param {string} label - label of the break or continue statement + * @returns {boolean} - return whether the node is a finally block or a sentinel node */ function isInFinallyBlock(node, label) { - var labelInside = false; - var sentinelNodeType; + let labelInside = false; + let sentinelNodeType; if (node.type === "BreakStatement" && !node.label) { sentinelNodeType = SENTINEL_NODE_TYPE_BREAK; @@ -81,7 +83,7 @@ module.exports = { function check(node) { if (isInFinallyBlock(node, node.label)) { context.report({ - message: "Unsafe usage of " + node.type, + message: "Unsafe usage of " + node.type + ".", node: node, line: node.loc.line, column: node.loc.column diff --git a/tools/eslint/lib/rules/no-unused-expressions.js b/tools/eslint/lib/rules/no-unused-expressions.js index 9438268ab24..d2bdda70f21 100644 --- a/tools/eslint/lib/rules/no-unused-expressions.js +++ b/tools/eslint/lib/rules/no-unused-expressions.js @@ -33,7 +33,7 @@ module.exports = { }, create: function(context) { - var config = context.options[0] || {}, + let config = context.options[0] || {}, allowShortCircuit = config.allowShortCircuit || false, allowTernary = config.allowTernary || false; @@ -52,12 +52,12 @@ module.exports = { * @returns {a[]} the leading sequence of members in the given list that pass the given predicate */ function takeWhile(predicate, list) { - for (var i = 0, l = list.length; i < l; ++i) { + for (let i = 0; i < list.length; ++i) { if (!predicate(list[i])) { - break; + return list.slice(0, i); } } - return [].slice.call(list, 0, i); + return list.slice(); } /** @@ -74,7 +74,7 @@ module.exports = { * @returns {boolean} whether the given node is considered a directive in its current position */ function isDirective(node, ancestors) { - var parent = ancestors[ancestors.length - 1], + let parent = ancestors[ancestors.length - 1], grandparent = ancestors[ancestors.length - 2]; return (parent.type === "Program" || parent.type === "BlockStatement" && diff --git a/tools/eslint/lib/rules/no-unused-labels.js b/tools/eslint/lib/rules/no-unused-labels.js index 77713fc408b..ec13c6168e7 100644 --- a/tools/eslint/lib/rules/no-unused-labels.js +++ b/tools/eslint/lib/rules/no-unused-labels.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var scopeInfo = null; + let scopeInfo = null; /** * Adds a scope info to the stack. @@ -68,8 +68,8 @@ module.exports = { return; } - var label = node.label.name; - var info = scopeInfo; + let label = node.label.name; + let info = scopeInfo; while (info) { if (info.label === label) { diff --git a/tools/eslint/lib/rules/no-unused-vars.js b/tools/eslint/lib/rules/no-unused-vars.js index 39b7703c3c1..951330de9bb 100644 --- a/tools/eslint/lib/rules/no-unused-vars.js +++ b/tools/eslint/lib/rules/no-unused-vars.js @@ -9,8 +9,8 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); -var astUtils = require("../ast-utils"); +let lodash = require("lodash"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -60,15 +60,15 @@ module.exports = { create: function(context) { - var MESSAGE = "'{{name}}' is defined but never used"; + let MESSAGE = "'{{name}}' is defined but never used."; - var config = { + let config = { vars: "all", args: "after-used", caughtErrors: "none" }; - var firstOption = context.options[0]; + let firstOption = context.options[0]; if (firstOption) { if (typeof firstOption === "string") { @@ -96,7 +96,7 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var STATEMENT_TYPE = /(?:Statement|Declaration)$/; + let STATEMENT_TYPE = /(?:Statement|Declaration)$/; /** * Determines if a given variable is being exported from a module. @@ -106,11 +106,11 @@ module.exports = { */ function isExported(variable) { - var definition = variable.defs[0]; + let definition = variable.defs[0]; if (definition) { - var node = definition.node; + let node = definition.node; if (node.type === "VariableDeclarator") { node = node.parent; @@ -142,7 +142,7 @@ module.exports = { * @private */ function isSelfReference(ref, nodes) { - var scope = ref.from; + let scope = ref.from; while (scope) { if (nodes.indexOf(scope.block) >= 0) { @@ -155,12 +155,35 @@ module.exports = { return false; } + /** + * Checks whether a given node is inside of a loop or not. + * + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is inside of a loop. + * @private + */ + function isInsideOfLoop(node) { + while (node) { + if (astUtils.isLoop(node)) { + return true; + } + if (astUtils.isFunction(node)) { + return false; + } + + node = node.parent; + } + + return false; + } + /** * Checks the position of given nodes. * * @param {ASTNode} inner - A node which is expected as inside. * @param {ASTNode} outer - A node which is expected as outside. * @returns {boolean} `true` if the `inner` node exists in the `outer` node. + * @private */ function isInside(inner, outer) { return ( @@ -173,17 +196,25 @@ module.exports = { * If a given reference is left-hand side of an assignment, this gets * the right-hand side node of the assignment. * + * In the following cases, this returns null. + * + * - The reference is not the LHS of an assignment expression. + * - The reference is inside of a loop. + * - The reference is inside of a function scope which is different from + * the declaration. + * * @param {escope.Reference} ref - A reference to check. * @param {ASTNode} prevRhsNode - The previous RHS node. - * @returns {ASTNode} The RHS node. + * @returns {ASTNode|null} The RHS node or null. + * @private */ function getRhsNode(ref, prevRhsNode) { - var id = ref.identifier; - var parent = id.parent; - var granpa = parent.parent; - var refScope = ref.from.variableScope; - var varScope = ref.resolved.scope.variableScope; - var canBeUsedLater = refScope !== varScope; + let id = ref.identifier; + let parent = id.parent; + let granpa = parent.parent; + let refScope = ref.from.variableScope; + let varScope = ref.resolved.scope.variableScope; + let canBeUsedLater = refScope !== varScope || isInsideOfLoop(id); /* * Inherits the previous node if this reference is in the node. @@ -213,10 +244,11 @@ module.exports = { * - the funcNode is assigned to a variable. * - the funcNode is bound as an argument of a function call. * - the function is bound to a property and the object satisfies above conditions. + * @private */ function isStorableFunction(funcNode, rhsNode) { - var node = funcNode; - var parent = funcNode.parent; + let node = funcNode; + let parent = funcNode.parent; while (parent && isInside(parent, rhsNode)) { switch (parent.type) { @@ -266,9 +298,10 @@ module.exports = { * @param {ASTNode} id - An Identifier node to check. * @param {ASTNode} rhsNode - The RHS node of the previous assignment. * @returns {boolean} `true` if the `id` node exists inside of a function node which can be used later. + * @private */ function isInsideOfStorableFunction(id, rhsNode) { - var funcNode = astUtils.getUpperFunction(id); + let funcNode = astUtils.getUpperFunction(id); return ( funcNode && @@ -283,11 +316,12 @@ module.exports = { * @param {escope.Reference} ref - A reference to check. * @param {ASTNode} rhsNode - The RHS node of the previous assignment. * @returns {boolean} The reference is a read to update itself. + * @private */ function isReadForItself(ref, rhsNode) { - var id = ref.identifier; - var parent = id.parent; - var granpa = parent.parent; + let id = ref.identifier; + let parent = id.parent; + let granpa = parent.parent; return ref.isRead() && ( @@ -319,7 +353,7 @@ module.exports = { * @private */ function isForInRef(ref) { - var target = ref.identifier.parent; + let target = ref.identifier.parent; // "for (var ...) { return; }" @@ -355,7 +389,7 @@ module.exports = { * @private */ function isUsedVariable(variable) { - var functionNodes = variable.defs.filter(function(def) { + let functionNodes = variable.defs.filter(function(def) { return def.type === "FunctionName"; }).map(function(def) { return def.node; @@ -368,7 +402,7 @@ module.exports = { return true; } - var forItself = isReadForItself(ref, rhsNode); + let forItself = isReadForItself(ref, rhsNode); rhsNode = getRhsNode(ref, rhsNode); @@ -388,13 +422,13 @@ module.exports = { * @private */ function collectUnusedVariables(scope, unusedVars) { - var variables = scope.variables; - var childScopes = scope.childScopes; - var i, l; + let variables = scope.variables; + let childScopes = scope.childScopes; + let i, l; if (scope.type !== "TDZ" && (scope.type !== "global" || config.vars === "all")) { for (i = 0, l = variables.length; i < l; ++i) { - var variable = variables[i]; + let variable = variables[i]; // skip a variable of class itself name in the class scope if (scope.type === "class" && scope.block.id === variable.identifiers[0]) { @@ -412,10 +446,10 @@ module.exports = { } // explicit global variables don't have definitions. - var def = variable.defs[0]; + let def = variable.defs[0]; if (def) { - var type = def.type; + let type = def.type; // skip catch variables if (type === "CatchClause") { @@ -480,13 +514,13 @@ module.exports = { * @private */ function getColumnInComment(variable, comment) { - var namePattern = new RegExp("[\\s,]" + lodash.escapeRegExp(variable.name) + "(?:$|[\\s,:])", "g"); + let namePattern = new RegExp("[\\s,]" + lodash.escapeRegExp(variable.name) + "(?:$|[\\s,:])", "g"); // To ignore the first text "global". namePattern.lastIndex = comment.value.indexOf("global") + 6; // Search a given variable name. - var match = namePattern.exec(comment.value); + let match = namePattern.exec(comment.value); return match ? match.index + 1 : 0; } @@ -500,11 +534,11 @@ module.exports = { * @private */ function getLocation(variable) { - var comment = variable.eslintExplicitGlobalComment; - var baseLoc = comment.loc.start; - var column = getColumnInComment(variable, comment); - var prefix = comment.value.slice(0, column); - var lineInComment = (prefix.match(/\n/g) || []).length; + let comment = variable.eslintExplicitGlobalComment; + let baseLoc = comment.loc.start; + let column = getColumnInComment(variable, comment); + let prefix = comment.value.slice(0, column); + let lineInComment = (prefix.match(/\n/g) || []).length; if (lineInComment > 0) { column -= 1 + prefix.lastIndexOf("\n"); @@ -526,10 +560,10 @@ module.exports = { return { "Program:exit": function(programNode) { - var unusedVars = collectUnusedVariables(context.getScope(), []); + let unusedVars = collectUnusedVariables(context.getScope(), []); - for (var i = 0, l = unusedVars.length; i < l; ++i) { - var unusedVar = unusedVars[i]; + for (let i = 0, l = unusedVars.length; i < l; ++i) { + let unusedVar = unusedVars[i]; if (unusedVar.eslintExplicitGlobal) { context.report({ diff --git a/tools/eslint/lib/rules/no-use-before-define.js b/tools/eslint/lib/rules/no-use-before-define.js index 889e7099482..90dd05c8b1b 100644 --- a/tools/eslint/lib/rules/no-use-before-define.js +++ b/tools/eslint/lib/rules/no-use-before-define.js @@ -9,17 +9,18 @@ // Helpers //------------------------------------------------------------------------------ -var SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/; +let SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/; +let FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/; /** * Parses a given value as options. * * @param {any} options - A value to parse. - * @returns {object} The parsed options. + * @returns {Object} The parsed options. */ function parseOptions(options) { - var functions = true; - var classes = true; + let functions = true; + let classes = true; if (typeof options === "string") { functions = (options !== "nofunc"); @@ -87,6 +88,14 @@ function isInRange(node, location) { /** * Checks whether or not a given reference is inside of the initializers of a given variable. * + * This returns `true` in the following cases: + * + * var a = a + * var [a = a] = list + * var {a = a} = obj + * for (var a in a) {} + * for (var a of a) {} + * * @param {Variable} variable - A variable to check. * @param {Reference} reference - A reference to check. * @returns {boolean} `true` if the reference is inside of the initializers. @@ -96,14 +105,19 @@ function isInInitializer(variable, reference) { return false; } - var node = variable.identifiers[0].parent; - var location = reference.identifier.range[1]; + let node = variable.identifiers[0].parent; + let location = reference.identifier.range[1]; while (node) { if (node.type === "VariableDeclarator") { if (isInRange(node.init, location)) { return true; } + if (FOR_IN_OF_TYPE.test(node.parent.parent.type) && + isInRange(node.parent.parent.right, location) + ) { + return true; + } break; } else if (node.type === "AssignmentPattern") { if (isInRange(node.right, location)) { @@ -151,10 +165,10 @@ module.exports = { }, create: function(context) { - var options = parseOptions(context.options[0]); + let options = parseOptions(context.options[0]); // Defines a function which checks whether or not a reference is allowed according to the option. - var isAllowed; + let isAllowed; if (options.functions && options.classes) { isAllowed = alwaysFalse; @@ -174,7 +188,7 @@ module.exports = { */ function findVariablesInScope(scope) { scope.references.forEach(function(reference) { - var variable = reference.resolved; + let variable = reference.resolved; // Skips when the reference is: // - initialization's. @@ -194,7 +208,7 @@ module.exports = { // Reports. context.report({ node: reference.identifier, - message: "'{{name}}' was used before it was defined", + message: "'{{name}}' was used before it was defined.", data: reference.identifier }); }); @@ -207,14 +221,14 @@ module.exports = { * @private */ function findVariables() { - var scope = context.getScope(); + let scope = context.getScope(); findVariablesInScope(scope); } - var ruleDefinition = { + let ruleDefinition = { "Program:exit": function(node) { - var scope = context.getScope(), + let scope = context.getScope(), ecmaFeatures = context.parserOptions.ecmaFeatures || {}; findVariablesInScope(scope); diff --git a/tools/eslint/lib/rules/no-useless-call.js b/tools/eslint/lib/rules/no-useless-call.js index 49cbbc5401c..b05292ff79e 100644 --- a/tools/eslint/lib/rules/no-useless-call.js +++ b/tools/eslint/lib/rules/no-useless-call.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -36,13 +36,13 @@ function isCallOrNonVariadicApply(node) { * @returns {boolean} the source code for the given node. */ function equalTokens(left, right, sourceCode) { - var tokensL = sourceCode.getTokens(left); - var tokensR = sourceCode.getTokens(right); + let tokensL = sourceCode.getTokens(left); + let tokensR = sourceCode.getTokens(right); if (tokensL.length !== tokensR.length) { return false; } - for (var i = 0; i < tokensL.length; ++i) { + for (let i = 0; i < tokensL.length; ++i) { if (tokensL[i].type !== tokensR[i].type || tokensL[i].value !== tokensR[i].value ) { @@ -83,7 +83,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { CallExpression: function(node) { @@ -91,9 +91,9 @@ module.exports = { return; } - var applied = node.callee.object; - var expectedThis = (applied.type === "MemberExpression") ? applied.object : null; - var thisArg = node.arguments[0]; + let applied = node.callee.object; + let expectedThis = (applied.type === "MemberExpression") ? applied.object : null; + let thisArg = node.arguments[0]; if (isValidThisArg(expectedThis, thisArg, sourceCode)) { context.report( diff --git a/tools/eslint/lib/rules/no-useless-computed-key.js b/tools/eslint/lib/rules/no-useless-computed-key.js index 2e0ac18019a..f25b9e54743 100644 --- a/tools/eslint/lib/rules/no-useless-computed-key.js +++ b/tools/eslint/lib/rules/no-useless-computed-key.js @@ -8,7 +8,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{property}}] found."; +let MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{property}}] found."; module.exports = { meta: { @@ -16,10 +16,12 @@ module.exports = { description: "disallow unnecessary computed property keys in object literals", category: "ECMAScript 6", recommended: false - } + }, + + schema: [] }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Property: function(node) { @@ -27,7 +29,7 @@ module.exports = { return; } - var key = node.key, + let key = node.key, nodeType = typeof key.value; if (key.type === "Literal" && (nodeType === "string" || nodeType === "number")) { diff --git a/tools/eslint/lib/rules/no-useless-concat.js b/tools/eslint/lib/rules/no-useless-concat.js index 8569d4276a4..6c4cecd7b67 100644 --- a/tools/eslint/lib/rules/no-useless-concat.js +++ b/tools/eslint/lib/rules/no-useless-concat.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -29,7 +29,7 @@ function isConcatenation(node) { * @returns {ASTNode} node */ function getLeft(node) { - var left = node.left; + let left = node.left; while (isConcatenation(left)) { left = left.right; @@ -43,7 +43,7 @@ function getLeft(node) { * @returns {ASTNode} node */ function getRight(node) { - var right = node.right; + let right = node.right; while (isConcatenation(right)) { right = right.left; @@ -67,7 +67,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { BinaryExpression: function(node) { @@ -78,8 +78,8 @@ module.exports = { } // account for the `foo + "a" + "b"` case - var left = getLeft(node); - var right = getRight(node); + let left = getLeft(node); + let right = getRight(node); if (astUtils.isStringLiteral(left) && astUtils.isStringLiteral(right) && @@ -87,7 +87,7 @@ module.exports = { ) { // move warning location to operator - var operatorToken = sourceCode.getTokenAfter(left); + let operatorToken = sourceCode.getTokenAfter(left); while (operatorToken.value !== "+") { operatorToken = sourceCode.getTokenAfter(operatorToken); diff --git a/tools/eslint/lib/rules/no-useless-constructor.js b/tools/eslint/lib/rules/no-useless-constructor.js index b91ab4bcae5..f6be08f69da 100644 --- a/tools/eslint/lib/rules/no-useless-constructor.js +++ b/tools/eslint/lib/rules/no-useless-constructor.js @@ -109,7 +109,7 @@ function isPassingThrough(ctorParams, superArgs) { return false; } - for (var i = 0; i < ctorParams.length; ++i) { + for (let i = 0; i < ctorParams.length; ++i) { if (!isValidPair(ctorParams[i], superArgs[i])) { return false; } @@ -163,9 +163,9 @@ module.exports = { return; } - var body = node.value.body.body; - var ctorParams = node.value.params; - var superClass = node.parent.parent.superClass; + let body = node.value.body.body; + let ctorParams = node.value.params; + let superClass = node.parent.parent.superClass; if (superClass ? isRedundantSuperCall(body, ctorParams) : (body.length === 0)) { context.report({ diff --git a/tools/eslint/lib/rules/no-useless-escape.js b/tools/eslint/lib/rules/no-useless-escape.js index 036831fc394..226a9da1659 100644 --- a/tools/eslint/lib/rules/no-useless-escape.js +++ b/tools/eslint/lib/rules/no-useless-escape.js @@ -9,7 +9,7 @@ // Rule Definition //------------------------------------------------------------------------------ -var VALID_STRING_ESCAPES = [ +let VALID_STRING_ESCAPES = [ "\\", "n", "r", @@ -23,7 +23,7 @@ var VALID_STRING_ESCAPES = [ "\r" ]; -var VALID_REGEX_ESCAPES = [ +let VALID_REGEX_ESCAPES = [ "\\", ".", "-", @@ -80,8 +80,8 @@ module.exports = { * @returns {void} */ function validate(escapes, node, elm) { - var escapeNotFound = escapes.indexOf(elm[0][1]) === -1; - var isQuoteEscape = elm[0][1] === node.raw[0]; + let escapeNotFound = escapes.indexOf(elm[0][1]) === -1; + let isQuoteEscape = elm[0][1] === node.raw[0]; if (escapeNotFound && !isQuoteEscape) { context.report({ @@ -90,7 +90,7 @@ module.exports = { line: node.loc.start.line, column: node.loc.start.column + elm.index }, - message: "Unnecessary escape character: " + elm[0] + message: "Unnecessary escape character: " + elm[0] + "." }); } } @@ -102,8 +102,8 @@ module.exports = { * @returns {void} */ function check(node) { - var nodeEscapes, match; - var pattern = /\\[^\d]/g; + let nodeEscapes, match; + let pattern = /\\[^\d]/g; if (typeof node.value === "string") { diff --git a/tools/eslint/lib/rules/no-useless-rename.js b/tools/eslint/lib/rules/no-useless-rename.js index ec2282784b5..80539e57723 100644 --- a/tools/eslint/lib/rules/no-useless-rename.js +++ b/tools/eslint/lib/rules/no-useless-rename.js @@ -31,7 +31,7 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, ignoreDestructuring = options.ignoreDestructuring === true, ignoreImport = options.ignoreImport === true, ignoreExport = options.ignoreExport === true; @@ -49,7 +49,7 @@ module.exports = { * @returns {void} */ function reportError(node, initial, result, type) { - var name = initial.type === "Identifier" ? initial.name : initial.value; + let name = initial.type === "Identifier" ? initial.name : initial.value; return context.report({ node: node, @@ -73,7 +73,7 @@ module.exports = { * @returns {void} */ function checkDestructured(node) { - var properties, + let properties, i; if (ignoreDestructuring) { diff --git a/tools/eslint/lib/rules/no-var.js b/tools/eslint/lib/rules/no-var.js index 2e9948a330e..fc7783d7160 100644 --- a/tools/eslint/lib/rules/no-var.js +++ b/tools/eslint/lib/rules/no-var.js @@ -5,6 +5,72 @@ "use strict"; +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +let SCOPE_NODE_TYPE = /^(?:Program|BlockStatement|SwitchStatement|ForStatement|ForInStatement|ForOfStatement)$/; + +/** + * Gets the scope node which directly contains a given node. + * + * @param {ASTNode} node - A node to get. This is a `VariableDeclaration` or + * an `Identifier`. + * @returns {ASTNode} A scope node. This is one of `Program`, `BlockStatement`, + * `SwitchStatement`, `ForStatement`, `ForInStatement`, and + * `ForOfStatement`. + */ +function getScopeNode(node) { + while (node) { + if (SCOPE_NODE_TYPE.test(node.type)) { + return node; + } + + node = node.parent; + } + + /* istanbul ignore next : unreachable */ + return null; +} + +/** + * Checks whether a given variable is redeclared or not. + * + * @param {escope.Variable} variable - A variable to check. + * @returns {boolean} `true` if the variable is redeclared. + */ +function isRedeclared(variable) { + return variable.defs.length >= 2; +} + +/** + * Checks whether a given variable is used from outside of the specified scope. + * + * @param {ASTNode} scopeNode - A scope node to check. + * @returns {Function} The predicate function which checks whether a given + * variable is used from outside of the specified scope. + */ +function isUsedFromOutsideOf(scopeNode) { + + /** + * Checks whether a given reference is inside of the specified scope or not. + * + * @param {escope.Reference} reference - A reference to check. + * @returns {boolean} `true` if the reference is inside of the specified + * scope. + */ + function isOutsideOfScope(reference) { + let scope = scopeNode.range; + let id = reference.identifier.range; + + return id[0] < scope[0] || id[1] > scope[1]; + } + + return function(variable) { + return variable.references.some(isOutsideOfScope); + }; +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -17,19 +83,80 @@ module.exports = { recommended: false }, - schema: [] + schema: [], + fixable: "code" }, create: function(context) { + let sourceCode = context.getSourceCode(); + + /** + * Checks whether it can fix a given variable declaration or not. + * It cannot fix if the following cases: + * + * - A variable is declared on a SwitchCase node. + * - A variable is redeclared. + * - A variable is used from outside the scope. + * + * ## A variable is declared on a SwitchCase node. + * + * If this rule modifies 'var' declarations on a SwitchCase node, it + * would generate the warnings of 'no-case-declarations' rule. And the + * 'eslint:recommended' preset includes 'no-case-declarations' rule, so + * this rule doesn't modify those declarations. + * + * ## A variable is redeclared. + * + * The language spec disallows redeclarations of `let` declarations. + * Those variables would cause syntax errors. + * + * ## A variable is used from outside the scope. + * + * The language spec disallows accesses from outside of the scope for + * `let` declarations. Those variables would cause reference errors. + * + * @param {ASTNode} node - A variable declaration node to check. + * @returns {boolean} `true` if it can fix the node. + */ + function canFix(node) { + let variables = context.getDeclaredVariables(node); + let scopeNode = getScopeNode(node); + + return !( + node.parent.type === "SwitchCase" || + variables.some(isRedeclared) || + variables.some(isUsedFromOutsideOf(scopeNode)) + ); + } + + /** + * Reports a given variable declaration node. + * + * @param {ASTNode} node - A variable declaration node to report. + * @returns {void} + */ + function report(node) { + let varToken = sourceCode.getFirstToken(node); + + context.report({ + node: node, + message: "Unexpected var, use let or const instead.", + + fix: function(fixer) { + if (canFix(node)) { + return fixer.replaceText(varToken, "let"); + } + return null; + } + }); + } return { VariableDeclaration: function(node) { if (node.kind === "var") { - context.report(node, "Unexpected var, use let or const instead."); + report(node); } } - }; - } }; diff --git a/tools/eslint/lib/rules/no-warning-comments.js b/tools/eslint/lib/rules/no-warning-comments.js index dadf231f5c3..7db6ed1234b 100644 --- a/tools/eslint/lib/rules/no-warning-comments.js +++ b/tools/eslint/lib/rules/no-warning-comments.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -40,7 +40,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0] || {}, + let configuration = context.options[0] || {}, warningTerms = configuration.terms || ["todo", "fixme", "xxx"], location = configuration.location || "start", selfConfigRegEx = /\bno-warning-comments\b/, @@ -51,11 +51,11 @@ module.exports = { * location ("start" or "anywhere"). If the term starts or ends with non word characters, then the match will not * require word boundaries on that side. * - * @param {String} term A term to convert to a RegExp + * @param {string} term A term to convert to a RegExp * @returns {RegExp} The term converted to a RegExp */ function convertToRegExp(term) { - var escaped = term.replace(/[-\/\\$\^*+?.()|\[\]{}]/g, "\\$&"), + let escaped = term.replace(/[-\/\\$\^*+?.()|\[\]{}]/g, "\\$&"), suffix, prefix; @@ -89,11 +89,11 @@ module.exports = { /** * Checks the specified comment for matches of the configured warning terms and returns the matches. - * @param {String} comment The comment which is checked. + * @param {string} comment The comment which is checked. * @returns {Array} All matched warning terms for this comment. */ function commentContainsWarningTerm(comment) { - var matches = []; + let matches = []; warningRegExps.forEach(function(regex, index) { if (regex.test(comment)) { @@ -114,7 +114,7 @@ module.exports = { return; } - var matches = commentContainsWarningTerm(node.value); + let matches = commentContainsWarningTerm(node.value); matches.forEach(function(matchedTerm) { context.report(node, "Unexpected '" + matchedTerm + "' comment."); diff --git a/tools/eslint/lib/rules/no-whitespace-before-property.js b/tools/eslint/lib/rules/no-whitespace-before-property.js index 347c63d934f..fd13ba9d5d5 100644 --- a/tools/eslint/lib/rules/no-whitespace-before-property.js +++ b/tools/eslint/lib/rules/no-whitespace-before-property.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -23,7 +23,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -36,7 +36,7 @@ module.exports = { * @private */ function findOpeningBracket(node) { - var token = sourceCode.getTokenBefore(node.property); + let token = sourceCode.getTokenBefore(node.property); while (token.value !== "[") { token = sourceCode.getTokenBefore(token); @@ -53,7 +53,7 @@ module.exports = { * @private */ function reportError(node, leftToken, rightToken) { - var replacementText = node.computed ? "" : "."; + let replacementText = node.computed ? "" : "."; context.report({ node: node, @@ -73,8 +73,8 @@ module.exports = { return { MemberExpression: function(node) { - var rightToken; - var leftToken; + let rightToken; + let leftToken; if (!astUtils.isTokenOnSameLine(node.object, node.property)) { return; diff --git a/tools/eslint/lib/rules/object-curly-newline.js b/tools/eslint/lib/rules/object-curly-newline.js index aaa4af02a28..b69bd190447 100644 --- a/tools/eslint/lib/rules/object-curly-newline.js +++ b/tools/eslint/lib/rules/object-curly-newline.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ // Schema objects. -var OPTION_VALUE = { +let OPTION_VALUE = { oneOf: [ { enum: ["always", "never"] @@ -41,12 +41,12 @@ var OPTION_VALUE = { /** * Normalizes a given option value. * - * @param {string|object|undefined} value - An option value to parse. + * @param {string|Object|undefined} value - An option value to parse. * @returns {{multiline: boolean, minProperties: number}} Normalized option object. */ function normalizeOptionValue(value) { - var multiline = false; - var minProperties = Number.POSITIVE_INFINITY; + let multiline = false; + let minProperties = Number.POSITIVE_INFINITY; if (value) { if (value === "always") { @@ -67,7 +67,7 @@ function normalizeOptionValue(value) { /** * Normalizes a given option value. * - * @param {string|object|undefined} options - An option value to parse. + * @param {string|Object|undefined} options - An option value to parse. * @returns {{ObjectExpression: {multiline: boolean, minProperties: number}, ObjectPattern: {multiline: boolean, minProperties: number}}} Normalized option object. */ function normalizeOptions(options) { @@ -78,7 +78,7 @@ function normalizeOptions(options) { }; } - var value = normalizeOptionValue(options); + let value = normalizeOptionValue(options); return {ObjectExpression: value, ObjectPattern: value}; } @@ -114,8 +114,8 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var normalizedOptions = normalizeOptions(context.options[0]); + let sourceCode = context.getSourceCode(); + let normalizedOptions = normalizeOptions(context.options[0]); /** * Reports a given node if it violated this rule. @@ -125,12 +125,12 @@ module.exports = { * @returns {void} */ function check(node) { - var options = normalizedOptions[node.type]; - var openBrace = sourceCode.getFirstToken(node); - var closeBrace = sourceCode.getLastToken(node); - var first = sourceCode.getTokenOrCommentAfter(openBrace); - var last = sourceCode.getTokenOrCommentBefore(closeBrace); - var needsLinebreaks = ( + let options = normalizedOptions[node.type]; + let openBrace = sourceCode.getFirstToken(node); + let closeBrace = sourceCode.getLastToken(node); + let first = sourceCode.getTokenOrCommentAfter(openBrace); + let last = sourceCode.getTokenOrCommentBefore(closeBrace); + let needsLinebreaks = ( node.properties.length >= options.minProperties || ( options.multiline && @@ -153,7 +153,7 @@ module.exports = { if (needsLinebreaks) { if (astUtils.isTokenOnSameLine(openBrace, first)) { context.report({ - message: "Expected a line break after this open brace.", + message: "Expected a line break after this opening brace.", node: node, loc: openBrace.loc.start, fix: function(fixer) { @@ -163,7 +163,7 @@ module.exports = { } if (astUtils.isTokenOnSameLine(last, closeBrace)) { context.report({ - message: "Expected a line break before this close brace.", + message: "Expected a line break before this closing brace.", node: node, loc: closeBrace.loc.start, fix: function(fixer) { @@ -174,7 +174,7 @@ module.exports = { } else { if (!astUtils.isTokenOnSameLine(openBrace, first)) { context.report({ - message: "Unexpected a line break after this open brace.", + message: "Unexpected line break after this opening brace.", node: node, loc: openBrace.loc.start, fix: function(fixer) { @@ -187,7 +187,7 @@ module.exports = { } if (!astUtils.isTokenOnSameLine(last, closeBrace)) { context.report({ - message: "Unexpected a line break before this close brace.", + message: "Unexpected line break before this closing brace.", node: node, loc: closeBrace.loc.start, fix: function(fixer) { diff --git a/tools/eslint/lib/rules/object-curly-spacing.js b/tools/eslint/lib/rules/object-curly-spacing.js index e5dfb8d036c..4fe1f85758b 100644 --- a/tools/eslint/lib/rules/object-curly-spacing.js +++ b/tools/eslint/lib/rules/object-curly-spacing.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -40,7 +40,7 @@ module.exports = { }, create: function(context) { - var spaced = context.options[0] === "always", + let spaced = context.options[0] === "always", sourceCode = context.getSourceCode(); /** @@ -54,7 +54,7 @@ module.exports = { return context.options[1] ? context.options[1][option] === !spaced : false; } - var options = { + let options = { spaced: spaced, arraysInObjectsException: isOptionSet("arraysInObjects"), objectsInObjectsException: isOptionSet("objectsInObjects") @@ -74,9 +74,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space after '" + token.value + "'", + message: "There should be no space after '" + token.value + "'.", fix: function(fixer) { - var nextToken = context.getSourceCode().getTokenAfter(token); + let nextToken = context.getSourceCode().getTokenAfter(token); return fixer.removeRange([token.range[1], nextToken.range[0]]); } @@ -93,9 +93,9 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "There should be no space before '" + token.value + "'", + message: "There should be no space before '" + token.value + "'.", fix: function(fixer) { - var previousToken = context.getSourceCode().getTokenBefore(token); + let previousToken = context.getSourceCode().getTokenBefore(token); return fixer.removeRange([previousToken.range[1], token.range[0]]); } @@ -112,7 +112,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required after '" + token.value + "'", + message: "A space is required after '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextAfter(token, " "); } @@ -129,7 +129,7 @@ module.exports = { context.report({ node: node, loc: token.loc.start, - message: "A space is required before '" + token.value + "'", + message: "A space is required before '" + token.value + "'.", fix: function(fixer) { return fixer.insertTextBefore(token, " "); } @@ -146,7 +146,7 @@ module.exports = { * @returns {void} */ function validateBraceSpacing(node, first, second, penultimate, last) { - var shouldCheckPenultimate, + let shouldCheckPenultimate, penultimateType, closingCurlyBraceMustBeSpaced, firstSpaced, @@ -195,7 +195,7 @@ module.exports = { return; } - var first = sourceCode.getFirstToken(node), + let first = sourceCode.getFirstToken(node), last = sourceCode.getLastToken(node), second = sourceCode.getTokenAfter(first), penultimate = sourceCode.getTokenBefore(last); @@ -213,7 +213,7 @@ module.exports = { return; } - var firstSpecifier = node.specifiers[0], + let firstSpecifier = node.specifiers[0], lastSpecifier = node.specifiers[node.specifiers.length - 1]; if (lastSpecifier.type !== "ImportSpecifier") { @@ -223,7 +223,7 @@ module.exports = { firstSpecifier = node.specifiers[1]; } - var first = sourceCode.getTokenBefore(firstSpecifier), + let first = sourceCode.getTokenBefore(firstSpecifier), last = sourceCode.getTokenAfter(lastSpecifier); // to support a trailing comma. @@ -231,7 +231,7 @@ module.exports = { last = sourceCode.getTokenAfter(last); } - var second = sourceCode.getTokenAfter(first), + let second = sourceCode.getTokenAfter(first), penultimate = sourceCode.getTokenBefore(last); validateBraceSpacing(node, first, second, penultimate, last); @@ -247,7 +247,7 @@ module.exports = { return; } - var firstSpecifier = node.specifiers[0], + let firstSpecifier = node.specifiers[0], lastSpecifier = node.specifiers[node.specifiers.length - 1], first = sourceCode.getTokenBefore(firstSpecifier), last = sourceCode.getTokenAfter(lastSpecifier); @@ -257,7 +257,7 @@ module.exports = { last = sourceCode.getTokenAfter(last); } - var second = sourceCode.getTokenAfter(first), + let second = sourceCode.getTokenAfter(first), penultimate = sourceCode.getTokenBefore(last); validateBraceSpacing(node, first, second, penultimate, last); diff --git a/tools/eslint/lib/rules/object-property-newline.js b/tools/eslint/lib/rules/object-property-newline.js index eb96152bb16..fef7b871b44 100644 --- a/tools/eslint/lib/rules/object-property-newline.js +++ b/tools/eslint/lib/rules/object-property-newline.js @@ -31,21 +31,21 @@ module.exports = { }, create: function(context) { - var allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine); - var errorMessage = allowSameLine ? - "Object properties must go on a new line if they aren't all on the same line" : - "Object properties must go on a new line"; + let allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine); + let errorMessage = allowSameLine ? + "Object properties must go on a new line if they aren't all on the same line." : + "Object properties must go on a new line."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { ObjectExpression: function(node) { - var lastTokenOfPreviousProperty, firstTokenOfCurrentProperty; + let lastTokenOfPreviousProperty, firstTokenOfCurrentProperty; if (allowSameLine) { if (node.properties.length > 1) { - var firstTokenOfFirstProperty = sourceCode.getFirstToken(node.properties[0]); - var lastTokenOfLastProperty = sourceCode.getLastToken(node.properties[node.properties.length - 1]); + let firstTokenOfFirstProperty = sourceCode.getFirstToken(node.properties[0]); + let lastTokenOfLastProperty = sourceCode.getLastToken(node.properties[node.properties.length - 1]); if (firstTokenOfFirstProperty.loc.end.line === lastTokenOfLastProperty.loc.start.line) { @@ -55,7 +55,7 @@ module.exports = { } } - for (var i = 1; i < node.properties.length; i++) { + for (let i = 1; i < node.properties.length; i++) { lastTokenOfPreviousProperty = sourceCode.getLastToken(node.properties[i - 1]); firstTokenOfCurrentProperty = sourceCode.getFirstToken(node.properties[i]); diff --git a/tools/eslint/lib/rules/object-shorthand.js b/tools/eslint/lib/rules/object-shorthand.js index a528c00d38f..1d08178d57e 100644 --- a/tools/eslint/lib/rules/object-shorthand.js +++ b/tools/eslint/lib/rules/object-shorthand.js @@ -5,7 +5,7 @@ "use strict"; -var OPTIONS = { +let OPTIONS = { always: "always", never: "never", methods: "methods", @@ -83,14 +83,14 @@ module.exports = { }, create: function(context) { - var APPLY = context.options[0] || OPTIONS.always; - var APPLY_TO_METHODS = APPLY === OPTIONS.methods || APPLY === OPTIONS.always; - var APPLY_TO_PROPS = APPLY === OPTIONS.properties || APPLY === OPTIONS.always; - var APPLY_NEVER = APPLY === OPTIONS.never; + let APPLY = context.options[0] || OPTIONS.always; + let APPLY_TO_METHODS = APPLY === OPTIONS.methods || APPLY === OPTIONS.always; + let APPLY_TO_PROPS = APPLY === OPTIONS.properties || APPLY === OPTIONS.always; + let APPLY_NEVER = APPLY === OPTIONS.never; - var PARAMS = context.options[1] || {}; - var IGNORE_CONSTRUCTORS = PARAMS.ignoreConstructors; - var AVOID_QUOTES = PARAMS.avoidQuotes; + let PARAMS = context.options[1] || {}; + let IGNORE_CONSTRUCTORS = PARAMS.ignoreConstructors; + let AVOID_QUOTES = PARAMS.avoidQuotes; //-------------------------------------------------------------------------- // Helpers @@ -103,7 +103,7 @@ module.exports = { * @private */ function isConstructor(name) { - var firstChar = name.charAt(0); + let firstChar = name.charAt(0); return firstChar === firstChar.toUpperCase(); } @@ -123,7 +123,7 @@ module.exports = { return { Property: function(node) { - var isConciseProperty = node.method || node.shorthand, + let isConciseProperty = node.method || node.shorthand, type; // Ignore destructuring assignment diff --git a/tools/eslint/lib/rules/one-var-declaration-per-line.js b/tools/eslint/lib/rules/one-var-declaration-per-line.js index f4cdb84b187..e7a29fb115d 100644 --- a/tools/eslint/lib/rules/one-var-declaration-per-line.js +++ b/tools/eslint/lib/rules/one-var-declaration-per-line.js @@ -25,8 +25,8 @@ module.exports = { create: function(context) { - var ERROR_MESSAGE = "Expected variable declaration to be on a new line."; - var always = context.options[0] === "always"; + let ERROR_MESSAGE = "Expected variable declaration to be on a new line."; + let always = context.options[0] === "always"; //-------------------------------------------------------------------------- // Helpers @@ -54,8 +54,8 @@ module.exports = { return; } - var declarations = node.declarations; - var prev; + let declarations = node.declarations; + let prev; declarations.forEach(function(current) { if (prev && prev.loc.end.line === current.loc.start.line) { diff --git a/tools/eslint/lib/rules/one-var.js b/tools/eslint/lib/rules/one-var.js index 2bd49f511f4..10cdb626e57 100644 --- a/tools/eslint/lib/rules/one-var.js +++ b/tools/eslint/lib/rules/one-var.js @@ -57,12 +57,12 @@ module.exports = { create: function(context) { - var MODE_ALWAYS = "always", + let MODE_ALWAYS = "always", MODE_NEVER = "never"; - var mode = context.options[0] || MODE_ALWAYS; + let mode = context.options[0] || MODE_ALWAYS; - var options = { + let options = { }; if (typeof mode === "string") { // simple options configuration with just a string @@ -113,8 +113,8 @@ module.exports = { // Helpers //-------------------------------------------------------------------------- - var functionStack = []; - var blockStack = []; + let functionStack = []; + let blockStack = []; /** * Increments the blockStack counter. @@ -166,7 +166,7 @@ module.exports = { * @private */ function recordTypes(statementType, declarations, currentScope) { - for (var i = 0; i < declarations.length; i++) { + for (let i = 0; i < declarations.length; i++) { if (declarations[i].init === null) { if (options[statementType] && options[statementType].uninitialized === MODE_ALWAYS) { currentScope.uninitialized = true; @@ -185,7 +185,7 @@ module.exports = { * @returns {Object} The scope associated with statementType */ function getCurrentScope(statementType) { - var currentScope; + let currentScope; if (statementType === "var") { currentScope = functionStack[functionStack.length - 1]; @@ -204,9 +204,9 @@ module.exports = { * @private */ function countDeclarations(declarations) { - var counts = { uninitialized: 0, initialized: 0 }; + let counts = { uninitialized: 0, initialized: 0 }; - for (var i = 0; i < declarations.length; i++) { + for (let i = 0; i < declarations.length; i++) { if (declarations[i].init === null) { counts.uninitialized++; } else { @@ -225,9 +225,9 @@ module.exports = { */ function hasOnlyOneStatement(statementType, declarations) { - var declarationCounts = countDeclarations(declarations); - var currentOptions = options[statementType] || {}; - var currentScope = getCurrentScope(statementType); + let declarationCounts = countDeclarations(declarations); + let currentOptions = options[statementType] || {}; + let currentScope = getCurrentScope(statementType); if (currentOptions.uninitialized === MODE_ALWAYS && currentOptions.initialized === MODE_ALWAYS) { if (currentScope.uninitialized || currentScope.initialized) { @@ -266,7 +266,7 @@ module.exports = { SwitchStatement: startBlock, VariableDeclaration: function(node) { - var parent = node.parent, + let parent = node.parent, type, declarations, declarationCounts; type = node.kind; @@ -296,7 +296,7 @@ module.exports = { // never if (parent.type !== "ForStatement" || parent.init !== node) { - var totalDeclarations = declarationCounts.uninitialized + declarationCounts.initialized; + let totalDeclarations = declarationCounts.uninitialized + declarationCounts.initialized; if (totalDeclarations > 1) { diff --git a/tools/eslint/lib/rules/operator-assignment.js b/tools/eslint/lib/rules/operator-assignment.js index 7e60c9efd40..3088ff174f5 100644 --- a/tools/eslint/lib/rules/operator-assignment.js +++ b/tools/eslint/lib/rules/operator-assignment.js @@ -93,7 +93,7 @@ module.exports = { * @returns {void} */ function verify(node) { - var expr, left, operator; + let expr, left, operator; if (node.operator !== "=" || node.right.type !== "BinaryExpression") { return; diff --git a/tools/eslint/lib/rules/operator-linebreak.js b/tools/eslint/lib/rules/operator-linebreak.js index 8f17155b862..2b2f1274aa1 100644 --- a/tools/eslint/lib/rules/operator-linebreak.js +++ b/tools/eslint/lib/rules/operator-linebreak.js @@ -5,7 +5,7 @@ "use strict"; -var lodash = require("lodash"), +let lodash = require("lodash"), astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ @@ -44,10 +44,10 @@ module.exports = { create: function(context) { - var usedDefaultGlobal = !context.options[0]; - var globalStyle = context.options[0] || "after"; - var options = context.options[1] || {}; - var styleOverrides = options.overrides ? lodash.assign({}, options.overrides) : {}; + let usedDefaultGlobal = !context.options[0]; + let globalStyle = context.options[0] || "after"; + let options = context.options[1] || {}; + let styleOverrides = options.overrides ? lodash.assign({}, options.overrides) : {}; if (usedDefaultGlobal && !styleOverrides["?"]) { styleOverrides["?"] = "before"; @@ -57,7 +57,7 @@ module.exports = { styleOverrides[":"] = "before"; } - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -71,8 +71,8 @@ module.exports = { * @returns {void} */ function validateNode(node, leftSide) { - var leftToken = sourceCode.getLastToken(leftSide); - var operatorToken = sourceCode.getTokenAfter(leftToken); + let leftToken = sourceCode.getLastToken(leftSide); + let operatorToken = sourceCode.getTokenAfter(leftToken); // When the left part of a binary expression is a single expression wrapped in // parentheses (ex: `(a) + b`), leftToken will be the last token of the expression @@ -84,10 +84,10 @@ module.exports = { operatorToken = sourceCode.getTokenAfter(operatorToken); } - var rightToken = sourceCode.getTokenAfter(operatorToken); - var operator = operatorToken.value; - var operatorStyleOverride = styleOverrides[operator]; - var style = operatorStyleOverride || globalStyle; + let rightToken = sourceCode.getTokenAfter(operatorToken); + let operator = operatorToken.value; + let operatorStyleOverride = styleOverrides[operator]; + let style = operatorStyleOverride || globalStyle; // if single line if (astUtils.isTokenOnSameLine(leftToken, operatorToken) && @@ -123,7 +123,7 @@ module.exports = { context.report(node, { line: operatorToken.loc.end.line, column: operatorToken.loc.end.column - }, "There should be no line break before or after '" + operator + "'"); + }, "There should be no line break before or after '" + operator + "'."); } } diff --git a/tools/eslint/lib/rules/padded-blocks.js b/tools/eslint/lib/rules/padded-blocks.js index 7ec24c65d7d..2754cda4de6 100644 --- a/tools/eslint/lib/rules/padded-blocks.js +++ b/tools/eslint/lib/rules/padded-blocks.js @@ -47,8 +47,8 @@ module.exports = { }, create: function(context) { - var options = {}; - var config = context.options[0] || "always"; + let options = {}; + let config = context.options[0] || "always"; if (typeof config === "string") { options.blocks = config === "always"; @@ -64,10 +64,10 @@ module.exports = { } } - var ALWAYS_MESSAGE = "Block must be padded by blank lines.", + let ALWAYS_MESSAGE = "Block must be padded by blank lines.", NEVER_MESSAGE = "Block must not be padded by blank lines."; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Gets the open brace token from a given node. @@ -96,7 +96,7 @@ module.exports = { * @returns {boolean} Whether or not the token is followed by a blank line. */ function isTokenTopPadded(token) { - var tokenStartLine = token.loc.start.line, + let tokenStartLine = token.loc.start.line, expectedFirstLine = tokenStartLine + 2, first, firstLine; @@ -116,7 +116,7 @@ module.exports = { * @returns {boolean} Whether or not the token is preceeded by a blank line */ function isTokenBottomPadded(token) { - var blockEnd = token.loc.end.line, + let blockEnd = token.loc.end.line, expectedLastLine = blockEnd - 2, last, lastLine; @@ -156,7 +156,7 @@ module.exports = { * @returns {void} undefined. */ function checkPadding(node) { - var openBrace = getOpenBrace(node), + let openBrace = getOpenBrace(node), closeBrace = sourceCode.getLastToken(node), blockHasTopPadding = isTokenTopPadded(openBrace), blockHasBottomPadding = isTokenBottomPadded(closeBrace); @@ -184,7 +184,7 @@ module.exports = { } } else { if (blockHasTopPadding) { - var nextToken = sourceCode.getTokenOrCommentAfter(openBrace); + let nextToken = sourceCode.getTokenOrCommentAfter(openBrace); context.report({ node: node, @@ -197,7 +197,7 @@ module.exports = { } if (blockHasBottomPadding) { - var previousToken = sourceCode.getTokenOrCommentBefore(closeBrace); + let previousToken = sourceCode.getTokenOrCommentBefore(closeBrace); context.report({ node: node, @@ -211,7 +211,7 @@ module.exports = { } } - var rule = {}; + let rule = {}; if (options.hasOwnProperty("switches")) { rule.SwitchStatement = function(node) { diff --git a/tools/eslint/lib/rules/prefer-arrow-callback.js b/tools/eslint/lib/rules/prefer-arrow-callback.js index 4c4c2e6f2b1..185bf160576 100644 --- a/tools/eslint/lib/rules/prefer-arrow-callback.js +++ b/tools/eslint/lib/rules/prefer-arrow-callback.js @@ -35,10 +35,10 @@ function checkMetaProperty(node, metaName, propertyName) { * @returns {escope.Variable} The found variable object. */ function getVariableOfArguments(scope) { - var variables = scope.variables; + let variables = scope.variables; - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; if (variable.name === "arguments") { @@ -58,13 +58,13 @@ function getVariableOfArguments(scope) { /** * Checkes whether or not a given node is a callback. * @param {ASTNode} node - A node to check. - * @returns {object} + * @returns {Object} * {boolean} retv.isCallback - `true` if the node is a callback. * {boolean} retv.isLexicalThis - `true` if the node is with `.bind(this)`. */ function getCallbackInfo(node) { - var retv = {isCallback: false, isLexicalThis: false}; - var parent = node.parent; + let retv = {isCallback: false, isLexicalThis: false}; + let parent = node.parent; while (node) { switch (parent.type) { @@ -144,10 +144,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; + let options = context.options[0] || {}; - var allowUnboundThis = options.allowUnboundThis !== false; // default to true - var allowNamedFunctions = options.allowNamedFunctions; + let allowUnboundThis = options.allowUnboundThis !== false; // default to true + let allowNamedFunctions = options.allowNamedFunctions; /* * {Array<{this: boolean, super: boolean, meta: boolean}>} @@ -155,7 +155,7 @@ module.exports = { * - super - A flag which shows there are one or more Super. * - meta - A flag which shows there are one or more MethProperty. */ - var stack = []; + let stack = []; /** * Pushes new function scope with all `false` flags. @@ -182,7 +182,7 @@ module.exports = { // If there are below, it cannot replace with arrow functions merely. ThisExpression: function() { - var info = stack[stack.length - 1]; + let info = stack[stack.length - 1]; if (info) { info.this = true; @@ -190,7 +190,7 @@ module.exports = { }, Super: function() { - var info = stack[stack.length - 1]; + let info = stack[stack.length - 1]; if (info) { info.super = true; @@ -198,7 +198,7 @@ module.exports = { }, MetaProperty: function(node) { - var info = stack[stack.length - 1]; + let info = stack[stack.length - 1]; if (info && checkMetaProperty(node, "new", "target")) { info.meta = true; @@ -212,7 +212,7 @@ module.exports = { // Main. FunctionExpression: enterScope, "FunctionExpression:exit": function(node) { - var scopeInfo = exitScope(); + let scopeInfo = exitScope(); // Skip named function expressions if (allowNamedFunctions && node.id && node.id.name) { @@ -225,21 +225,21 @@ module.exports = { } // Skip recursive functions. - var nameVar = context.getDeclaredVariables(node)[0]; + let nameVar = context.getDeclaredVariables(node)[0]; if (isFunctionName(nameVar) && nameVar.references.length > 0) { return; } // Skip if it's using arguments. - var variable = getVariableOfArguments(context.getScope()); + let variable = getVariableOfArguments(context.getScope()); if (variable && variable.references.length > 0) { return; } // Reports if it's a callback which can replace with arrows. - var callbackInfo = getCallbackInfo(node); + let callbackInfo = getCallbackInfo(node); if (callbackInfo.isCallback && (!allowUnboundThis || !scopeInfo.this || callbackInfo.isLexicalThis) && diff --git a/tools/eslint/lib/rules/prefer-const.js b/tools/eslint/lib/rules/prefer-const.js index 7b8ac425193..5935e02b2c3 100644 --- a/tools/eslint/lib/rules/prefer-const.js +++ b/tools/eslint/lib/rules/prefer-const.js @@ -9,16 +9,15 @@ // Requirements //------------------------------------------------------------------------------ -var Map = require("es6-map"); -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var PATTERN_TYPE = /^(?:.+?Pattern|RestElement|Property)$/; -var DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/; -var DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/; +let PATTERN_TYPE = /^(?:.+?Pattern|RestElement|Property)$/; +let DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/; +let DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/; /** * Adds multiple items to the tail of an array. @@ -27,7 +26,7 @@ var DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/; * @param {any[]} values - Items to be added. * @returns {void} */ -var pushAll = Function.apply.bind(Array.prototype.push); +let pushAll = Function.apply.bind(Array.prototype.push); /** * Checks whether a given node is located at `ForStatement.init` or not. @@ -46,7 +45,7 @@ function isInitOfForStatement(node) { * @returns {boolean} `true` if the node can become a VariableDeclaration. */ function canBecomeVariableDeclaration(identifier) { - var node = identifier.parent; + let node = identifier.parent; while (PATTERN_TYPE.test(node.type)) { node = node.parent; @@ -88,15 +87,15 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) { } // Finds the unique WriteReference. - var writer = null; - var isReadBeforeInit = false; - var references = variable.references; + let writer = null; + let isReadBeforeInit = false; + let references = variable.references; - for (var i = 0; i < references.length; ++i) { - var reference = references[i]; + for (let i = 0; i < references.length; ++i) { + let reference = references[i]; if (reference.isWrite()) { - var isReassigned = ( + let isReassigned = ( writer !== null && writer.identifier !== reference.identifier ); @@ -116,7 +115,7 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) { // If the assignment is from a different scope, ignore it. // If the assignment cannot change to a declaration, ignore it. - var shouldBeConst = ( + let shouldBeConst = ( writer !== null && writer.from === variable.scope && canBecomeVariableDeclaration(writer.identifier) @@ -145,7 +144,7 @@ function getDestructuringHost(reference) { if (!reference.isWrite()) { return null; } - var node = reference.identifier.parent; + let node = reference.identifier.parent; while (PATTERN_TYPE.test(node.type)) { node = node.parent; @@ -169,17 +168,17 @@ function getDestructuringHost(reference) { * @returns {Map} Grouped identifier nodes. */ function groupByDestructuring(variables, ignoreReadBeforeAssign) { - var identifierMap = new Map(); + let identifierMap = new Map(); - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; - var references = variable.references; - var identifier = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); - var prevId = null; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; + let references = variable.references; + let identifier = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); + let prevId = null; - for (var j = 0; j < references.length; ++j) { - var reference = references[j]; - var id = reference.identifier; + for (let j = 0; j < references.length; ++j) { + let reference = references[j]; + let id = reference.identifier; // Avoid counting a reference twice or more for default values of // destructuring. @@ -189,7 +188,7 @@ function groupByDestructuring(variables, ignoreReadBeforeAssign) { prevId = id; // Add the identifier node into the destructuring group. - var group = getDestructuringHost(reference); + let group = getDestructuringHost(reference); if (group) { if (identifierMap.has(group)) { @@ -209,7 +208,7 @@ function groupByDestructuring(variables, ignoreReadBeforeAssign) { * * @param {ASTNode} node – The node to search from. * @param {string} type – The type field of the parent node. - * @param {function} shouldStop – a predicate that returns true if the traversal should stop, and false otherwise. + * @param {Function} shouldStop – a predicate that returns true if the traversal should stop, and false otherwise. * @returns {ASTNode} The closest ancestor with the specified type; null if no such ancestor exists. */ function findUp(node, type, shouldStop) { @@ -249,10 +248,10 @@ module.exports = { }, create: function(context) { - var options = context.options[0] || {}; - var checkingMixedDestructuring = options.destructuring !== "all"; - var ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true; - var variables = null; + let options = context.options[0] || {}; + let checkingMixedDestructuring = options.destructuring !== "all"; + let ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true; + let variables = null; /** * Reports a given Identifier node. @@ -261,7 +260,7 @@ module.exports = { * @returns {void} */ function report(node) { - var reportArgs = { + let reportArgs = { node: node, message: "'{{name}}' is never reassigned. Use 'const' instead.", data: node @@ -318,7 +317,7 @@ module.exports = { * @returns {void} */ function checkVariable(variable) { - var node = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); + let node = getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign); if (node) { report(node); diff --git a/tools/eslint/lib/rules/prefer-reflect.js b/tools/eslint/lib/rules/prefer-reflect.js index 38bb093ba6f..b2b0b9abda8 100644 --- a/tools/eslint/lib/rules/prefer-reflect.js +++ b/tools/eslint/lib/rules/prefer-reflect.js @@ -45,7 +45,7 @@ module.exports = { }, create: function(context) { - var existingNames = { + let existingNames = { apply: "Function.prototype.apply", call: "Function.prototype.call", defineProperty: "Object.defineProperty", @@ -57,7 +57,7 @@ module.exports = { preventExtensions: "Object.preventExtensions" }; - var reflectSubsitutes = { + let reflectSubsitutes = { apply: "Reflect.apply", call: "Reflect.apply", defineProperty: "Reflect.defineProperty", @@ -69,7 +69,7 @@ module.exports = { preventExtensions: "Reflect.preventExtensions" }; - var exceptions = (context.options[0] || {}).exceptions || []; + let exceptions = (context.options[0] || {}).exceptions || []; /** * Reports the Reflect violation based on the `existing` and `substitute` @@ -79,7 +79,7 @@ module.exports = { * @returns {void} */ function report(node, existing, substitute) { - context.report(node, "Avoid using {{existing}}, instead use {{substitute}}", { + context.report(node, "Avoid using {{existing}}, instead use {{substitute}}.", { existing: existing, substitute: substitute }); @@ -87,19 +87,19 @@ module.exports = { return { CallExpression: function(node) { - var methodName = (node.callee.property || {}).name; - var isReflectCall = (node.callee.object || {}).name === "Reflect"; - var hasReflectSubsitute = reflectSubsitutes.hasOwnProperty(methodName); - var userConfiguredException = exceptions.indexOf(methodName) !== -1; + let methodName = (node.callee.property || {}).name; + let isReflectCall = (node.callee.object || {}).name === "Reflect"; + let hasReflectSubsitute = reflectSubsitutes.hasOwnProperty(methodName); + let userConfiguredException = exceptions.indexOf(methodName) !== -1; if (hasReflectSubsitute && !isReflectCall && !userConfiguredException) { report(node, existingNames[methodName], reflectSubsitutes[methodName]); } }, UnaryExpression: function(node) { - var isDeleteOperator = node.operator === "delete"; - var targetsIdentifier = node.argument.type === "Identifier"; - var userConfiguredException = exceptions.indexOf("delete") !== -1; + let isDeleteOperator = node.operator === "delete"; + let targetsIdentifier = node.argument.type === "Identifier"; + let userConfiguredException = exceptions.indexOf("delete") !== -1; if (isDeleteOperator && !targetsIdentifier && !userConfiguredException) { report(node, "the delete keyword", "Reflect.deleteProperty"); diff --git a/tools/eslint/lib/rules/prefer-rest-params.js b/tools/eslint/lib/rules/prefer-rest-params.js index 0ce1d8a1220..5a9164ed7f4 100644 --- a/tools/eslint/lib/rules/prefer-rest-params.js +++ b/tools/eslint/lib/rules/prefer-rest-params.js @@ -15,10 +15,10 @@ * @returns {escope.Variable} The found variable object. */ function getVariableOfArguments(scope) { - var variables = scope.variables; + let variables = scope.variables; - for (var i = 0; i < variables.length; ++i) { - var variable = variables[i]; + for (let i = 0; i < variables.length; ++i) { + let variable = variables[i]; if (variable.name === "arguments") { @@ -68,7 +68,7 @@ module.exports = { * @returns {void} */ function checkForArguments() { - var argumentsVar = getVariableOfArguments(context.getScope()); + let argumentsVar = getVariableOfArguments(context.getScope()); if (argumentsVar) { argumentsVar.references.forEach(report); diff --git a/tools/eslint/lib/rules/prefer-spread.js b/tools/eslint/lib/rules/prefer-spread.js index 67f1e855b00..58fc85ca907 100644 --- a/tools/eslint/lib/rules/prefer-spread.js +++ b/tools/eslint/lib/rules/prefer-spread.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -35,13 +35,13 @@ function isVariadicApplyCalling(node) { * @returns {boolean} the source code for the given node. */ function equalTokens(left, right, sourceCode) { - var tokensL = sourceCode.getTokens(left); - var tokensR = sourceCode.getTokens(right); + let tokensL = sourceCode.getTokens(left); + let tokensR = sourceCode.getTokens(right); if (tokensL.length !== tokensR.length) { return false; } - for (var i = 0; i < tokensL.length; ++i) { + for (let i = 0; i < tokensL.length; ++i) { if (tokensL[i].type !== tokensR[i].type || tokensL[i].value !== tokensR[i].value ) { @@ -82,7 +82,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { CallExpression: function(node) { @@ -90,9 +90,9 @@ module.exports = { return; } - var applied = node.callee.object; - var expectedThis = (applied.type === "MemberExpression") ? applied.object : null; - var thisArg = node.arguments[0]; + let applied = node.callee.object; + let expectedThis = (applied.type === "MemberExpression") ? applied.object : null; + let thisArg = node.arguments[0]; if (isValidThisArg(expectedThis, thisArg, sourceCode)) { context.report(node, "use the spread operator instead of the '.apply()'."); diff --git a/tools/eslint/lib/rules/prefer-template.js b/tools/eslint/lib/rules/prefer-template.js index 0165aaecd65..4a0da8e197d 100644 --- a/tools/eslint/lib/rules/prefer-template.js +++ b/tools/eslint/lib/rules/prefer-template.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers @@ -66,7 +66,7 @@ module.exports = { }, create: function(context) { - var done = Object.create(null); + let done = Object.create(null); /** * Reports if a given node is string concatenation with non string literals. @@ -79,7 +79,7 @@ module.exports = { return; } - var topBinaryExpr = getTopConcatBinaryExpression(node.parent); + let topBinaryExpr = getTopConcatBinaryExpression(node.parent); // Checks whether or not this node had been checked already. if (done[topBinaryExpr.range[0]]) { diff --git a/tools/eslint/lib/rules/quote-props.js b/tools/eslint/lib/rules/quote-props.js index 1fd2e74a5a3..ec65647450c 100644 --- a/tools/eslint/lib/rules/quote-props.js +++ b/tools/eslint/lib/rules/quote-props.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var espree = require("espree"), +let espree = require("espree"), keywords = require("../util/keywords"); //------------------------------------------------------------------------------ @@ -66,7 +66,7 @@ module.exports = { create: function(context) { - var MODE = context.options[0], + let MODE = context.options[0], KEYWORDS = context.options[1] && context.options[1].keywords, CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false, NUMBERS = context.options[1] && context.options[1].numbers, @@ -106,7 +106,7 @@ module.exports = { * @returns {void} */ function checkUnnecessaryQuotes(node) { - var key = node.key, + let key = node.key, isKeywordToken, tokens; @@ -147,7 +147,7 @@ module.exports = { * @returns {void} */ function checkOmittedQuotes(node) { - var key = node.key; + let key = node.key; if (!node.method && !node.computed && !node.shorthand && !(key.type === "Literal" && typeof key.value === "string")) { context.report(node, MESSAGE_UNQUOTED, { @@ -163,12 +163,12 @@ module.exports = { * @returns {void} */ function checkConsistency(node, checkQuotesRedundancy) { - var quotes = false, + let quotes = false, lackOfQuotes = false, necessaryQuotes = false; node.properties.forEach(function(property) { - var key = property.key, + let key = property.key, tokens; if (!key || property.method || property.computed || property.shorthand) { diff --git a/tools/eslint/lib/rules/quotes.js b/tools/eslint/lib/rules/quotes.js index d4e9203811c..18635da537f 100644 --- a/tools/eslint/lib/rules/quotes.js +++ b/tools/eslint/lib/rules/quotes.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ -var QUOTE_SETTINGS = { +let QUOTE_SETTINGS = { double: { quote: "\"", alternateQuote: "'", @@ -45,8 +45,8 @@ var QUOTE_SETTINGS = { QUOTE_SETTINGS.double.convert = QUOTE_SETTINGS.single.convert = QUOTE_SETTINGS.backtick.convert = function(str) { - var newQuote = this.quote; - var oldQuote = str[0]; + let newQuote = this.quote; + let oldQuote = str[0]; if (newQuote === oldQuote) { return str; @@ -65,8 +65,7 @@ QUOTE_SETTINGS.backtick.convert = function(str) { }) + newQuote; }; -var AVOID_ESCAPE = "avoid-escape", - FUNCTION_TYPE = /^(?:Arrow)?Function(?:Declaration|Expression)$/; +let AVOID_ESCAPE = "avoid-escape"; //------------------------------------------------------------------------------ // Rule Definition @@ -110,7 +109,7 @@ module.exports = { create: function(context) { - var quoteOption = context.options[0], + let quoteOption = context.options[0], settings = QUOTE_SETTINGS[quoteOption || "double"], options = context.options[1], avoidEscape = options && options.avoidEscape === true, @@ -155,15 +154,15 @@ module.exports = { * @private */ function isPartOfDirectivePrologue(node) { - var block = node.parent.parent; + let block = node.parent.parent; - if (block.type !== "Program" && (block.type !== "BlockStatement" || !FUNCTION_TYPE.test(block.parent.type))) { + if (block.type !== "Program" && (block.type !== "BlockStatement" || !astUtils.isFunction(block.parent))) { return false; } // Check the node is at a prologue. - for (var i = 0; i < block.body.length; ++i) { - var statement = block.body[i]; + for (let i = 0; i < block.body.length; ++i) { + let statement = block.body[i]; if (statement === node.parent) { return true; @@ -183,7 +182,7 @@ module.exports = { * @private */ function isAllowedAsNonBacktick(node) { - var parent = node.parent; + let parent = node.parent; switch (parent.type) { @@ -210,7 +209,7 @@ module.exports = { return { Literal: function(node) { - var val = node.value, + let val = node.value, rawVal = node.raw, isValid; @@ -242,7 +241,7 @@ module.exports = { return; } - var shouldWarn = node.quasis.length === 1 && (node.quasis[0].value.cooked.indexOf("\n") === -1); + let shouldWarn = node.quasis.length === 1 && (node.quasis[0].value.cooked.indexOf("\n") === -1); if (shouldWarn) { context.report({ diff --git a/tools/eslint/lib/rules/radix.js b/tools/eslint/lib/rules/radix.js index 05a1c130a9f..4c9cb73bebc 100644 --- a/tools/eslint/lib/rules/radix.js +++ b/tools/eslint/lib/rules/radix.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var MODE_ALWAYS = "always", +let MODE_ALWAYS = "always", MODE_AS_NEEDED = "as-needed"; /** @@ -92,7 +92,7 @@ module.exports = { }, create: function(context) { - var mode = context.options[0] || MODE_ALWAYS; + let mode = context.options[0] || MODE_ALWAYS; /** * Checks the arguments of a given CallExpression node and reports it if it @@ -102,7 +102,7 @@ module.exports = { * @returns {void} */ function checkArguments(node) { - var args = node.arguments; + let args = node.arguments; switch (args.length) { case 0: @@ -139,14 +139,14 @@ module.exports = { return { "Program:exit": function() { - var scope = context.getScope(); - var variable; + let scope = context.getScope(); + let variable; // Check `parseInt()` variable = astUtils.getVariableByName(scope, "parseInt"); if (!isShadowed(variable)) { variable.references.forEach(function(reference) { - var node = reference.identifier; + let node = reference.identifier; if (astUtils.isCallee(node)) { checkArguments(node.parent); @@ -158,7 +158,7 @@ module.exports = { variable = astUtils.getVariableByName(scope, "Number"); if (!isShadowed(variable)) { variable.references.forEach(function(reference) { - var node = reference.identifier.parent; + let node = reference.identifier.parent; if (isParseIntMethod(node) && astUtils.isCallee(node)) { checkArguments(node.parent); diff --git a/tools/eslint/lib/rules/require-jsdoc.js b/tools/eslint/lib/rules/require-jsdoc.js index 083e79b1f55..1503c0ff886 100644 --- a/tools/eslint/lib/rules/require-jsdoc.js +++ b/tools/eslint/lib/rules/require-jsdoc.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let lodash = require("lodash"); module.exports = { meta: { @@ -40,13 +40,13 @@ module.exports = { }, create: function(context) { - var source = context.getSourceCode(); - var DEFAULT_OPTIONS = { + let source = context.getSourceCode(); + let DEFAULT_OPTIONS = { FunctionDeclaration: true, MethodDefinition: false, ClassDeclaration: false }; - var options = lodash.assign(DEFAULT_OPTIONS, context.options[0] && context.options[0].require || {}); + let options = lodash.assign(DEFAULT_OPTIONS, context.options[0] && context.options[0].require || {}); /** * Report the error message @@ -64,7 +64,7 @@ module.exports = { */ function checkClassMethodJsDoc(node) { if (node.parent.type === "MethodDefinition") { - var jsdocComment = source.getJSDocComment(node); + let jsdocComment = source.getJSDocComment(node); if (!jsdocComment) { report(node); @@ -78,7 +78,7 @@ module.exports = { * @returns {void} */ function checkJsDoc(node) { - var jsdocComment = source.getJSDocComment(node); + let jsdocComment = source.getJSDocComment(node); if (!jsdocComment) { report(node); diff --git a/tools/eslint/lib/rules/require-yield.js b/tools/eslint/lib/rules/require-yield.js index cde7d8c2c48..a4bb292b7a9 100644 --- a/tools/eslint/lib/rules/require-yield.js +++ b/tools/eslint/lib/rules/require-yield.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var stack = []; + let stack = []; /** * If the node is a generator function, start counting `yield` keywords. @@ -45,7 +45,7 @@ module.exports = { return; } - var countYield = stack.pop(); + let countYield = stack.pop(); if (countYield === 0 && node.body.body.length > 0) { context.report( diff --git a/tools/eslint/lib/rules/rest-spread-spacing.js b/tools/eslint/lib/rules/rest-spread-spacing.js index 7ffafa53199..3be2a434210 100644 --- a/tools/eslint/lib/rules/rest-spread-spacing.js +++ b/tools/eslint/lib/rules/rest-spread-spacing.js @@ -25,7 +25,7 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), alwaysSpace = context.options[0] === "always"; //-------------------------------------------------------------------------- @@ -38,7 +38,7 @@ module.exports = { * @returns {void} */ function checkWhiteSpace(node) { - var operator = sourceCode.getFirstToken(node), + let operator = sourceCode.getFirstToken(node), nextToken = sourceCode.getTokenAfter(operator), hasWhitespace = sourceCode.isSpaceBetweenTokens(operator, nextToken), type; @@ -67,7 +67,7 @@ module.exports = { line: operator.loc.end.line, column: operator.loc.end.column }, - message: "Expected whitespace after {{type}} operator", + message: "Expected whitespace after {{type}} operator.", data: { type: type }, @@ -82,7 +82,7 @@ module.exports = { line: operator.loc.end.line, column: operator.loc.end.column }, - message: "Unexpected whitespace after {{type}} operator", + message: "Unexpected whitespace after {{type}} operator.", data: { type: type }, diff --git a/tools/eslint/lib/rules/semi-spacing.js b/tools/eslint/lib/rules/semi-spacing.js index 830044d2f3f..261905f96fa 100644 --- a/tools/eslint/lib/rules/semi-spacing.js +++ b/tools/eslint/lib/rules/semi-spacing.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -39,7 +39,7 @@ module.exports = { create: function(context) { - var config = context.options[0], + let config = context.options[0], requireSpaceBefore = false, requireSpaceAfter = true, sourceCode = context.getSourceCode(); @@ -59,7 +59,7 @@ module.exports = { * @returns {boolean} True if the given token has leading space, false if not. */ function hasLeadingSpace(token) { - var tokenBefore = sourceCode.getTokenBefore(token); + let tokenBefore = sourceCode.getTokenBefore(token); return tokenBefore && astUtils.isTokenOnSameLine(tokenBefore, token) && sourceCode.isSpaceBetweenTokens(tokenBefore, token); } @@ -70,7 +70,7 @@ module.exports = { * @returns {boolean} True if the given token has trailing space, false if not. */ function hasTrailingSpace(token) { - var tokenAfter = sourceCode.getTokenAfter(token); + let tokenAfter = sourceCode.getTokenAfter(token); return tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter) && sourceCode.isSpaceBetweenTokens(token, tokenAfter); } @@ -81,7 +81,7 @@ module.exports = { * @returns {boolean} Whether or not the token is the last in its line. */ function isLastTokenInCurrentLine(token) { - var tokenAfter = sourceCode.getTokenAfter(token); + let tokenAfter = sourceCode.getTokenAfter(token); return !(tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter)); } @@ -92,7 +92,7 @@ module.exports = { * @returns {boolean} Whether or not the token is the first in its line. */ function isFirstTokenInCurrentLine(token) { - var tokenBefore = sourceCode.getTokenBefore(token); + let tokenBefore = sourceCode.getTokenBefore(token); return !(tokenBefore && astUtils.isTokenOnSameLine(token, tokenBefore)); } @@ -103,7 +103,7 @@ module.exports = { * @returns {boolean} Whether or not the next token of a given token is a closing parenthesis. */ function isBeforeClosingParen(token) { - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); return ( nextToken && @@ -128,7 +128,7 @@ module.exports = { * @returns {void} */ function checkSemicolonSpacing(token, node) { - var location; + let location; if (isSemicolon(token)) { location = token.loc.start; @@ -140,7 +140,7 @@ module.exports = { loc: location, message: "Unexpected whitespace before semicolon.", fix: function(fixer) { - var tokenBefore = sourceCode.getTokenBefore(token); + let tokenBefore = sourceCode.getTokenBefore(token); return fixer.removeRange([tokenBefore.range[1], token.range[0]]); } @@ -167,7 +167,7 @@ module.exports = { loc: location, message: "Unexpected whitespace after semicolon.", fix: function(fixer) { - var tokenAfter = sourceCode.getTokenAfter(token); + let tokenAfter = sourceCode.getTokenAfter(token); return fixer.removeRange([token.range[1], tokenAfter.range[0]]); } @@ -195,7 +195,7 @@ module.exports = { * @returns {void} */ function checkNode(node) { - var token = sourceCode.getLastToken(node); + let token = sourceCode.getLastToken(node); checkSemicolonSpacing(token, node); } diff --git a/tools/eslint/lib/rules/semi.js b/tools/eslint/lib/rules/semi.js index d530725040b..80b1e9d0025 100644 --- a/tools/eslint/lib/rules/semi.js +++ b/tools/eslint/lib/rules/semi.js @@ -53,9 +53,9 @@ module.exports = { create: function(context) { - var OPT_OUT_PATTERN = /[\[\(\/\+\-]/; // One of [(/+- - var options = context.options[1]; - var never = context.options[0] === "never", + let OPT_OUT_PATTERN = /[\[\(\/\+\-]/; // One of [(/+- + let options = context.options[1]; + let never = context.options[0] === "never", exceptOneLine = options && options.omitLastInOneLineBlock === true, sourceCode = context.getSourceCode(); @@ -70,7 +70,7 @@ module.exports = { * @returns {void} */ function report(node, missing) { - var message, + let message, fix, lastToken = sourceCode.getLastToken(node), loc = lastToken.loc; @@ -115,7 +115,7 @@ module.exports = { * @returns {boolean} whether the semicolon is unnecessary. */ function isUnnecessarySemicolon(lastToken) { - var isDivider, isOptOutToken, lastTokenLine, nextToken, nextTokenLine; + let isDivider, isOptOutToken, lastTokenLine, nextToken, nextTokenLine; if (!isSemicolon(lastToken)) { return false; @@ -141,13 +141,13 @@ module.exports = { * @returns {boolean} whether the node is in a one-liner block statement. */ function isOneLinerBlock(node) { - var nextToken = sourceCode.getTokenAfter(node); + let nextToken = sourceCode.getTokenAfter(node); if (!nextToken || nextToken.value !== "}") { return false; } - var parent = node.parent; + let parent = node.parent; return parent && parent.type === "BlockStatement" && parent.loc.start.line === parent.loc.end.line; @@ -159,7 +159,7 @@ module.exports = { * @returns {void} */ function checkForSemicolon(node) { - var lastToken = sourceCode.getLastToken(node); + let lastToken = sourceCode.getLastToken(node); if (never) { if (isUnnecessarySemicolon(lastToken)) { @@ -184,7 +184,7 @@ module.exports = { * @returns {void} */ function checkForSemicolonForVariableDeclaration(node) { - var ancestors = context.getAncestors(), + let ancestors = context.getAncestors(), parentIndex = ancestors.length - 1, parent = ancestors[parentIndex]; diff --git a/tools/eslint/lib/rules/sort-imports.js b/tools/eslint/lib/rules/sort-imports.js index 18b34f86a09..c8d3340b0cd 100644 --- a/tools/eslint/lib/rules/sort-imports.js +++ b/tools/eslint/lib/rules/sort-imports.js @@ -44,7 +44,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0] || {}, + let configuration = context.options[0] || {}, ignoreCase = configuration.ignoreCase || false, ignoreMemberSort = configuration.ignoreMemberSort || false, memberSyntaxSortOrder = configuration.memberSyntaxSortOrder || ["none", "all", "multiple", "single"], @@ -98,7 +98,7 @@ module.exports = { return { ImportDeclaration: function(node) { if (previousDeclaration) { - var currentLocalMemberName = getFirstLocalMemberName(node), + let currentLocalMemberName = getFirstLocalMemberName(node), currentMemberSyntaxGroupIndex = getMemberParameterGroupIndex(node), previousLocalMemberName = getFirstLocalMemberName(previousDeclaration), previousMemberSyntaxGroupIndex = getMemberParameterGroupIndex(previousDeclaration); @@ -137,17 +137,17 @@ module.exports = { // Multiple members of an import declaration should also be sorted alphabetically. if (!ignoreMemberSort && node.specifiers.length > 1) { - var previousSpecifier = null; - var previousSpecifierName = null; + let previousSpecifier = null; + let previousSpecifierName = null; - for (var i = 0; i < node.specifiers.length; ++i) { - var currentSpecifier = node.specifiers[i]; + for (let i = 0; i < node.specifiers.length; ++i) { + let currentSpecifier = node.specifiers[i]; if (currentSpecifier.type !== "ImportSpecifier") { continue; } - var currentSpecifierName = currentSpecifier.local.name; + let currentSpecifierName = currentSpecifier.local.name; if (ignoreCase) { currentSpecifierName = currentSpecifierName.toLowerCase(); diff --git a/tools/eslint/lib/rules/sort-vars.js b/tools/eslint/lib/rules/sort-vars.js index 8a7b0e710a7..4b8187f36a9 100644 --- a/tools/eslint/lib/rules/sort-vars.js +++ b/tools/eslint/lib/rules/sort-vars.js @@ -32,7 +32,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0] || {}, + let configuration = context.options[0] || {}, ignoreCase = configuration.ignoreCase || false; return { @@ -42,7 +42,7 @@ module.exports = { return memo; } - var lastVariableName = memo.id.name, + let lastVariableName = memo.id.name, currenVariableName = decl.id.name; if (ignoreCase) { @@ -51,7 +51,7 @@ module.exports = { } if (currenVariableName < lastVariableName) { - context.report(decl, "Variables within the same declaration block should be sorted alphabetically"); + context.report(decl, "Variables within the same declaration block should be sorted alphabetically."); return memo; } else { return decl; diff --git a/tools/eslint/lib/rules/space-before-blocks.js b/tools/eslint/lib/rules/space-before-blocks.js index 468b3204470..b695e7ac12e 100644 --- a/tools/eslint/lib/rules/space-before-blocks.js +++ b/tools/eslint/lib/rules/space-before-blocks.js @@ -5,7 +5,7 @@ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -48,7 +48,7 @@ module.exports = { }, create: function(context) { - var config = context.options[0], + let config = context.options[0], sourceCode = context.getSourceCode(), checkFunctions = true, checkKeywords = true, @@ -81,7 +81,7 @@ module.exports = { * @returns {void} undefined. */ function checkPrecedingSpace(node) { - var precedingToken = sourceCode.getTokenBefore(node), + let precedingToken = sourceCode.getTokenBefore(node), hasSpace, parent, requireSpace; @@ -127,7 +127,7 @@ module.exports = { * @returns {void} undefined. */ function checkSpaceBeforeCaseBlock(node) { - var cases = node.cases, + let cases = node.cases, firstCase, openingBrace; diff --git a/tools/eslint/lib/rules/space-before-function-paren.js b/tools/eslint/lib/rules/space-before-function-paren.js index 2d26e41e4a9..b43d11ed13f 100644 --- a/tools/eslint/lib/rules/space-before-function-paren.js +++ b/tools/eslint/lib/rules/space-before-function-paren.js @@ -43,7 +43,7 @@ module.exports = { create: function(context) { - var configuration = context.options[0], + let configuration = context.options[0], sourceCode = context.getSourceCode(), requireAnonymousFunctionSpacing = true, forbidAnonymousFunctionSpacing = false, @@ -70,7 +70,7 @@ module.exports = { * @returns {boolean} Whether the function has a name. */ function isNamedFunction(node) { - var parent; + let parent; if (node.id) { return true; @@ -93,7 +93,7 @@ module.exports = { * @returns {void} */ function validateSpacingBeforeParentheses(node) { - var isNamed = isNamedFunction(node), + let isNamed = isNamedFunction(node), leftToken, rightToken, location; diff --git a/tools/eslint/lib/rules/space-in-parens.js b/tools/eslint/lib/rules/space-in-parens.js index 11361aec120..bd8c6eb3af8 100644 --- a/tools/eslint/lib/rules/space-in-parens.js +++ b/tools/eslint/lib/rules/space-in-parens.js @@ -4,7 +4,7 @@ */ "use strict"; -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition @@ -42,7 +42,7 @@ module.exports = { create: function(context) { - var MISSING_SPACE_MESSAGE = "There must be a space inside this paren.", + let MISSING_SPACE_MESSAGE = "There must be a space inside this paren.", REJECTED_SPACE_MESSAGE = "There should be no spaces inside this paren.", ALWAYS = context.options[0] === "always", @@ -64,7 +64,7 @@ module.exports = { * @private */ function getExceptions() { - var openers = [], + let openers = [], closers = []; if (options.braceException) { @@ -96,7 +96,7 @@ module.exports = { //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines if a token is one of the exceptions for the opener paren @@ -217,7 +217,7 @@ module.exports = { return { Program: function checkParenSpaces(node) { - var tokens, prevToken, nextToken; + let tokens, prevToken, nextToken; exceptions = getExceptions(); tokens = sourceCode.tokensAndComments; diff --git a/tools/eslint/lib/rules/space-infix-ops.js b/tools/eslint/lib/rules/space-infix-ops.js index bea82ba0b65..9f5b08773a4 100644 --- a/tools/eslint/lib/rules/space-infix-ops.js +++ b/tools/eslint/lib/rules/space-infix-ops.js @@ -32,29 +32,29 @@ module.exports = { }, create: function(context) { - var int32Hint = context.options[0] ? context.options[0].int32Hint === true : false; + let int32Hint = context.options[0] ? context.options[0].int32Hint === true : false; - var OPERATORS = [ + let OPERATORS = [ "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in", "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=", "?", ":", ",", "**" ]; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Returns the first token which violates the rule * @param {ASTNode} left - The left node of the main node * @param {ASTNode} right - The right node of the main node - * @returns {object} The violator token or null + * @returns {Object} The violator token or null * @private */ function getFirstNonSpacedToken(left, right) { - var op, + let op, tokens = sourceCode.getTokensBetween(left, right, 1); - for (var i = 1, l = tokens.length - 1; i < l; ++i) { + for (let i = 1, l = tokens.length - 1; i < l; ++i) { op = tokens[i]; if ( op.type === "Punctuator" && @@ -70,7 +70,7 @@ module.exports = { /** * Reports an AST node as a rule violation * @param {ASTNode} mainNode - The node to report - * @param {object} culpritToken - The token which has a problem + * @param {Object} culpritToken - The token which has a problem * @returns {void} * @private */ @@ -80,9 +80,9 @@ module.exports = { loc: culpritToken.loc.start, message: "Infix operators must be spaced.", fix: function(fixer) { - var previousToken = sourceCode.getTokenBefore(culpritToken); - var afterToken = sourceCode.getTokenAfter(culpritToken); - var fixString = ""; + let previousToken = sourceCode.getTokenBefore(culpritToken); + let afterToken = sourceCode.getTokenAfter(culpritToken); + let fixString = ""; if (culpritToken.range[0] - previousToken.range[1] === 0) { fixString = " "; @@ -106,7 +106,11 @@ module.exports = { * @private */ function checkBinary(node) { - var nonSpacedNode = getFirstNonSpacedToken(node.left, node.right); + if (node.left.typeAnnotation) { + return; + } + + let nonSpacedNode = getFirstNonSpacedToken(node.left, node.right); if (nonSpacedNode) { if (!(int32Hint && sourceCode.getText(node).substr(-2) === "|0")) { @@ -122,8 +126,8 @@ module.exports = { * @private */ function checkConditional(node) { - var nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent); - var nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate); + let nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent); + let nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate); if (nonSpacedConsequesntNode) { report(node, nonSpacedConsequesntNode); @@ -139,7 +143,7 @@ module.exports = { * @private */ function checkVar(node) { - var nonSpacedNode; + let nonSpacedNode; if (node.init) { nonSpacedNode = getFirstNonSpacedToken(node.id, node.init); diff --git a/tools/eslint/lib/rules/space-unary-ops.js b/tools/eslint/lib/rules/space-unary-ops.js index fdb1c03e987..77a98150b86 100644 --- a/tools/eslint/lib/rules/space-unary-ops.js +++ b/tools/eslint/lib/rules/space-unary-ops.js @@ -41,9 +41,9 @@ module.exports = { }, create: function(context) { - var options = context.options && Array.isArray(context.options) && context.options[0] || { words: true, nonwords: false }; + let options = context.options && Array.isArray(context.options) && context.options[0] || { words: true, nonwords: false }; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers @@ -91,8 +91,8 @@ module.exports = { /** * Verify Unary Word Operator has spaces after the word operator * @param {ASTnode} node AST node - * @param {object} firstToken first token from the AST node - * @param {object} secondToken second token from the AST node + * @param {Object} firstToken first token from the AST node + * @param {Object} secondToken second token from the AST node * @param {string} word The word to be used for reporting * @returns {void} */ @@ -111,8 +111,8 @@ module.exports = { /** * Verify Unary Word Operator doesn't have spaces after the word operator * @param {ASTnode} node AST node - * @param {object} firstToken first token from the AST node - * @param {object} secondToken second token from the AST node + * @param {Object} firstToken first token from the AST node + * @param {Object} secondToken second token from the AST node * @param {string} word The word to be used for reporting * @returns {void} */ @@ -133,8 +133,8 @@ module.exports = { /** * Check Unary Word Operators for spaces after the word operator * @param {ASTnode} node AST node - * @param {object} firstToken first token from the AST node - * @param {object} secondToken second token from the AST node + * @param {Object} firstToken first token from the AST node + * @param {Object} secondToken second token from the AST node * @param {string} word The word to be used for reporting * @returns {void} */ @@ -160,7 +160,7 @@ module.exports = { * @returns {void} */ function checkForSpacesAfterYield(node) { - var tokens = sourceCode.getFirstTokens(node, 3), + let tokens = sourceCode.getFirstTokens(node, 3), word = "yield"; if (!node.argument || node.delegate) { @@ -173,8 +173,8 @@ module.exports = { /** * Verifies UnaryExpression, UpdateExpression and NewExpression have spaces before or after the operator * @param {ASTnode} node AST node - * @param {object} firstToken First token in the expression - * @param {object} secondToken Second token in the expression + * @param {Object} firstToken First token in the expression + * @param {Object} secondToken Second token in the expression * @returns {void} */ function verifyNonWordsHaveSpaces(node, firstToken, secondToken) { @@ -207,8 +207,8 @@ module.exports = { /** * Verifies UnaryExpression, UpdateExpression and NewExpression don't have spaces before or after the operator * @param {ASTnode} node AST node - * @param {object} firstToken First token in the expression - * @param {object} secondToken Second token in the expression + * @param {Object} firstToken First token in the expression + * @param {Object} secondToken Second token in the expression * @returns {void} */ function verifyNonWordsDontHaveSpaces(node, firstToken, secondToken) { @@ -241,7 +241,7 @@ module.exports = { * @returns {void} */ function checkForSpaces(node) { - var tokens = sourceCode.getFirstTokens(node, 2), + let tokens = sourceCode.getFirstTokens(node, 2), firstToken = tokens[0], secondToken = tokens[1]; @@ -250,7 +250,7 @@ module.exports = { return; } - var operator = node.prefix ? tokens[0].value : tokens[1].value; + let operator = node.prefix ? tokens[0].value : tokens[1].value; if (overrideExistsForOperator(node, operator)) { if (overrideEnforcesSpaces(node, operator)) { diff --git a/tools/eslint/lib/rules/spaced-comment.js b/tools/eslint/lib/rules/spaced-comment.js index 149862024c2..7141ba1f423 100644 --- a/tools/eslint/lib/rules/spaced-comment.js +++ b/tools/eslint/lib/rules/spaced-comment.js @@ -4,7 +4,7 @@ */ "use strict"; -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers @@ -16,7 +16,7 @@ var lodash = require("lodash"); * @returns {string} An escaped string. */ function escape(s) { - var isOneChar = s.length === 1; + let isOneChar = s.length === 1; s = lodash.escapeRegExp(s); return isOneChar ? s : "(?:" + s + ")"; @@ -50,38 +50,16 @@ function parseMarkersOption(markers) { } /** - * Creates RegExp object for `always` mode. - * Generated pattern is below: + * Creates string pattern for exceptions. + * Generated pattern: * - * 1. First, a marker or nothing. - * 2. Next, a space or an exception pattern sequence. + * 1. A space or an exception pattern sequence. * - * @param {string[]} markers - A marker list. - * @param {string[]} exceptions - A exception pattern list. - * @returns {RegExp} A RegExp object for `always` mode. + * @param {string[]} exceptions - An exception pattern list. + * @returns {string} A regular expression string for exceptions. */ -function createAlwaysStylePattern(markers, exceptions) { - var pattern = "^"; - - /* - * A marker or nothing. - * ["*"] ==> "\*?" - * ["*", "!"] ==> "(?:\*|!)?" - * ["*", "/", "!<"] ==> "(?:\*|\/|(?:!<))?" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5C*%7C%5C%2F%7C(%3F%3A!%3C))%3F - */ - if (markers.length === 1) { - - // the marker. - pattern += escape(markers[0]); - } else { - - // one of markers. - pattern += "(?:"; - pattern += markers.map(escape).join("|"); - pattern += ")"; - } - - pattern += "?"; // or nothing. +function createExceptionsPattern(exceptions) { + let pattern = ""; /* * A space or an exception pattern sequence. @@ -105,21 +83,59 @@ function createAlwaysStylePattern(markers, exceptions) { pattern += escapeAndRepeat(exceptions[0]); } else { - // a sequence of one of exception patterns. + // a sequence of one of the exception patterns. pattern += "(?:"; pattern += exceptions.map(escapeAndRepeat).join("|"); pattern += ")"; } - pattern += "(?:$|[\n\r]))"; // the sequence continues until the end. + pattern += "(?:$|[\n\r]))"; } + return pattern; +} + +/** + * Creates RegExp object for `always` mode. + * Generated pattern for beginning of comment: + * + * 1. First, a marker or nothing. + * 2. Next, a space or an exception pattern sequence. + * + * @param {string[]} markers - A marker list. + * @param {string[]} exceptions - An exception pattern list. + * @returns {RegExp} A RegExp object for the beginning of a comment in `always` mode. + */ +function createAlwaysStylePattern(markers, exceptions) { + let pattern = "^"; + + /* + * A marker or nothing. + * ["*"] ==> "\*?" + * ["*", "!"] ==> "(?:\*|!)?" + * ["*", "/", "!<"] ==> "(?:\*|\/|(?:!<))?" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5C*%7C%5C%2F%7C(%3F%3A!%3C))%3F + */ + if (markers.length === 1) { + + // the marker. + pattern += escape(markers[0]); + } else { + + // one of markers. + pattern += "(?:"; + pattern += markers.map(escape).join("|"); + pattern += ")"; + } + + pattern += "?"; // or nothing. + pattern += createExceptionsPattern(exceptions); + return new RegExp(pattern); } /** * Creates RegExp object for `never` mode. - * Generated pattern is below: + * Generated pattern for beginning of comment: * * 1. First, a marker or nothing (captured). * 2. Next, a space or a tab. @@ -128,7 +144,7 @@ function createAlwaysStylePattern(markers, exceptions) { * @returns {RegExp} A RegExp object for `never` mode. */ function createNeverStylePattern(markers) { - var pattern = "^(" + markers.map(escape).join("|") + ")?[ \t]+"; + let pattern = "^(" + markers.map(escape).join("|") + ")?[ \t]+"; return new RegExp(pattern); } @@ -198,6 +214,9 @@ module.exports = { items: { type: "string" } + }, + balanced: { + type: "boolean" } }, additionalProperties: false @@ -211,21 +230,25 @@ module.exports = { create: function(context) { // Unless the first option is never, require a space - var requireSpace = context.options[0] !== "never"; + let requireSpace = context.options[0] !== "never"; /* * Parse the second options. * If markers don't include `"*"`, it's added automatically for JSDoc * comments. */ - var config = context.options[1] || {}; - var styleRules = ["block", "line"].reduce(function(rule, type) { - var markers = parseMarkersOption(config[type] && config[type].markers || config.markers); - var exceptions = config[type] && config[type].exceptions || config.exceptions || []; + let config = context.options[1] || {}; + let balanced = config.block && config.block.balanced; + + let styleRules = ["block", "line"].reduce(function(rule, type) { + let markers = parseMarkersOption(config[type] && config[type].markers || config.markers); + let exceptions = config[type] && config[type].exceptions || config.exceptions || []; + let endNeverPattern = "[ \t]+$"; // Create RegExp object for valid patterns. rule[type] = { - regex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers), + beginRegex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers), + endRegex: balanced && requireSpace ? new RegExp(createExceptionsPattern(exceptions) + "$") : new RegExp(endNeverPattern), hasExceptions: exceptions.length > 0, markers: new RegExp("^(" + markers.map(escape).join("|") + ")") }; @@ -234,20 +257,20 @@ module.exports = { }, {}); /** - * Reports a spacing error with an appropriate message. + * Reports a beginning spacing error with an appropriate message. * @param {ASTNode} node - A comment node to check. - * @param {string} message - An error message to report + * @param {string} message - An error message to report. * @param {Array} match - An array of match results for markers. * @returns {void} */ - function report(node, message, match) { - var type = node.type.toLowerCase(), + function reportBegin(node, message, match) { + let type = node.type.toLowerCase(), commentIdentifier = type === "block" ? "/*" : "//"; context.report({ node: node, fix: function(fixer) { - var start = node.range[0], + let start = node.range[0], end = start + 2; if (requireSpace) { @@ -264,13 +287,37 @@ module.exports = { }); } + /** + * Reports an ending spacing error with an appropriate message. + * @param {ASTNode} node - A comment node to check. + * @param {string} message - An error message to report. + * @param {string} match - An array of the matched whitespace characters. + * @returns {void} + */ + function reportEnd(node, message, match) { + context.report({ + node: node, + fix: function(fixer) { + if (requireSpace) { + return fixer.insertTextAfterRange([node.start, node.end - 2], " "); + } else { + let end = node.end - 2, + start = end - match[0].length; + + return fixer.replaceTextRange([start, end], ""); + } + }, + message: message + }); + } + /** * Reports a given comment if it's invalid. * @param {ASTNode} node - a comment node to check. * @returns {void} */ function checkCommentForSpace(node) { - var type = node.type.toLowerCase(), + let type = node.type.toLowerCase(), rule = styleRules[type], commentIdentifier = type === "block" ? "/*" : "//"; @@ -279,28 +326,37 @@ module.exports = { return; } + let beginMatch = rule.beginRegex.exec(node.value); + let endMatch = rule.endRegex.exec(node.value); + // Checks. if (requireSpace) { - if (!rule.regex.test(node.value)) { - var hasMarker = rule.markers.exec(node.value); - var marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier; + if (!beginMatch) { + let hasMarker = rule.markers.exec(node.value); + let marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier; if (rule.hasExceptions) { - report(node, "Expected exception block, space or tab after '" + marker + "' in comment.", hasMarker); + reportBegin(node, "Expected exception block, space or tab after '" + marker + "' in comment.", hasMarker); } else { - report(node, "Expected space or tab after '" + marker + "' in comment.", hasMarker); + reportBegin(node, "Expected space or tab after '" + marker + "' in comment.", hasMarker); } } - } else { - var matched = rule.regex.exec(node.value); - if (matched) { - if (!matched[1]) { - report(node, "Unexpected space or tab after '" + commentIdentifier + "' in comment.", matched); + if (balanced && type === "block" && !endMatch) { + reportEnd(node, "Expected space or tab before '*/' in comment."); + } + } else { + if (beginMatch) { + if (!beginMatch[1]) { + reportBegin(node, "Unexpected space or tab after '" + commentIdentifier + "' in comment.", beginMatch); } else { - report(node, "Unexpected space or tab after marker (" + matched[1] + ") in comment.", matched); + reportBegin(node, "Unexpected space or tab after marker (" + beginMatch[1] + ") in comment.", beginMatch); } } + + if (balanced && type === "block" && endMatch) { + reportEnd(node, "Unexpected space or tab before '*/' in comment.", endMatch); + } } } diff --git a/tools/eslint/lib/rules/strict.js b/tools/eslint/lib/rules/strict.js index 45021517c70..5f54b15e799 100644 --- a/tools/eslint/lib/rules/strict.js +++ b/tools/eslint/lib/rules/strict.js @@ -9,13 +9,13 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"); +let lodash = require("lodash"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var messages = { +let messages = { function: "Use the function form of 'use strict'.", global: "Use the global form of 'use strict'.", multiple: "Multiple 'use strict' directives.", @@ -35,7 +35,7 @@ var messages = { * @returns {ASTNode[]} All of the Use Strict Directives. */ function getUseStrictDirectives(statements) { - var directives = [], + let directives = [], i, statement; for (i = 0; i < statements.length; i++) { @@ -96,7 +96,7 @@ module.exports = { create: function(context) { - var mode = context.options[0] || "safe", + let mode = context.options[0] || "safe", ecmaFeatures = context.parserOptions.ecmaFeatures || {}, scopes = [], classScopes = [], @@ -117,7 +117,7 @@ module.exports = { * @returns {void} */ function reportSlice(nodes, start, end, message) { - var i; + let i; for (i = start; i < end; i++) { context.report(nodes[i], message); @@ -152,7 +152,7 @@ module.exports = { * @returns {void} */ function enterFunctionInFunctionMode(node, useStrictDirectives) { - var isInClass = classScopes.length > 0, + let isInClass = classScopes.length > 0, isParentGlobal = scopes.length === 0 && classScopes.length === 0, isParentStrict = scopes.length > 0 && scopes[scopes.length - 1], isStrict = useStrictDirectives.length > 0; @@ -194,7 +194,7 @@ module.exports = { * @returns {void} */ function enterFunction(node) { - var isBlock = node.body.type === "BlockStatement", + let isBlock = node.body.type === "BlockStatement", useStrictDirectives = isBlock ? getUseStrictDirectives(node.body.body) : []; @@ -212,7 +212,7 @@ module.exports = { rule = { Program: function(node) { - var useStrictDirectives = getUseStrictDirectives(node.body); + let useStrictDirectives = getUseStrictDirectives(node.body); if (node.sourceType === "module") { mode = "module"; diff --git a/tools/eslint/lib/rules/template-curly-spacing.js b/tools/eslint/lib/rules/template-curly-spacing.js index 144a0353690..36c33e53309 100644 --- a/tools/eslint/lib/rules/template-curly-spacing.js +++ b/tools/eslint/lib/rules/template-curly-spacing.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var astUtils = require("../ast-utils"); +let astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var OPEN_PAREN = /\$\{$/; -var CLOSE_PAREN = /^\}/; +let OPEN_PAREN = /\$\{$/; +let CLOSE_PAREN = /^\}/; //------------------------------------------------------------------------------ // Rule Definition @@ -38,9 +38,9 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); - var always = context.options[0] === "always"; - var prefix = always ? "Expected" : "Unexpected"; + let sourceCode = context.getSourceCode(); + let always = context.options[0] === "always"; + let prefix = always ? "Expected" : "Unexpected"; /** * Checks spacing before `}` of a given token. @@ -48,7 +48,7 @@ module.exports = { * @returns {void} */ function checkSpacingBefore(token) { - var prevToken = sourceCode.getTokenBefore(token); + let prevToken = sourceCode.getTokenBefore(token); if (prevToken && CLOSE_PAREN.test(token.value) && @@ -77,7 +77,7 @@ module.exports = { * @returns {void} */ function checkSpacingAfter(token) { - var nextToken = sourceCode.getTokenAfter(token); + let nextToken = sourceCode.getTokenAfter(token); if (nextToken && OPEN_PAREN.test(token.value) && @@ -105,7 +105,7 @@ module.exports = { return { TemplateElement: function(node) { - var token = sourceCode.getFirstToken(node); + let token = sourceCode.getFirstToken(node); checkSpacingBefore(token); checkSpacingAfter(token); diff --git a/tools/eslint/lib/rules/unicode-bom.js b/tools/eslint/lib/rules/unicode-bom.js index a152b03ac99..931d840b55c 100644 --- a/tools/eslint/lib/rules/unicode-bom.js +++ b/tools/eslint/lib/rules/unicode-bom.js @@ -35,7 +35,7 @@ module.exports = { Program: function checkUnicodeBOM(node) { - var sourceCode = context.getSourceCode(), + let sourceCode = context.getSourceCode(), location = {column: 0, line: 1}, requireBOM = context.options[0] || "never"; diff --git a/tools/eslint/lib/rules/valid-jsdoc.js b/tools/eslint/lib/rules/valid-jsdoc.js index 65ed539d55f..8af117e30eb 100644 --- a/tools/eslint/lib/rules/valid-jsdoc.js +++ b/tools/eslint/lib/rules/valid-jsdoc.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var doctrine = require("doctrine"); +let doctrine = require("doctrine"); //------------------------------------------------------------------------------ // Rule Definition @@ -61,7 +61,7 @@ module.exports = { create: function(context) { - var options = context.options[0] || {}, + let options = context.options[0] || {}, prefer = options.prefer || {}, sourceCode = context.getSourceCode(), @@ -78,7 +78,7 @@ module.exports = { //-------------------------------------------------------------------------- // Using a stack to store if a function returns or not (handling nested functions) - var fns = []; + let fns = []; /** * Check if node type is a Class @@ -110,7 +110,7 @@ module.exports = { * @private */ function addReturn(node) { - var functionState = fns[fns.length - 1]; + let functionState = fns[fns.length - 1]; if (functionState && node.argument !== null) { functionState.returnPresent = true; @@ -148,8 +148,8 @@ module.exports = { * @private */ function getCurrentExpectedTypes(type) { - var currentType; - var expectedType; + let currentType; + let expectedType; if (type.name) { currentType = type.name; @@ -177,8 +177,8 @@ module.exports = { return; } - var typesToCheck = []; - var elements = []; + let typesToCheck = []; + let elements = []; switch (type.type) { case "TypeApplication": // {Array.} @@ -223,7 +223,7 @@ module.exports = { * @private */ function checkJSDoc(node) { - var jsdocNode = sourceCode.getJSDocComment(node), + let jsdocNode = sourceCode.getJSDocComment(node), functionData = fns.pop(), hasReturns = false, hasConstructor = false, @@ -336,7 +336,7 @@ module.exports = { } // check the parameters - var jsdocParams = Object.keys(params); + let jsdocParams = Object.keys(params); if (node.params) { node.params.forEach(function(param, i) { @@ -344,7 +344,7 @@ module.exports = { param = param.left; } - var name = param.name; + let name = param.name; // TODO(nzakas): Figure out logical things to do with destructured, default, rest params if (param.type === "Identifier") { @@ -363,7 +363,7 @@ module.exports = { } if (options.matchDescription) { - var regex = new RegExp(options.matchDescription); + let regex = new RegExp(options.matchDescription); if (!regex.test(jsdoc.description)) { context.report(jsdocNode, "JSDoc description does not satisfy the regex pattern."); diff --git a/tools/eslint/lib/rules/valid-typeof.js b/tools/eslint/lib/rules/valid-typeof.js index 289375a88ba..dc378d9401d 100644 --- a/tools/eslint/lib/rules/valid-typeof.js +++ b/tools/eslint/lib/rules/valid-typeof.js @@ -21,7 +21,7 @@ module.exports = { create: function(context) { - var VALID_TYPES = ["symbol", "undefined", "object", "boolean", "number", "string", "function"], + let VALID_TYPES = ["symbol", "undefined", "object", "boolean", "number", "string", "function"], OPERATORS = ["==", "===", "!=", "!=="]; //-------------------------------------------------------------------------- @@ -31,7 +31,7 @@ module.exports = { return { UnaryExpression: function(node) { - var parent, sibling; + let parent, sibling; if (node.operator === "typeof") { parent = context.getAncestors().pop(); @@ -40,7 +40,7 @@ module.exports = { sibling = parent.left === node ? parent.right : parent.left; if (sibling.type === "Literal" && VALID_TYPES.indexOf(sibling.value) === -1) { - context.report(sibling, "Invalid typeof comparison value"); + context.report(sibling, "Invalid typeof comparison value."); } } } diff --git a/tools/eslint/lib/rules/vars-on-top.js b/tools/eslint/lib/rules/vars-on-top.js index 25bef0411db..e94e4875593 100644 --- a/tools/eslint/lib/rules/vars-on-top.js +++ b/tools/eslint/lib/rules/vars-on-top.js @@ -21,7 +21,7 @@ module.exports = { }, create: function(context) { - var errorMessage = "All 'var' declarations must be at the top of the function scope."; + let errorMessage = "All 'var' declarations must be at the top of the function scope."; //-------------------------------------------------------------------------- // Helpers @@ -29,7 +29,7 @@ module.exports = { /** * @param {ASTNode} node - any node - * @returns {Boolean} whether the given node structurally represents a directive + * @returns {boolean} whether the given node structurally represents a directive */ function looksLikeDirective(node) { return node.type === "ExpressionStatement" && @@ -39,7 +39,7 @@ module.exports = { /** * Check to see if its a ES6 import declaration * @param {ASTNode} node - any node - * @returns {Boolean} whether the given node represents a import declaration + * @returns {boolean} whether the given node represents a import declaration */ function looksLikeImport(node) { return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" || @@ -67,10 +67,10 @@ module.exports = { * Checks whether this variable is on top of the block body * @param {ASTNode} node - The node to check * @param {ASTNode[]} statements - collection of ASTNodes for the parent node block - * @returns {Boolean} True if var is on top otherwise false + * @returns {boolean} True if var is on top otherwise false */ function isVarOnTop(node, statements) { - var i = 0, + let i = 0, l = statements.length; // skip over directives @@ -125,9 +125,9 @@ module.exports = { return { VariableDeclaration: function(node) { - var ancestors = context.getAncestors(); - var parent = ancestors.pop(); - var grandParent = ancestors.pop(); + let ancestors = context.getAncestors(); + let parent = ancestors.pop(); + let grandParent = ancestors.pop(); if (node.kind === "var") { // check variable is `var` type and not `let` or `const` if (parent.type === "ExportNamedDeclaration") { diff --git a/tools/eslint/lib/rules/wrap-iife.js b/tools/eslint/lib/rules/wrap-iife.js index 2f73699a429..78554091c99 100644 --- a/tools/eslint/lib/rules/wrap-iife.js +++ b/tools/eslint/lib/rules/wrap-iife.js @@ -26,9 +26,9 @@ module.exports = { create: function(context) { - var style = context.options[0] || "outside"; + let style = context.options[0] || "outside"; - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Check if the node is wrapped in () @@ -37,7 +37,7 @@ module.exports = { * @private */ function wrapped(node) { - var previousToken = sourceCode.getTokenBefore(node), + let previousToken = sourceCode.getTokenBefore(node), nextToken = sourceCode.getTokenAfter(node); return previousToken && previousToken.value === "(" && @@ -48,7 +48,7 @@ module.exports = { CallExpression: function(node) { if (node.callee.type === "FunctionExpression") { - var callExpressionWrapped = wrapped(node), + let callExpressionWrapped = wrapped(node), functionExpressionWrapped = wrapped(node.callee); if (!callExpressionWrapped && !functionExpressionWrapped) { diff --git a/tools/eslint/lib/rules/wrap-regex.js b/tools/eslint/lib/rules/wrap-regex.js index 1aed713bdd0..44750a3fbd1 100644 --- a/tools/eslint/lib/rules/wrap-regex.js +++ b/tools/eslint/lib/rules/wrap-regex.js @@ -21,12 +21,12 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); return { Literal: function(node) { - var token = sourceCode.getFirstToken(node), + let token = sourceCode.getFirstToken(node), nodeType = token.type, source, grandparent, diff --git a/tools/eslint/lib/rules/yield-star-spacing.js b/tools/eslint/lib/rules/yield-star-spacing.js index e2911b72005..c9ca64e0c25 100644 --- a/tools/eslint/lib/rules/yield-star-spacing.js +++ b/tools/eslint/lib/rules/yield-star-spacing.js @@ -39,9 +39,9 @@ module.exports = { }, create: function(context) { - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); - var mode = (function(option) { + let mode = (function(option) { if (!option || typeof option === "string") { return { before: { before: true, after: false }, @@ -64,11 +64,11 @@ module.exports = { */ function checkSpacing(side, leftToken, rightToken) { if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken) !== mode[side]) { - var after = leftToken.value === "*"; - var spaceRequired = mode[side]; - var node = after ? leftToken : rightToken; - var type = spaceRequired ? "Missing" : "Unexpected"; - var message = type + " space " + side + " *."; + let after = leftToken.value === "*"; + let spaceRequired = mode[side]; + let node = after ? leftToken : rightToken; + let type = spaceRequired ? "Missing" : "Unexpected"; + let message = type + " space " + side + " *."; context.report({ node: node, @@ -96,10 +96,10 @@ module.exports = { return; } - var tokens = sourceCode.getFirstTokens(node, 3); - var yieldToken = tokens[0]; - var starToken = tokens[1]; - var nextToken = tokens[2]; + let tokens = sourceCode.getFirstTokens(node, 3); + let yieldToken = tokens[0]; + let starToken = tokens[1]; + let nextToken = tokens[2]; checkSpacing("before", yieldToken, starToken); checkSpacing("after", starToken, nextToken); diff --git a/tools/eslint/lib/rules/yoda.js b/tools/eslint/lib/rules/yoda.js index 0373e91a4a9..29f0602b98d 100644 --- a/tools/eslint/lib/rules/yoda.js +++ b/tools/eslint/lib/rules/yoda.js @@ -10,7 +10,7 @@ /** * Determines whether an operator is a comparison operator. - * @param {String} operator The operator to check. + * @param {string} operator The operator to check. * @returns {boolean} Whether or not it is a comparison operator. */ function isComparisonOperator(operator) { @@ -19,7 +19,7 @@ function isComparisonOperator(operator) { /** * Determines whether an operator is an equality operator. - * @param {String} operator The operator to check. + * @param {string} operator The operator to check. * @returns {boolean} Whether or not it is an equality operator. */ function isEqualityOperator(operator) { @@ -29,7 +29,7 @@ function isEqualityOperator(operator) { /** * Determines whether an operator is one used in a range test. * Allowed operators are `<` and `<=`. - * @param {String} operator The operator to check. + * @param {string} operator The operator to check. * @returns {boolean} Whether the operator is used in range tests. */ function isRangeTestOperator(operator) { @@ -147,11 +147,11 @@ module.exports = { create: function(context) { // Default to "never" (!always) if no option - var always = (context.options[0] === "always"); - var exceptRange = (context.options[1] && context.options[1].exceptRange); - var onlyEquality = (context.options[1] && context.options[1].onlyEquality); + let always = (context.options[0] === "always"); + let exceptRange = (context.options[1] && context.options[1].exceptRange); + let onlyEquality = (context.options[1] && context.options[1].onlyEquality); - var sourceCode = context.getSourceCode(); + let sourceCode = context.getSourceCode(); /** * Determines whether node represents a range test. @@ -161,18 +161,18 @@ module.exports = { * must be less than or equal to the literal on the right side so that the * test makes any sense. * @param {ASTNode} node LogicalExpression node to test. - * @returns {Boolean} Whether node is a range test. + * @returns {boolean} Whether node is a range test. */ function isRangeTest(node) { - var left = node.left, + let left = node.left, right = node.right; /** * Determines whether node is of the form `0 <= x && x < 1`. - * @returns {Boolean} Whether node is a "between" range test. + * @returns {boolean} Whether node is a "between" range test. */ function isBetweenTest() { - var leftLiteral, rightLiteral; + let leftLiteral, rightLiteral; return (node.operator === "&&" && (leftLiteral = getNormalizedLiteral(left.left)) && @@ -183,10 +183,10 @@ module.exports = { /** * Determines whether node is of the form `x < 0 || 1 <= x`. - * @returns {Boolean} Whether node is an "outside" range test. + * @returns {boolean} Whether node is an "outside" range test. */ function isOutsideTest() { - var leftLiteral, rightLiteral; + let leftLiteral, rightLiteral; return (node.operator === "||" && (leftLiteral = getNormalizedLiteral(left.right)) && @@ -197,12 +197,12 @@ module.exports = { /** * Determines whether node is wrapped in parentheses. - * @returns {Boolean} Whether node is preceded immediately by an open + * @returns {boolean} Whether node is preceded immediately by an open * paren token and followed immediately by a close * paren token. */ function isParenWrapped() { - var tokenBefore, tokenAfter; + let tokenBefore, tokenAfter; return ((tokenBefore = sourceCode.getTokenBefore(node)) && tokenBefore.value === "(" && diff --git a/tools/eslint/lib/testers/event-generator-tester.js b/tools/eslint/lib/testers/event-generator-tester.js index 00b2d03307a..f77152c0bba 100644 --- a/tools/eslint/lib/testers/event-generator-tester.js +++ b/tools/eslint/lib/testers/event-generator-tester.js @@ -10,7 +10,7 @@ // Requirements //------------------------------------------------------------------------------ -var assert = require("assert"); +let assert = require("assert"); //------------------------------------------------------------------------------ // Public Interface @@ -21,7 +21,7 @@ module.exports = { /** * Overrideable `describe` function to test. * @param {string} text - A description. - * @param {function} method - A test logic. + * @param {Function} method - A test logic. * @returns {any} The returned value with the test logic. */ describe: (typeof describe === "function") ? describe : /* istanbul ignore next */ function(text, method) { @@ -31,7 +31,7 @@ module.exports = { /** * Overrideable `it` function to test. * @param {string} text - A description. - * @param {function} method - A test logic. + * @param {Function} method - A test logic. * @returns {any} The returned value with the test logic. */ it: (typeof it === "function") ? it : /* istanbul ignore next */ function(text, method) { @@ -40,7 +40,7 @@ module.exports = { /** * Does some tests to check a given object implements the EventGenerator interface. - * @param {object} instance - An object to check. + * @param {Object} instance - An object to check. * @returns {void} */ testEventGeneratorInterface: function(instance) { diff --git a/tools/eslint/lib/testers/rule-tester.js b/tools/eslint/lib/testers/rule-tester.js index 2ee87eca6d4..703129ca057 100644 --- a/tools/eslint/lib/testers/rule-tester.js +++ b/tools/eslint/lib/testers/rule-tester.js @@ -40,7 +40,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), assert = require("assert"), util = require("util"), validator = require("../config/config-validator"), @@ -58,14 +58,14 @@ var lodash = require("lodash"), * testerDefaultConfig must not be modified as it allows to reset the tester to * the initial default configuration */ -var testerDefaultConfig = { rules: {} }; -var defaultConfig = { rules: {} }; +let testerDefaultConfig = { rules: {} }; +let defaultConfig = { rules: {} }; /* * List every parameters possible on a test case that are not related to eslint * configuration */ -var RuleTesterParameters = [ +let RuleTesterParameters = [ "code", "filename", "options", @@ -73,9 +73,9 @@ var RuleTesterParameters = [ "errors" ]; -var validateSchema = validate(metaSchema, { verbose: true }); +let validateSchema = validate(metaSchema, { verbose: true }); -var hasOwnProperty = Function.call.bind(Object.hasOwnProperty); +let hasOwnProperty = Function.call.bind(Object.hasOwnProperty); /** * Clones a given value deeply. @@ -90,9 +90,9 @@ function cloneDeeplyExcludesParent(x) { return x.map(cloneDeeplyExcludesParent); } - var retv = {}; + let retv = {}; - for (var key in x) { + for (let key in x) { if (key !== "parent" && hasOwnProperty(x, key)) { retv[key] = cloneDeeplyExcludesParent(x[key]); } @@ -115,7 +115,7 @@ function freezeDeeply(x) { if (Array.isArray(x)) { x.forEach(freezeDeeply); } else { - for (var key in x) { + for (let key in x) { if (key !== "parent" && hasOwnProperty(x, key)) { freezeDeeply(x[key]); } @@ -211,7 +211,7 @@ RuleTester.prototype = { */ run: function(ruleName, rule, test) { - var testerConfig = this.testerConfig, + let testerConfig = this.testerConfig, result = {}; /* eslint-disable no-shadow */ @@ -219,12 +219,12 @@ RuleTester.prototype = { /** * Run the rule for the given item * @param {string} ruleName name of the rule - * @param {string|object} item Item to run the rule against - * @returns {object} Eslint run result + * @param {string|Object} item Item to run the rule against + * @returns {Object} Eslint run result * @private */ function runRuleForItem(ruleName, item) { - var config = lodash.cloneDeep(testerConfig), + let config = lodash.cloneDeep(testerConfig), code, filename, schema, beforeAST, afterAST; if (typeof item === "string") { @@ -234,7 +234,7 @@ RuleTester.prototype = { // Assumes everything on the item is a config except for the // parameters used by this tester - var itemConfig = lodash.omit(item, RuleTesterParameters); + let itemConfig = lodash.omit(item, RuleTesterParameters); // Create the config object from the tester config and this item // specific configurations. @@ -249,7 +249,7 @@ RuleTester.prototype = { } if (item.options) { - var options = item.options.concat(); + let options = item.options.concat(); options.unshift(1); config.rules[ruleName] = options; @@ -290,11 +290,11 @@ RuleTester.prototype = { }); // Freezes rule-context properties. - var originalGet = rules.get; + let originalGet = rules.get; try { rules.get = function(ruleId) { - var rule = originalGet(ruleId); + let rule = originalGet(ruleId); if (typeof rule === "function") { return function(context) { @@ -349,13 +349,13 @@ RuleTester.prototype = { * Check if the template is valid or not * all valid cases go through this * @param {string} ruleName name of the rule - * @param {string|object} item Item to run the rule against + * @param {string|Object} item Item to run the rule against * @returns {void} * @private */ function testValidTemplate(ruleName, item) { - var result = runRuleForItem(ruleName, item); - var messages = result.messages; + let result = runRuleForItem(ruleName, item); + let messages = result.messages; assert.equal(messages.length, 0, util.format("Should have no errors but had %d: %s", messages.length, util.inspect(messages))); @@ -367,7 +367,7 @@ RuleTester.prototype = { * Check if the template is invalid or not * all invalid cases go through this. * @param {string} ruleName name of the rule - * @param {string|object} item Item to run the rule against + * @param {string|Object} item Item to run the rule against * @returns {void} * @private */ @@ -375,8 +375,8 @@ RuleTester.prototype = { assert.ok(item.errors || item.errors === 0, "Did not specify errors for an invalid test of " + ruleName); - var result = runRuleForItem(ruleName, item); - var messages = result.messages; + let result = runRuleForItem(ruleName, item); + let messages = result.messages; @@ -388,14 +388,14 @@ RuleTester.prototype = { util.format("Should have %d error%s but had %d: %s", item.errors.length, item.errors.length === 1 ? "" : "s", messages.length, util.inspect(messages))); - for (var i = 0, l = item.errors.length; i < l; i++) { + for (let i = 0, l = item.errors.length; i < l; i++) { assert.ok(!("fatal" in messages[i]), "A fatal parsing error occurred: " + messages[i].message); assert.equal(messages[i].ruleId, ruleName, "Error rule name should be the same as the name of the rule being tested"); if (typeof item.errors[i] === "string") { // Just an error message. - assert.equal(messages[i].message, item.errors[i], "Error message should be " + item.errors[i]); + assert.equal(messages[i].message, item.errors[i]); } else if (typeof item.errors[i] === "object") { /* @@ -404,7 +404,7 @@ RuleTester.prototype = { * column. */ if (item.errors[i].message) { - assert.equal(messages[i].message, item.errors[i].message, "Error message should be " + item.errors[i].message); + assert.equal(messages[i].message, item.errors[i].message); } if (item.errors[i].type) { @@ -418,6 +418,14 @@ RuleTester.prototype = { if (item.errors[i].hasOwnProperty("column")) { assert.equal(messages[i].column, item.errors[i].column, "Error column should be " + item.errors[i].column); } + + if (item.errors[i].hasOwnProperty("endLine")) { + assert.equal(messages[i].endLine, item.errors[i].endLine, "Error endLine should be " + item.errors[i].endLine); + } + + if (item.errors[i].hasOwnProperty("endColumn")) { + assert.equal(messages[i].endColumn, item.errors[i].endColumn, "Error endColumn should be " + item.errors[i].endColumn); + } } else { // Only string or object errors are valid. @@ -426,7 +434,7 @@ RuleTester.prototype = { } if (item.hasOwnProperty("output")) { - var fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages); + let fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages); assert.equal(fixResult.output, item.output, "Output is incorrect."); } diff --git a/tools/eslint/lib/timing.js b/tools/eslint/lib/timing.js index 6dfffc19d97..ff0dd7ffb27 100644 --- a/tools/eslint/lib/timing.js +++ b/tools/eslint/lib/timing.js @@ -39,23 +39,23 @@ function alignRight(str, len, ch) { // Module definition //------------------------------------------------------------------------------ -var enabled = !!process.env.TIMING; +let enabled = !!process.env.TIMING; -var HEADERS = ["Rule", "Time (ms)", "Relative"]; -var ALIGN = [alignLeft, alignRight, alignRight]; +let HEADERS = ["Rule", "Time (ms)", "Relative"]; +let ALIGN = [alignLeft, alignRight, alignRight]; /* istanbul ignore next */ /** * display the data - * @param {object} data Data object to be displayed + * @param {Object} data Data object to be displayed * @returns {string} modified string * @private */ function display(data) { - var total = 0; - var rows = Object.keys(data) + let total = 0; + let rows = Object.keys(data) .map(function(key) { - var time = data[key]; + let time = data[key]; total += time; return [key, time]; @@ -72,10 +72,10 @@ function display(data) { rows.unshift(HEADERS); - var widths = []; + let widths = []; rows.forEach(function(row) { - var len = row.length, + let len = row.length, i, n; @@ -87,7 +87,7 @@ function display(data) { } }); - var table = rows.map(function(row) { + let table = rows.map(function(row) { return row.map(function(cell, index) { return ALIGN[index](cell, widths[index]); }).join(" | "); @@ -107,7 +107,7 @@ function display(data) { /* istanbul ignore next */ module.exports = (function() { - var data = Object.create(null); + let data = Object.create(null); /** * Time the run @@ -122,7 +122,7 @@ module.exports = (function() { } return function() { - var t = process.hrtime(); + let t = process.hrtime(); fn.apply(null, Array.prototype.slice.call(arguments)); t = process.hrtime(t); diff --git a/tools/eslint/lib/token-store.js b/tools/eslint/lib/token-store.js index 0262b69a521..183c7363ec9 100644 --- a/tools/eslint/lib/token-store.js +++ b/tools/eslint/lib/token-store.js @@ -9,7 +9,7 @@ //------------------------------------------------------------------------------ module.exports = function(tokens) { - var api = {}, + let api = {}, starts = Object.create(null), ends = Object.create(null), index, length, range; @@ -21,7 +21,7 @@ module.exports = function(tokens) { * @returns {Token[]} Tokens in the interval. */ function get(start, end) { - var result = [], + let result = [], i; for (i = Math.max(0, start); i < end && i < length; i++) { @@ -39,7 +39,7 @@ module.exports = function(tokens) { * @returns {int} Index in the tokens array of the node's last token. */ function lastTokenIndex(node) { - var end = node.range[1], + let end = node.range[1], cursor = ends[end]; // If the node extends beyond its last token, get the token before the @@ -73,7 +73,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getTokensBefore = function(node, beforeCount) { - var first = starts[node.range[0]]; + let first = starts[node.range[0]]; return get(first - (beforeCount || 0), first); }; @@ -98,7 +98,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getTokensAfter = function(node, afterCount) { - var start = lastTokenIndex(node) + 1; + let start = lastTokenIndex(node) + 1; return get(start, start + (afterCount || 0)); }; @@ -135,7 +135,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getFirstTokens = function(node, count) { - var first = starts[node.range[0]]; + let first = starts[node.range[0]]; return get( first, @@ -160,7 +160,7 @@ module.exports = function(tokens) { * @returns {Token[]} Array of objects representing tokens. */ api.getLastTokens = function(node, count) { - var last = lastTokenIndex(node) + 1; + let last = lastTokenIndex(node) + 1; return get(Math.max(starts[node.range[0]], last - (count || 0)), last); }; diff --git a/tools/eslint/lib/util/comment-event-generator.js b/tools/eslint/lib/util/comment-event-generator.js index 2989f4ee26a..40771790b7f 100644 --- a/tools/eslint/lib/util/comment-event-generator.js +++ b/tools/eslint/lib/util/comment-event-generator.js @@ -21,7 +21,7 @@ function emitComments(comments, emitter, locs, eventName) { if (comments.length > 0) { comments.forEach(function(node) { - var index = locs.indexOf(node.loc); + let index = locs.indexOf(node.loc); if (index >= 0) { locs.splice(index, 1); @@ -91,7 +91,7 @@ CommentEventGenerator.prototype = { * @returns {void} */ enterNode: function enterNode(node) { - var comments = this.sourceCode.getComments(node); + let comments = this.sourceCode.getComments(node); emitCommentsEnter(this, comments.leading); this.original.enterNode(node); @@ -104,7 +104,7 @@ CommentEventGenerator.prototype = { * @returns {void} */ leaveNode: function leaveNode(node) { - var comments = this.sourceCode.getComments(node); + let comments = this.sourceCode.getComments(node); emitCommentsExit(this, comments.trailing); this.original.leaveNode(node); diff --git a/tools/eslint/lib/util/glob-util.js b/tools/eslint/lib/util/glob-util.js index 1209dabd6a1..30784b2bfc1 100644 --- a/tools/eslint/lib/util/glob-util.js +++ b/tools/eslint/lib/util/glob-util.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug"), +let debug = require("debug"), fs = require("fs"), path = require("path"), glob = require("glob"), @@ -33,7 +33,7 @@ debug = debug("eslint:glob-util"); * * Also makes sure all path separators are POSIX style for `glob` compatibility. * - * @param {object} [options] An options object + * @param {Object} [options] An options object * @param {string[]} [options.extensions=[".js"]] An array of accepted extensions * @param {string} [options.cwd=process.cwd()] The cwd to use to resolve relative pathnames * @returns {Function} A function that takes a pathname and returns a glob that @@ -41,14 +41,14 @@ debug = debug("eslint:glob-util"); * pathname is a directory. */ function processPath(options) { - var cwd = (options && options.cwd) || process.cwd(); - var extensions = (options && options.extensions) || [".js"]; + let cwd = (options && options.cwd) || process.cwd(); + let extensions = (options && options.extensions) || [".js"]; extensions = extensions.map(function(ext) { return ext.charAt(0) === "." ? ext.substr(1) : ext; }); - var suffix = "/**"; + let suffix = "/**"; if (extensions.length === 1) { suffix += "/*." + extensions[0]; @@ -64,8 +64,8 @@ function processPath(options) { * @private */ return function(pathname) { - var newPath = pathname; - var resolvedPath = path.resolve(cwd, pathname); + let newPath = pathname; + let resolvedPath = path.resolve(cwd, pathname); if (shell.test("-d", resolvedPath)) { newPath = pathname.replace(/[\/\\]$/, "") + suffix; @@ -87,7 +87,7 @@ function processPath(options) { */ function resolveFileGlobPatterns(patterns, options) { - var processPathExtensions = processPath(options); + let processPathExtensions = processPath(options); return patterns.map(processPathExtensions); } @@ -105,12 +105,12 @@ function resolveFileGlobPatterns(patterns, options) { * @returns {string[]} Resolved absolute filenames. */ function listFilesToProcess(globPatterns, options) { - var ignoredPaths, + let ignoredPaths, files = [], added = {}, globOptions; - var cwd = (options && options.cwd) || process.cwd(); + let cwd = (options && options.cwd) || process.cwd(); /** * Executes the linter on a file defined by the `filename`. Skips @@ -121,8 +121,8 @@ function listFilesToProcess(globPatterns, options) { * @returns {void} */ function addFile(filename, shouldWarnIgnored) { - var ignored = false; - var isSilentlyIgnored; + let ignored = false; + let isSilentlyIgnored; if (ignoredPaths.contains(filename, "default")) { ignored = (options.ignore !== false) && shouldWarnIgnored; @@ -160,7 +160,7 @@ function listFilesToProcess(globPatterns, options) { debug("Creating list of files to process."); globPatterns.forEach(function(pattern) { - var file = path.resolve(cwd, pattern); + let file = path.resolve(cwd, pattern); if (shell.test("-f", file)) { addFile(fs.realpathSync(file), !shell.test("-d", file)); diff --git a/tools/eslint/lib/util/hash.js b/tools/eslint/lib/util/hash.js index 9f3b734c278..092c56e8633 100644 --- a/tools/eslint/lib/util/hash.js +++ b/tools/eslint/lib/util/hash.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var murmur = require("imurmurhash"); +let murmur = require("imurmurhash"); //------------------------------------------------------------------------------ // Helpers diff --git a/tools/eslint/lib/util/module-resolver.js b/tools/eslint/lib/util/module-resolver.js index 251292280dd..964988ec6eb 100644 --- a/tools/eslint/lib/util/module-resolver.js +++ b/tools/eslint/lib/util/module-resolver.js @@ -9,14 +9,14 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), Module = require("module"); //------------------------------------------------------------------------------ // Private //------------------------------------------------------------------------------ -var DEFAULT_OPTIONS = { +let DEFAULT_OPTIONS = { /* * module.paths is an array of paths to search for resolving things relative @@ -60,7 +60,7 @@ ModuleResolver.prototype = { * subsequent calls to this function. Then, move the extraLookupPath to the * top of the lookup paths list so it will be searched first. */ - var lookupPaths = this.options.lookupPaths.concat(); + let lookupPaths = this.options.lookupPaths.concat(); lookupPaths.unshift(extraLookupPath); @@ -69,7 +69,7 @@ ModuleResolver.prototype = { * lookup file paths when require() is called. So, we are hooking into the * exact same logic that Node.js uses. */ - var result = Module._findPath(name, lookupPaths); // eslint-disable-line no-underscore-dangle + let result = Module._findPath(name, lookupPaths); // eslint-disable-line no-underscore-dangle if (!result) { throw new Error("Cannot find module '" + name + "'"); diff --git a/tools/eslint/lib/util/npm-util.js b/tools/eslint/lib/util/npm-util.js index 9f28dc2b7ed..e888f8feb61 100644 --- a/tools/eslint/lib/util/npm-util.js +++ b/tools/eslint/lib/util/npm-util.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var fs = require("fs"), +let fs = require("fs"), path = require("path"), shell = require("shelljs"), log = require("../logging"); @@ -26,10 +26,10 @@ var fs = require("fs"), * @returns {string} Absolute path to closest package.json file */ function findPackageJson(startDir) { - var dir = path.resolve(startDir || process.cwd()); + let dir = path.resolve(startDir || process.cwd()); do { - var pkgfile = path.join(dir, "package.json"); + let pkgfile = path.join(dir, "package.json"); if (!fs.existsSync(pkgfile)) { dir = path.join(dir, ".."); @@ -68,9 +68,9 @@ function installSyncSaveDev(packages) { * and values are booleans indicating installation. */ function check(packages, opt) { - var deps = []; - var pkgJson = (opt) ? findPackageJson(opt.startDir) : findPackageJson(); - var fileJson; + let deps = []; + let pkgJson = (opt) ? findPackageJson(opt.startDir) : findPackageJson(); + let fileJson; if (!pkgJson) { throw new Error("Could not find a package.json file. Run 'npm init' to create one."); diff --git a/tools/eslint/lib/util/path-util.js b/tools/eslint/lib/util/path-util.js index a199046bb77..8add2064adc 100644 --- a/tools/eslint/lib/util/path-util.js +++ b/tools/eslint/lib/util/path-util.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var path = require("path"); +let path = require("path"); //------------------------------------------------------------------------------ // Private @@ -21,8 +21,8 @@ var path = require("path"); * @returns {string} Converted filepath */ function convertPathToPosix(filepath) { - var normalizedFilepath = path.normalize(filepath); - var posixFilepath = normalizedFilepath.replace(/\\/g, "/"); + let normalizedFilepath = path.normalize(filepath); + let posixFilepath = normalizedFilepath.replace(/\\/g, "/"); return posixFilepath; } @@ -48,7 +48,7 @@ function convertPathToPosix(filepath) { * @returns {string} Relative filepath */ function getRelativePath(filepath, baseDir) { - var relativePath; + let relativePath; if (!path.isAbsolute(filepath)) { filepath = path.resolve(filepath); diff --git a/tools/eslint/lib/util/source-code-fixer.js b/tools/eslint/lib/util/source-code-fixer.js index 042eff591f3..d855edb206b 100644 --- a/tools/eslint/lib/util/source-code-fixer.js +++ b/tools/eslint/lib/util/source-code-fixer.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var debug = require("debug")("eslint:text-fixer"); +let debug = require("debug")("eslint:text-fixer"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var BOM = "\uFEFF"; +let BOM = "\uFEFF"; /** * Compares items in a messages array by line and column. @@ -24,7 +24,7 @@ var BOM = "\uFEFF"; * @private */ function compareMessagesByLocation(a, b) { - var lineDiff = a.line - b.line; + let lineDiff = a.line - b.line; if (lineDiff === 0) { return a.column - b.column; @@ -66,7 +66,7 @@ SourceCodeFixer.applyFixes = function(sourceCode, messages) { } // clone the array - var remainingMessages = [], + let remainingMessages = [], fixes = [], text = sourceCode.text, lastFixPos = text.length + 1, @@ -89,13 +89,13 @@ SourceCodeFixer.applyFixes = function(sourceCode, messages) { }); // split into array of characters for easier manipulation - var chars = text.split(""); + let chars = text.split(""); fixes.forEach(function(problem) { - var fix = problem.fix; - var start = fix.range[0]; - var end = fix.range[1]; - var insertionText = fix.text; + let fix = problem.fix; + let start = fix.range[0]; + let end = fix.range[1]; + let insertionText = fix.text; if (end < lastFixPos) { if (start < 0) { diff --git a/tools/eslint/lib/util/source-code-util.js b/tools/eslint/lib/util/source-code-util.js index e51c1c124c7..f07f61192b9 100644 --- a/tools/eslint/lib/util/source-code-util.js +++ b/tools/eslint/lib/util/source-code-util.js @@ -9,7 +9,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), debug = require("debug"), CLIEngine = require("../cli-engine"), eslint = require("../eslint"), @@ -31,16 +31,16 @@ debug = debug("eslint:source-code-util"); */ function getSourceCodeOfFile(filename, options) { debug("getting sourceCode of", filename); - var opts = lodash.assign({}, options, { rules: {}}); - var cli = new CLIEngine(opts); - var results = cli.executeOnFiles([filename]); + let opts = lodash.assign({}, options, { rules: {}}); + let cli = new CLIEngine(opts); + let results = cli.executeOnFiles([filename]); if (results && results.results[0] && results.results[0].messages[0] && results.results[0].messages[0].fatal) { - var msg = results.results[0].messages[0]; + let msg = results.results[0].messages[0]; throw new Error("(" + filename + ":" + msg.line + ":" + msg.column + ") " + msg.message); } - var sourceCode = eslint.getSourceCode(); + let sourceCode = eslint.getSourceCode(); return sourceCode; } @@ -66,7 +66,7 @@ function getSourceCodeOfFile(filename, options) { * @returns {Object} The SourceCode of all processed files. */ function getSourceCodeOfFiles(patterns, options, cb) { - var sourceCodes = {}, + let sourceCodes = {}, filenames, opts; @@ -94,7 +94,7 @@ function getSourceCodeOfFiles(patterns, options, cb) { debug("Did not find any files matching pattern(s): " + patterns); } filenames.forEach(function(filename) { - var sourceCode = getSourceCodeOfFile(filename, opts); + let sourceCode = getSourceCodeOfFile(filename, opts); if (sourceCode) { debug("got sourceCode of", filename); diff --git a/tools/eslint/lib/util/source-code.js b/tools/eslint/lib/util/source-code.js index adf4df93a6b..b8ed5841cd1 100644 --- a/tools/eslint/lib/util/source-code.js +++ b/tools/eslint/lib/util/source-code.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var lodash = require("lodash"), +let lodash = require("lodash"), createTokenStore = require("../token-store.js"), Traverser = require("./traverser"); @@ -52,7 +52,7 @@ function validate(ast) { function findJSDocComment(comments, line) { if (comments) { - for (var i = comments.length - 1; i >= 0; i--) { + for (let i = comments.length - 1; i >= 0; i--) { if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") { if (line - comments[i].loc.end.line <= 1) { @@ -123,13 +123,13 @@ function SourceCode(text, ast) { }); // create token store methods - var tokenStore = createTokenStore(ast.tokens); + let tokenStore = createTokenStore(ast.tokens); Object.keys(tokenStore).forEach(function(methodName) { this[methodName] = tokenStore[methodName]; }, this); - var tokensAndCommentsStore = createTokenStore(this.tokensAndComments); + let tokensAndCommentsStore = createTokenStore(this.tokensAndComments); this.getTokenOrCommentBefore = tokensAndCommentsStore.getTokenBefore; this.getTokenOrCommentAfter = tokensAndCommentsStore.getTokenAfter; @@ -193,7 +193,7 @@ SourceCode.prototype = { */ getComments: function(node) { - var leadingComments = node.leadingComments || [], + let leadingComments = node.leadingComments || [], trailingComments = node.trailingComments || []; /* @@ -222,7 +222,7 @@ SourceCode.prototype = { */ getJSDocComment: function(node) { - var parent = node.parent; + let parent = node.parent; switch (node.type) { case "ClassDeclaration": @@ -261,7 +261,7 @@ SourceCode.prototype = { * @returns {ASTNode} The node if found or null if not found. */ getNodeByRangeIndex: function(index) { - var result = null, + let result = null, resultParent = null, traverser = new Traverser(); @@ -294,7 +294,7 @@ SourceCode.prototype = { * if there is anything other than whitespace between tokens. */ isSpaceBetweenTokens: function(first, second) { - var text = this.text.slice(first.range[1], second.range[0]); + let text = this.text.slice(first.range[1], second.range[0]); return /\s/.test(text.replace(/\/\*.*?\*\//g, "")); } diff --git a/tools/eslint/lib/util/traverser.js b/tools/eslint/lib/util/traverser.js index 03a1c376e15..b68d0993af3 100644 --- a/tools/eslint/lib/util/traverser.js +++ b/tools/eslint/lib/util/traverser.js @@ -8,13 +8,13 @@ // Requirements //------------------------------------------------------------------------------ -var estraverse = require("estraverse"); +let estraverse = require("estraverse"); //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -var KEY_BLACKLIST = [ +let KEY_BLACKLIST = [ "parent", "leadingComments", "trailingComments" @@ -27,7 +27,7 @@ var KEY_BLACKLIST = [ */ function Traverser() { - var controller = Object.create(new estraverse.Controller()), + let controller = Object.create(new estraverse.Controller()), originalTraverse = controller.traverse; // intercept call to traverse() and add the fallback key to the visitor diff --git a/tools/eslint/lib/util/xml-escape.js b/tools/eslint/lib/util/xml-escape.js new file mode 100644 index 00000000000..2c3abd39d5b --- /dev/null +++ b/tools/eslint/lib/util/xml-escape.js @@ -0,0 +1,34 @@ +/** + * @fileoverview XML character escaper + * @author George Chung + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +/** + * Returns the escaped value for a character + * @param {string} s string to examine + * @returns {string} severity level + * @private + */ +module.exports = function(s) { + return ("" + s).replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/g, function(c) { // eslint-disable-line no-control-regex + switch (c) { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "\"": + return """; + case "'": + return "'"; + default: + return "&#" + c.charCodeAt(0) + ";"; + } + }); +}; diff --git a/tools/eslint/node_modules/acorn-jsx/package.json b/tools/eslint/node_modules/acorn-jsx/package.json index 1982020ad52..ecb4920524a 100644 --- a/tools/eslint/node_modules/acorn-jsx/package.json +++ b/tools/eslint/node_modules/acorn-jsx/package.json @@ -1,7 +1,15 @@ { "_args": [ [ - "acorn-jsx@^3.0.0", + { + "raw": "acorn-jsx@^3.0.0", + "scope": null, + "escapedName": "acorn-jsx", + "name": "acorn-jsx", + "rawSpec": "^3.0.0", + "spec": ">=3.0.0 <4.0.0", + "type": "range" + }, "/Users/trott/io.js/tools/node_modules/espree" ] ], @@ -16,16 +24,17 @@ "tmp": "tmp/acorn-jsx-3.0.1.tgz_1462206645285_0.17844340158626437" }, "_npmUser": { - "email": "me@rreverser.com", - "name": "rreverser" + "name": "rreverser", + "email": "me@rreverser.com" }, "_npmVersion": "3.8.6", "_phantomChildren": {}, "_requested": { - "name": "acorn-jsx", "raw": "acorn-jsx@^3.0.0", - "rawSpec": "^3.0.0", "scope": null, + "escapedName": "acorn-jsx", + "name": "acorn-jsx", + "rawSpec": "^3.0.0", "spec": ">=3.0.0 <4.0.0", "type": "range" }, @@ -58,8 +67,8 @@ "license": "MIT", "maintainers": [ { - "email": "me@rreverser.com", - "name": "rreverser" + "name": "rreverser", + "email": "me@rreverser.com" } ], "name": "acorn-jsx", diff --git a/tools/eslint/node_modules/acorn/AUTHORS b/tools/eslint/node_modules/acorn/AUTHORS index c459c44642f..1b2061cd4b3 100644 --- a/tools/eslint/node_modules/acorn/AUTHORS +++ b/tools/eslint/node_modules/acorn/AUTHORS @@ -1,7 +1,8 @@ --e List of Acorn contributors. Updated before every release. +List of Acorn contributors. Updated before every release. Adrian Rakovsky Alistair Braidwood +Amila Welihinda Andres Suarez Angelo Aparajita Fishman @@ -10,6 +11,7 @@ Artem Govorov Brandon Mills Charles Hughes Conrad Irwin +Daniel Tschinder David Bonnet Domenico Matteo ForbesLindesay @@ -26,6 +28,7 @@ Jordan Klassen Jürg Lehni keeyipchan Keheliya Gallaba +Kevin Irish Kevin Kwok krator Marijn Haverbeke @@ -49,6 +52,7 @@ ReadmeCritic r-e-d Richard Gibson Rich Harris +Rich-Harris Sebastian McKenzie Timothy Gu Toru Nagashima diff --git a/tools/eslint/node_modules/acorn/bin/acorn b/tools/eslint/node_modules/acorn/bin/acorn index 63b7615e359..cf4acd56317 100755 --- a/tools/eslint/node_modules/acorn/bin/acorn +++ b/tools/eslint/node_modules/acorn/bin/acorn @@ -1,71 +1,65 @@ #!/usr/bin/env node -"use strict"; +'use strict'; -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj["default"] = obj; return newObj; } } +var path = require('path'); +var fs = require('fs'); +var acorn = require('../dist/acorn.js'); -var _path = require("path"); - -var _fs = require("fs"); - -var _distAcornJs = require("../dist/acorn.js"); - -var acorn = _interopRequireWildcard(_distAcornJs); - -var infile = undefined, - forceFile = undefined, - silent = false, - compact = false, - tokenize = false; -var options = {}; +var infile; +var forceFile; +var silent = false; +var compact = false; +var tokenize = false; +var options = {} function help(status) { - var print = status == 0 ? console.log : console.error; - print("usage: " + (0, _path.basename)(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7]"); - print(" [--tokenize] [--locations] [---allow-hash-bang] [--compact] [--silent] [--module] [--help] [--] [infile]"); - process.exit(status); + var print = (status == 0) ? console.log : console.error + print("usage: " + path.basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7]") + print(" [--tokenize] [--locations] [---allow-hash-bang] [--compact] [--silent] [--module] [--help] [--] [infile]") + process.exit(status) } for (var i = 2; i < process.argv.length; ++i) { - var arg = process.argv[i]; - if ((arg == "-" || arg[0] != "-") && !infile) infile = arg;else if (arg == "--" && !infile && i + 2 == process.argv.length) forceFile = infile = process.argv[++i];else if (arg == "--ecma3") options.ecmaVersion = 3;else if (arg == "--ecma5") options.ecmaVersion = 5;else if (arg == "--ecma6") options.ecmaVersion = 6;else if (arg == "--ecma7") options.ecmaVersion = 7;else if (arg == "--locations") options.locations = true;else if (arg == "--allow-hash-bang") options.allowHashBang = true;else if (arg == "--silent") silent = true;else if (arg == "--compact") compact = true;else if (arg == "--help") help(0);else if (arg == "--tokenize") tokenize = true;else if (arg == "--module") options.sourceType = 'module';else help(1); + var arg = process.argv[i] + if ((arg == "-" || arg[0] != "-") && !infile) infile = arg + else if (arg == "--" && !infile && i + 2 == process.argv.length) forceFile = infile = process.argv[++i] + else if (arg == "--ecma3") options.ecmaVersion = 3 + else if (arg == "--ecma5") options.ecmaVersion = 5 + else if (arg == "--ecma6") options.ecmaVersion = 6 + else if (arg == "--ecma7") options.ecmaVersion = 7 + else if (arg == "--locations") options.locations = true + else if (arg == "--allow-hash-bang") options.allowHashBang = true + else if (arg == "--silent") silent = true + else if (arg == "--compact") compact = true + else if (arg == "--help") help(0) + else if (arg == "--tokenize") tokenize = true + else if (arg == "--module") options.sourceType = 'module' + else help(1) } function run(code) { - var result = undefined; + var result if (!tokenize) { - try { - result = acorn.parse(code, options); - } catch (e) { - console.error(e.message);process.exit(1); - } + try { result = acorn.parse(code, options) } + catch(e) { console.error(e.message); process.exit(1) } } else { - result = []; - var tokenizer = acorn.tokenizer(code, options), - token = undefined; + result = [] + var tokenizer = acorn.tokenizer(code, options), token while (true) { - try { - token = tokenizer.getToken(); - } catch (e) { - console.error(e.message);process.exit(1); - } - result.push(token); - if (token.type == acorn.tokTypes.eof) break; + try { token = tokenizer.getToken() } + catch(e) { console.error(e.message); process.exit(1) } + result.push(token) + if (token.type == acorn.tokTypes.eof) break } } - if (!silent) console.log(JSON.stringify(result, null, compact ? null : 2)); + if (!silent) console.log(JSON.stringify(result, null, compact ? null : 2)) } if (forceFile || infile && infile != "-") { - run((0, _fs.readFileSync)(infile, "utf8")); + run(fs.readFileSync(infile, "utf8")) } else { - (function () { - var code = ""; - process.stdin.resume(); - process.stdin.on("data", function (chunk) { - return code += chunk; - }); - process.stdin.on("end", function () { - return run(code); - }); - })(); + var code = "" + process.stdin.resume() + process.stdin.on("data", function (chunk) { return code += chunk; }) + process.stdin.on("end", function () { return run(code); }) } \ No newline at end of file diff --git a/tools/eslint/node_modules/acorn/bin/build-acorn.js b/tools/eslint/node_modules/acorn/bin/build-acorn.js deleted file mode 100644 index 71f2cf941f5..00000000000 --- a/tools/eslint/node_modules/acorn/bin/build-acorn.js +++ /dev/null @@ -1,82 +0,0 @@ -var fs = require("fs"), path = require("path") -var stream = require("stream") - -var browserify = require("browserify") -var babel = require('babel-core') -var babelify = require("babelify").configure({loose: "all"}) - -process.chdir(path.resolve(__dirname, "..")) - -browserify({standalone: "acorn"}) - .plugin(require('browserify-derequire')) - .transform(babelify) - .require("./src/index.js", {entry: true}) - .bundle() - .on("error", function (err) { console.log("Error: " + err.message) }) - .pipe(fs.createWriteStream("dist/acorn.js")) - -var ACORN_PLACEHOLDER = "this_function_call_should_be_replaced_with_a_call_to_load_acorn()"; -function acornShimPrepare(file) { - var tr = new stream.Transform - if (file == path.resolve(__dirname, "../src/index.js")) { - var sent = false - tr._transform = function(chunk, _, callback) { - if (!sent) { - sent = true - callback(null, ACORN_PLACEHOLDER); - } else { - callback() - } - } - } else { - tr._transform = function(chunk, _, callback) { callback(null, chunk) } - } - return tr -} -function acornShimComplete() { - var tr = new stream.Transform - var buffer = ""; - tr._transform = function(chunk, _, callback) { - buffer += chunk.toString("utf8"); - callback(); - }; - tr._flush = function (callback) { - tr.push(buffer.replace(ACORN_PLACEHOLDER, "module.exports = typeof acorn != 'undefined' ? acorn : require(\"./acorn\")")); - callback(null); - }; - return tr; -} - -browserify({standalone: "acorn.loose"}) - .plugin(require('browserify-derequire')) - .transform(acornShimPrepare) - .transform(babelify) - .require("./src/loose/index.js", {entry: true}) - .bundle() - .on("error", function (err) { console.log("Error: " + err.message) }) - .pipe(acornShimComplete()) - .pipe(fs.createWriteStream("dist/acorn_loose.js")) - -browserify({standalone: "acorn.walk"}) - .plugin(require('browserify-derequire')) - .transform(acornShimPrepare) - .transform(babelify) - .require("./src/walk/index.js", {entry: true}) - .bundle() - .on("error", function (err) { console.log("Error: " + err.message) }) - .pipe(acornShimComplete()) - .pipe(fs.createWriteStream("dist/walk.js")) - -babel.transformFile("./src/bin/acorn.js", function (err, result) { - if (err) return console.log("Error: " + err.message) - fs.writeFile("bin/acorn", result.code, function (err) { - if (err) return console.log("Error: " + err.message) - - // Make bin/acorn executable - if (process.platform === 'win32') - return - var stat = fs.statSync("bin/acorn") - var newPerm = stat.mode | parseInt('111', 8) - fs.chmodSync("bin/acorn", newPerm) - }) -}) diff --git a/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js b/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js index e9f35510323..100e8cf280f 100644 --- a/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js +++ b/tools/eslint/node_modules/acorn/bin/generate-identifier-regex.js @@ -1,11 +1,13 @@ +'use strict'; + // Which Unicode version should be used? -var version = '8.0.0'; +var version = '9.0.0'; -var start = require('unicode-' + version + '/properties/ID_Start/code-points') - .filter(function(ch) { return ch > 127; }); +var start = require('unicode-' + version + '/Binary_Property/ID_Start/code-points.js') + .filter(function(ch) { return ch > 0x7f; }); var last = -1; -var cont = [0x200c, 0x200d].concat(require('unicode-' + version + '/properties/ID_Continue/code-points') - .filter(function(ch) { return ch > 127 && search(start, ch, last + 1) == -1; })); +var cont = [0x200c, 0x200d].concat(require('unicode-' + version + '/Binary_Property/ID_Continue/code-points.js') + .filter(function(ch) { return ch > 0x7f && search(start, ch, last + 1) == -1; })); function search(arr, ch, starting) { for (var i = starting; arr[i] <= ch && i < arr.length; last = i++) diff --git a/tools/eslint/node_modules/acorn/dist/acorn.es.js b/tools/eslint/node_modules/acorn/dist/acorn.es.js new file mode 100644 index 00000000000..4460957fd78 --- /dev/null +++ b/tools/eslint/node_modules/acorn/dist/acorn.es.js @@ -0,0 +1,3112 @@ +// Reserved word lists for various dialects of the language + +var reservedWords = { + 3: "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile", + 5: "class enum extends super const export import", + 6: "enum", + 7: "enum", + strict: "implements interface let package private protected public static yield", + strictBind: "eval arguments" +} + +// And the keywords + +var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this" + +var keywords = { + 5: ecma5AndLessKeywords, + 6: ecma5AndLessKeywords + " const class extends export import super" +} + +// ## Character categories + +// Big ugly regular expressions that match characters in the +// whitespace, identifier, and identifier-start categories. These +// are only applied when a character is found to actually have a +// code point above 128. +// Generated by `bin/generate-identifier-regex.js`. + +var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc" +var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d4-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d01-\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f" + +var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]") +var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]") + +nonASCIIidentifierStartChars = nonASCIIidentifierChars = null + +// These are a run-length and offset encoded representation of the +// >0xffff code points that are a valid part of identifiers. The +// offset starts at 0x10000, and each pair of numbers represents an +// offset to the next range, and then a size of the range. They were +// generated by bin/generate-identifier-regex.js +var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,17,26,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,785,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,25,391,63,32,0,449,56,264,8,2,36,18,0,50,29,881,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,65,0,32,6124,20,754,9486,1,3071,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,10591,541] +var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,10,2,4,9,83,11,7,0,161,11,6,9,7,3,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,87,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,423,9,838,7,2,7,17,9,57,21,2,13,19882,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239] + +// This has a complexity linear to the value of the code. The +// assumption is that looking up astral identifier characters is +// rare. +function isInAstralSet(code, set) { + var pos = 0x10000 + for (var i = 0; i < set.length; i += 2) { + pos += set[i] + if (pos > code) return false + pos += set[i + 1] + if (pos >= code) return true + } +} + +// Test whether a given character code starts an identifier. + +function isIdentifierStart(code, astral) { + if (code < 65) return code === 36 + if (code < 91) return true + if (code < 97) return code === 95 + if (code < 123) return true + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)) + if (astral === false) return false + return isInAstralSet(code, astralIdentifierStartCodes) +} + +// Test whether a given character is part of an identifier. + +function isIdentifierChar(code, astral) { + if (code < 48) return code === 36 + if (code < 58) return true + if (code < 65) return false + if (code < 91) return true + if (code < 97) return code === 95 + if (code < 123) return true + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)) + if (astral === false) return false + return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes) +} + +// ## Token types + +// The assignment of fine-grained, information-carrying type objects +// allows the tokenizer to store the information it has about a +// token in a way that is very cheap for the parser to look up. + +// All token type variables start with an underscore, to make them +// easy to recognize. + +// The `beforeExpr` property is used to disambiguate between regular +// expressions and divisions. It is set on all token types that can +// be followed by an expression (thus, a slash after them would be a +// regular expression). +// +// The `startsExpr` property is used to check if the token ends a +// `yield` expression. It is set on all token types that either can +// directly start an expression (like a quotation mark) or can +// continue an expression (like the body of a string). +// +// `isLoop` marks a keyword as starting a loop, which is important +// to know when parsing a label, in order to allow or disallow +// continue jumps to that label. + +var TokenType = function TokenType(label, conf) { + if ( conf === void 0 ) conf = {}; + + this.label = label + this.keyword = conf.keyword + this.beforeExpr = !!conf.beforeExpr + this.startsExpr = !!conf.startsExpr + this.isLoop = !!conf.isLoop + this.isAssign = !!conf.isAssign + this.prefix = !!conf.prefix + this.postfix = !!conf.postfix + this.binop = conf.binop || null + this.updateContext = null +}; + +function binop(name, prec) { + return new TokenType(name, {beforeExpr: true, binop: prec}) +} +var beforeExpr = {beforeExpr: true}; +var startsExpr = {startsExpr: true}; +// Map keyword names to token types. + +var keywordTypes = {} + +// Succinct definitions of keyword token types +function kw(name, options) { + if ( options === void 0 ) options = {}; + + options.keyword = name + return keywordTypes[name] = new TokenType(name, options) +} + +var tt = { + num: new TokenType("num", startsExpr), + regexp: new TokenType("regexp", startsExpr), + string: new TokenType("string", startsExpr), + name: new TokenType("name", startsExpr), + eof: new TokenType("eof"), + + // Punctuation token types. + bracketL: new TokenType("[", {beforeExpr: true, startsExpr: true}), + bracketR: new TokenType("]"), + braceL: new TokenType("{", {beforeExpr: true, startsExpr: true}), + braceR: new TokenType("}"), + parenL: new TokenType("(", {beforeExpr: true, startsExpr: true}), + parenR: new TokenType(")"), + comma: new TokenType(",", beforeExpr), + semi: new TokenType(";", beforeExpr), + colon: new TokenType(":", beforeExpr), + dot: new TokenType("."), + question: new TokenType("?", beforeExpr), + arrow: new TokenType("=>", beforeExpr), + template: new TokenType("template"), + ellipsis: new TokenType("...", beforeExpr), + backQuote: new TokenType("`", startsExpr), + dollarBraceL: new TokenType("${", {beforeExpr: true, startsExpr: true}), + + // Operators. These carry several kinds of properties to help the + // parser use them properly (the presence of these properties is + // what categorizes them as operators). + // + // `binop`, when present, specifies that this operator is a binary + // operator, and will refer to its precedence. + // + // `prefix` and `postfix` mark the operator as a prefix or postfix + // unary operator. + // + // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as + // binary operators with a very low precedence, that should result + // in AssignmentExpression nodes. + + eq: new TokenType("=", {beforeExpr: true, isAssign: true}), + assign: new TokenType("_=", {beforeExpr: true, isAssign: true}), + incDec: new TokenType("++/--", {prefix: true, postfix: true, startsExpr: true}), + prefix: new TokenType("prefix", {beforeExpr: true, prefix: true, startsExpr: true}), + logicalOR: binop("||", 1), + logicalAND: binop("&&", 2), + bitwiseOR: binop("|", 3), + bitwiseXOR: binop("^", 4), + bitwiseAND: binop("&", 5), + equality: binop("==/!=", 6), + relational: binop("", 7), + bitShift: binop("<>", 8), + plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}), + modulo: binop("%", 10), + star: binop("*", 10), + slash: binop("/", 10), + starstar: new TokenType("**", {beforeExpr: true}), + + // Keyword token types. + _break: kw("break"), + _case: kw("case", beforeExpr), + _catch: kw("catch"), + _continue: kw("continue"), + _debugger: kw("debugger"), + _default: kw("default", beforeExpr), + _do: kw("do", {isLoop: true, beforeExpr: true}), + _else: kw("else", beforeExpr), + _finally: kw("finally"), + _for: kw("for", {isLoop: true}), + _function: kw("function", startsExpr), + _if: kw("if"), + _return: kw("return", beforeExpr), + _switch: kw("switch"), + _throw: kw("throw", beforeExpr), + _try: kw("try"), + _var: kw("var"), + _const: kw("const"), + _while: kw("while", {isLoop: true}), + _with: kw("with"), + _new: kw("new", {beforeExpr: true, startsExpr: true}), + _this: kw("this", startsExpr), + _super: kw("super", startsExpr), + _class: kw("class"), + _extends: kw("extends", beforeExpr), + _export: kw("export"), + _import: kw("import"), + _null: kw("null", startsExpr), + _true: kw("true", startsExpr), + _false: kw("false", startsExpr), + _in: kw("in", {beforeExpr: true, binop: 7}), + _instanceof: kw("instanceof", {beforeExpr: true, binop: 7}), + _typeof: kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true}), + _void: kw("void", {beforeExpr: true, prefix: true, startsExpr: true}), + _delete: kw("delete", {beforeExpr: true, prefix: true, startsExpr: true}) +} + +// Matches a whole line break (where CRLF is considered a single +// line break). Used to count lines. + +var lineBreak = /\r\n?|\n|\u2028|\u2029/ +var lineBreakG = new RegExp(lineBreak.source, "g") + +function isNewLine(code) { + return code === 10 || code === 13 || code === 0x2028 || code == 0x2029 +} + +var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/ + +var skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g + +function isArray(obj) { + return Object.prototype.toString.call(obj) === "[object Array]" +} + +// Checks if an object has a property. + +function has(obj, propName) { + return Object.prototype.hasOwnProperty.call(obj, propName) +} + +// These are used when `options.locations` is on, for the +// `startLoc` and `endLoc` properties. + +var Position = function Position(line, col) { + this.line = line + this.column = col +}; + +Position.prototype.offset = function offset (n) { + return new Position(this.line, this.column + n) +}; + +var SourceLocation = function SourceLocation(p, start, end) { + this.start = start + this.end = end + if (p.sourceFile !== null) this.source = p.sourceFile +}; + +// The `getLineInfo` function is mostly useful when the +// `locations` option is off (for performance reasons) and you +// want to find the line/column position for a given character +// offset. `input` should be the code string that the offset refers +// into. + +function getLineInfo(input, offset) { + for (var line = 1, cur = 0;;) { + lineBreakG.lastIndex = cur + var match = lineBreakG.exec(input) + if (match && match.index < offset) { + ++line + cur = match.index + match[0].length + } else { + return new Position(line, offset - cur) + } + } +} + +// A second optional argument can be given to further configure +// the parser process. These options are recognized: + +var defaultOptions = { + // `ecmaVersion` indicates the ECMAScript version to parse. Must + // be either 3, or 5, or 6. This influences support for strict + // mode, the set of reserved words, support for getters and + // setters and other features. The default is 6. + ecmaVersion: 6, + // Source type ("script" or "module") for different semantics + sourceType: "script", + // `onInsertedSemicolon` can be a callback that will be called + // when a semicolon is automatically inserted. It will be passed + // th position of the comma as an offset, and if `locations` is + // enabled, it is given the location as a `{line, column}` object + // as second argument. + onInsertedSemicolon: null, + // `onTrailingComma` is similar to `onInsertedSemicolon`, but for + // trailing commas. + onTrailingComma: null, + // By default, reserved words are only enforced if ecmaVersion >= 5. + // Set `allowReserved` to a boolean value to explicitly turn this on + // an off. When this option has the value "never", reserved words + // and keywords can also not be used as property names. + allowReserved: null, + // When enabled, a return at the top level is not considered an + // error. + allowReturnOutsideFunction: false, + // When enabled, import/export statements are not constrained to + // appearing at the top of the program. + allowImportExportEverywhere: false, + // When enabled, hashbang directive in the beginning of file + // is allowed and treated as a line comment. + allowHashBang: false, + // When `locations` is on, `loc` properties holding objects with + // `start` and `end` properties in `{line, column}` form (with + // line being 1-based and column 0-based) will be attached to the + // nodes. + locations: false, + // A function can be passed as `onToken` option, which will + // cause Acorn to call that function with object in the same + // format as tokens returned from `tokenizer().getToken()`. Note + // that you are not allowed to call the parser from the + // callback—that will corrupt its internal state. + onToken: null, + // A function can be passed as `onComment` option, which will + // cause Acorn to call that function with `(block, text, start, + // end)` parameters whenever a comment is skipped. `block` is a + // boolean indicating whether this is a block (`/* */`) comment, + // `text` is the content of the comment, and `start` and `end` are + // character offsets that denote the start and end of the comment. + // When the `locations` option is on, two more parameters are + // passed, the full `{line, column}` locations of the start and + // end of the comments. Note that you are not allowed to call the + // parser from the callback—that will corrupt its internal state. + onComment: null, + // Nodes have their start and end characters offsets recorded in + // `start` and `end` properties (directly on the node, rather than + // the `loc` object, which holds line/column data. To also add a + // [semi-standardized][range] `range` property holding a `[start, + // end]` array with the same numbers, set the `ranges` option to + // `true`. + // + // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 + ranges: false, + // It is possible to parse multiple files into a single AST by + // passing the tree produced by parsing the first file as + // `program` option in subsequent parses. This will add the + // toplevel forms of the parsed file to the `Program` (top) node + // of an existing parse tree. + program: null, + // When `locations` is on, you can pass this to record the source + // file in every node's `loc` object. + sourceFile: null, + // This value, if given, is stored in every node, whether + // `locations` is on or off. + directSourceFile: null, + // When enabled, parenthesized expressions are represented by + // (non-standard) ParenthesizedExpression nodes + preserveParens: false, + plugins: {} +} + +// Interpret and default an options object + +function getOptions(opts) { + var options = {} + for (var opt in defaultOptions) + options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt] + if (options.allowReserved == null) + options.allowReserved = options.ecmaVersion < 5 + + if (isArray(options.onToken)) { + var tokens = options.onToken + options.onToken = function (token) { return tokens.push(token); } + } + if (isArray(options.onComment)) + options.onComment = pushComment(options, options.onComment) + + return options +} + +function pushComment(options, array) { + return function (block, text, start, end, startLoc, endLoc) { + var comment = { + type: block ? 'Block' : 'Line', + value: text, + start: start, + end: end + } + if (options.locations) + comment.loc = new SourceLocation(this, startLoc, endLoc) + if (options.ranges) + comment.range = [start, end] + array.push(comment) + } +} + +// Registered plugins +var plugins = {} + +function keywordRegexp(words) { + return new RegExp("^(" + words.replace(/ /g, "|") + ")$") +} + +var Parser = function Parser(options, input, startPos) { + this.options = options = getOptions(options) + this.sourceFile = options.sourceFile + this.keywords = keywordRegexp(keywords[options.ecmaVersion >= 6 ? 6 : 5]) + var reserved = options.allowReserved ? "" : + reservedWords[options.ecmaVersion] + (options.sourceType == "module" ? " await" : "") + this.reservedWords = keywordRegexp(reserved) + var reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict + this.reservedWordsStrict = keywordRegexp(reservedStrict) + this.reservedWordsStrictBind = keywordRegexp(reservedStrict + " " + reservedWords.strictBind) + this.input = String(input) + + // Used to signal to callers of `readWord1` whether the word + // contained any escape sequences. This is needed because words with + // escape sequences must not be interpreted as keywords. + this.containsEsc = false + + // Load plugins + this.loadPlugins(options.plugins) + + // Set up token state + + // The current position of the tokenizer in the input. + if (startPos) { + this.pos = startPos + this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos)) + this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length + } else { + this.pos = this.lineStart = 0 + this.curLine = 1 + } + + // Properties of the current token: + // Its type + this.type = tt.eof + // For tokens that include more information than their type, the value + this.value = null + // Its start and end offset + this.start = this.end = this.pos + // And, if locations are used, the {line, column} object + // corresponding to those offsets + this.startLoc = this.endLoc = this.curPosition() + + // Position information for the previous token + this.lastTokEndLoc = this.lastTokStartLoc = null + this.lastTokStart = this.lastTokEnd = this.pos + + // The context stack is used to superficially track syntactic + // context to predict whether a regular expression is allowed in a + // given position. + this.context = this.initialContext() + this.exprAllowed = true + + // Figure out if it's a module code. + this.strict = this.inModule = options.sourceType === "module" + + // Used to signify the start of a potential arrow function + this.potentialArrowAt = -1 + + // Flags to track whether we are in a function, a generator. + this.inFunction = this.inGenerator = false + // Labels in scope. + this.labels = [] + + // If enabled, skip leading hashbang line. + if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === '#!') + this.skipLineComment(2) +}; + +// DEPRECATED Kept for backwards compatibility until 3.0 in case a plugin uses them +Parser.prototype.isKeyword = function isKeyword (word) { return this.keywords.test(word) }; +Parser.prototype.isReservedWord = function isReservedWord (word) { return this.reservedWords.test(word) }; + +Parser.prototype.extend = function extend (name, f) { + this[name] = f(this[name]) +}; + +Parser.prototype.loadPlugins = function loadPlugins (pluginConfigs) { + var this$1 = this; + + for (var name in pluginConfigs) { + var plugin = plugins[name] + if (!plugin) throw new Error("Plugin '" + name + "' not found") + plugin(this$1, pluginConfigs[name]) + } +}; + +Parser.prototype.parse = function parse () { + var node = this.options.program || this.startNode() + this.nextToken() + return this.parseTopLevel(node) +}; + +var pp = Parser.prototype + +// ## Parser utilities + +// Test whether a statement node is the string literal `"use strict"`. + +pp.isUseStrict = function(stmt) { + return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && + stmt.expression.type === "Literal" && + stmt.expression.raw.slice(1, -1) === "use strict" +} + +// Predicate that tests whether the next token is of the given +// type, and if yes, consumes it as a side effect. + +pp.eat = function(type) { + if (this.type === type) { + this.next() + return true + } else { + return false + } +} + +// Tests whether parsed token is a contextual keyword. + +pp.isContextual = function(name) { + return this.type === tt.name && this.value === name +} + +// Consumes contextual keyword if possible. + +pp.eatContextual = function(name) { + return this.value === name && this.eat(tt.name) +} + +// Asserts that following token is given contextual keyword. + +pp.expectContextual = function(name) { + if (!this.eatContextual(name)) this.unexpected() +} + +// Test whether a semicolon can be inserted at the current position. + +pp.canInsertSemicolon = function() { + return this.type === tt.eof || + this.type === tt.braceR || + lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) +} + +pp.insertSemicolon = function() { + if (this.canInsertSemicolon()) { + if (this.options.onInsertedSemicolon) + this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc) + return true + } +} + +// Consume a semicolon, or, failing that, see if we are allowed to +// pretend that there is a semicolon at this position. + +pp.semicolon = function() { + if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected() +} + +pp.afterTrailingComma = function(tokType) { + if (this.type == tokType) { + if (this.options.onTrailingComma) + this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc) + this.next() + return true + } +} + +// Expect a token of a given type. If found, consume it, otherwise, +// raise an unexpected token error. + +pp.expect = function(type) { + this.eat(type) || this.unexpected() +} + +// Raise an unexpected token error. + +pp.unexpected = function(pos) { + this.raise(pos != null ? pos : this.start, "Unexpected token") +} + +var DestructuringErrors = function DestructuringErrors() { + this.shorthandAssign = 0 + this.trailingComma = 0 +}; + +pp.checkPatternErrors = function(refDestructuringErrors, andThrow) { + var trailing = refDestructuringErrors && refDestructuringErrors.trailingComma + if (!andThrow) return !!trailing + if (trailing) this.raise(trailing, "Comma is not permitted after the rest element") +} + +pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) { + var pos = refDestructuringErrors && refDestructuringErrors.shorthandAssign + if (!andThrow) return !!pos + if (pos) this.raise(pos, "Shorthand property assignments are valid only in destructuring patterns") +} + +var pp$1 = Parser.prototype + +// ### Statement parsing + +// Parse a program. Initializes the parser, reads any number of +// statements, and wraps them in a Program node. Optionally takes a +// `program` argument. If present, the statements will be appended +// to its body instead of creating a new node. + +pp$1.parseTopLevel = function(node) { + var this$1 = this; + + var first = true + if (!node.body) node.body = [] + while (this.type !== tt.eof) { + var stmt = this$1.parseStatement(true, true) + node.body.push(stmt) + if (first) { + if (this$1.isUseStrict(stmt)) this$1.setStrict(true) + first = false + } + } + this.next() + if (this.options.ecmaVersion >= 6) { + node.sourceType = this.options.sourceType + } + return this.finishNode(node, "Program") +} + +var loopLabel = {kind: "loop"}; +var switchLabel = {kind: "switch"}; +pp$1.isLet = function() { + if (this.type !== tt.name || this.options.ecmaVersion < 6 || this.value != "let") return false + skipWhiteSpace.lastIndex = this.pos + var skip = skipWhiteSpace.exec(this.input) + var next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next) + if (nextCh === 91 || nextCh == 123) return true // '{' and '[' + if (isIdentifierStart(nextCh, true)) { + for (var pos = next + 1; isIdentifierChar(this.input.charCodeAt(pos), true); ++pos) {} + var ident = this.input.slice(next, pos) + if (!this.isKeyword(ident)) return true + } + return false +} + +// Parse a single statement. +// +// If expecting a statement and finding a slash operator, parse a +// regular expression literal. This is to handle cases like +// `if (foo) /blah/.exec(foo)`, where looking at the previous token +// does not help. + +pp$1.parseStatement = function(declaration, topLevel) { + var starttype = this.type, node = this.startNode(), kind + + if (this.isLet()) { + starttype = tt._var + kind = "let" + } + + // Most types of statements are recognized by the keyword they + // start with. Many are trivial to parse, some require a bit of + // complexity. + + switch (starttype) { + case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword) + case tt._debugger: return this.parseDebuggerStatement(node) + case tt._do: return this.parseDoStatement(node) + case tt._for: return this.parseForStatement(node) + case tt._function: + if (!declaration && this.options.ecmaVersion >= 6) this.unexpected() + return this.parseFunctionStatement(node) + case tt._class: + if (!declaration) this.unexpected() + return this.parseClass(node, true) + case tt._if: return this.parseIfStatement(node) + case tt._return: return this.parseReturnStatement(node) + case tt._switch: return this.parseSwitchStatement(node) + case tt._throw: return this.parseThrowStatement(node) + case tt._try: return this.parseTryStatement(node) + case tt._const: case tt._var: + kind = kind || this.value + if (!declaration && kind != "var") this.unexpected() + return this.parseVarStatement(node, kind) + case tt._while: return this.parseWhileStatement(node) + case tt._with: return this.parseWithStatement(node) + case tt.braceL: return this.parseBlock() + case tt.semi: return this.parseEmptyStatement(node) + case tt._export: + case tt._import: + if (!this.options.allowImportExportEverywhere) { + if (!topLevel) + this.raise(this.start, "'import' and 'export' may only appear at the top level") + if (!this.inModule) + this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'") + } + return starttype === tt._import ? this.parseImport(node) : this.parseExport(node) + + // If the statement does not start with a statement keyword or a + // brace, it's an ExpressionStatement or LabeledStatement. We + // simply start parsing an expression, and afterwards, if the + // next token is a colon and the expression was a simple + // Identifier node, we switch to interpreting it as a label. + default: + var maybeName = this.value, expr = this.parseExpression() + if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) + return this.parseLabeledStatement(node, maybeName, expr) + else return this.parseExpressionStatement(node, expr) + } +} + +pp$1.parseBreakContinueStatement = function(node, keyword) { + var this$1 = this; + + var isBreak = keyword == "break" + this.next() + if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null + else if (this.type !== tt.name) this.unexpected() + else { + node.label = this.parseIdent() + this.semicolon() + } + + // Verify that there is an actual destination to break or + // continue to. + for (var i = 0; i < this.labels.length; ++i) { + var lab = this$1.labels[i] + if (node.label == null || lab.name === node.label.name) { + if (lab.kind != null && (isBreak || lab.kind === "loop")) break + if (node.label && isBreak) break + } + } + if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword) + return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") +} + +pp$1.parseDebuggerStatement = function(node) { + this.next() + this.semicolon() + return this.finishNode(node, "DebuggerStatement") +} + +pp$1.parseDoStatement = function(node) { + this.next() + this.labels.push(loopLabel) + node.body = this.parseStatement(false) + this.labels.pop() + this.expect(tt._while) + node.test = this.parseParenExpression() + if (this.options.ecmaVersion >= 6) + this.eat(tt.semi) + else + this.semicolon() + return this.finishNode(node, "DoWhileStatement") +} + +// Disambiguating between a `for` and a `for`/`in` or `for`/`of` +// loop is non-trivial. Basically, we have to parse the init `var` +// statement or expression, disallowing the `in` operator (see +// the second parameter to `parseExpression`), and then check +// whether the next token is `in` or `of`. When there is no init +// part (semicolon immediately after the opening parenthesis), it +// is a regular `for` loop. + +pp$1.parseForStatement = function(node) { + this.next() + this.labels.push(loopLabel) + this.expect(tt.parenL) + if (this.type === tt.semi) return this.parseFor(node, null) + var isLet = this.isLet() + if (this.type === tt._var || this.type === tt._const || isLet) { + var init$1 = this.startNode(), kind = isLet ? "let" : this.value + this.next() + this.parseVar(init$1, true, kind) + this.finishNode(init$1, "VariableDeclaration") + if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init$1.declarations.length === 1 && + !(kind !== "var" && init$1.declarations[0].init)) + return this.parseForIn(node, init$1) + return this.parseFor(node, init$1) + } + var refDestructuringErrors = new DestructuringErrors + var init = this.parseExpression(true, refDestructuringErrors) + if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) { + this.checkPatternErrors(refDestructuringErrors, true) + this.toAssignable(init) + this.checkLVal(init) + return this.parseForIn(node, init) + } else { + this.checkExpressionErrors(refDestructuringErrors, true) + } + return this.parseFor(node, init) +} + +pp$1.parseFunctionStatement = function(node) { + this.next() + return this.parseFunction(node, true) +} + +pp$1.parseIfStatement = function(node) { + this.next() + node.test = this.parseParenExpression() + node.consequent = this.parseStatement(false) + node.alternate = this.eat(tt._else) ? this.parseStatement(false) : null + return this.finishNode(node, "IfStatement") +} + +pp$1.parseReturnStatement = function(node) { + if (!this.inFunction && !this.options.allowReturnOutsideFunction) + this.raise(this.start, "'return' outside of function") + this.next() + + // In `return` (and `break`/`continue`), the keywords with + // optional arguments, we eagerly look for a semicolon or the + // possibility to insert one. + + if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null + else { node.argument = this.parseExpression(); this.semicolon() } + return this.finishNode(node, "ReturnStatement") +} + +pp$1.parseSwitchStatement = function(node) { + var this$1 = this; + + this.next() + node.discriminant = this.parseParenExpression() + node.cases = [] + this.expect(tt.braceL) + this.labels.push(switchLabel) + + // Statements under must be grouped (by label) in SwitchCase + // nodes. `cur` is used to keep the node that we are currently + // adding statements to. + + for (var cur, sawDefault = false; this.type != tt.braceR;) { + if (this$1.type === tt._case || this$1.type === tt._default) { + var isCase = this$1.type === tt._case + if (cur) this$1.finishNode(cur, "SwitchCase") + node.cases.push(cur = this$1.startNode()) + cur.consequent = [] + this$1.next() + if (isCase) { + cur.test = this$1.parseExpression() + } else { + if (sawDefault) this$1.raiseRecoverable(this$1.lastTokStart, "Multiple default clauses") + sawDefault = true + cur.test = null + } + this$1.expect(tt.colon) + } else { + if (!cur) this$1.unexpected() + cur.consequent.push(this$1.parseStatement(true)) + } + } + if (cur) this.finishNode(cur, "SwitchCase") + this.next() // Closing brace + this.labels.pop() + return this.finishNode(node, "SwitchStatement") +} + +pp$1.parseThrowStatement = function(node) { + this.next() + if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) + this.raise(this.lastTokEnd, "Illegal newline after throw") + node.argument = this.parseExpression() + this.semicolon() + return this.finishNode(node, "ThrowStatement") +} + +// Reused empty array added for node fields that are always empty. + +var empty = [] + +pp$1.parseTryStatement = function(node) { + this.next() + node.block = this.parseBlock() + node.handler = null + if (this.type === tt._catch) { + var clause = this.startNode() + this.next() + this.expect(tt.parenL) + clause.param = this.parseBindingAtom() + this.checkLVal(clause.param, true) + this.expect(tt.parenR) + clause.body = this.parseBlock() + node.handler = this.finishNode(clause, "CatchClause") + } + node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null + if (!node.handler && !node.finalizer) + this.raise(node.start, "Missing catch or finally clause") + return this.finishNode(node, "TryStatement") +} + +pp$1.parseVarStatement = function(node, kind) { + this.next() + this.parseVar(node, false, kind) + this.semicolon() + return this.finishNode(node, "VariableDeclaration") +} + +pp$1.parseWhileStatement = function(node) { + this.next() + node.test = this.parseParenExpression() + this.labels.push(loopLabel) + node.body = this.parseStatement(false) + this.labels.pop() + return this.finishNode(node, "WhileStatement") +} + +pp$1.parseWithStatement = function(node) { + if (this.strict) this.raise(this.start, "'with' in strict mode") + this.next() + node.object = this.parseParenExpression() + node.body = this.parseStatement(false) + return this.finishNode(node, "WithStatement") +} + +pp$1.parseEmptyStatement = function(node) { + this.next() + return this.finishNode(node, "EmptyStatement") +} + +pp$1.parseLabeledStatement = function(node, maybeName, expr) { + var this$1 = this; + + for (var i = 0; i < this.labels.length; ++i) + if (this$1.labels[i].name === maybeName) this$1.raise(expr.start, "Label '" + maybeName + "' is already declared") + var kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null + for (var i$1 = this.labels.length - 1; i$1 >= 0; i$1--) { + var label = this$1.labels[i$1] + if (label.statementStart == node.start) { + label.statementStart = this$1.start + label.kind = kind + } else break + } + this.labels.push({name: maybeName, kind: kind, statementStart: this.start}) + node.body = this.parseStatement(true) + this.labels.pop() + node.label = expr + return this.finishNode(node, "LabeledStatement") +} + +pp$1.parseExpressionStatement = function(node, expr) { + node.expression = expr + this.semicolon() + return this.finishNode(node, "ExpressionStatement") +} + +// Parse a semicolon-enclosed block of statements, handling `"use +// strict"` declarations when `allowStrict` is true (used for +// function bodies). + +pp$1.parseBlock = function(allowStrict) { + var this$1 = this; + + var node = this.startNode(), first = true, oldStrict + node.body = [] + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + var stmt = this$1.parseStatement(true) + node.body.push(stmt) + if (first && allowStrict && this$1.isUseStrict(stmt)) { + oldStrict = this$1.strict + this$1.setStrict(this$1.strict = true) + } + first = false + } + if (oldStrict === false) this.setStrict(false) + return this.finishNode(node, "BlockStatement") +} + +// Parse a regular `for` loop. The disambiguation code in +// `parseStatement` will already have parsed the init statement or +// expression. + +pp$1.parseFor = function(node, init) { + node.init = init + this.expect(tt.semi) + node.test = this.type === tt.semi ? null : this.parseExpression() + this.expect(tt.semi) + node.update = this.type === tt.parenR ? null : this.parseExpression() + this.expect(tt.parenR) + node.body = this.parseStatement(false) + this.labels.pop() + return this.finishNode(node, "ForStatement") +} + +// Parse a `for`/`in` and `for`/`of` loop, which are almost +// same from parser's perspective. + +pp$1.parseForIn = function(node, init) { + var type = this.type === tt._in ? "ForInStatement" : "ForOfStatement" + this.next() + node.left = init + node.right = this.parseExpression() + this.expect(tt.parenR) + node.body = this.parseStatement(false) + this.labels.pop() + return this.finishNode(node, type) +} + +// Parse a list of variable declarations. + +pp$1.parseVar = function(node, isFor, kind) { + var this$1 = this; + + node.declarations = [] + node.kind = kind + for (;;) { + var decl = this$1.startNode() + this$1.parseVarId(decl) + if (this$1.eat(tt.eq)) { + decl.init = this$1.parseMaybeAssign(isFor) + } else if (kind === "const" && !(this$1.type === tt._in || (this$1.options.ecmaVersion >= 6 && this$1.isContextual("of")))) { + this$1.unexpected() + } else if (decl.id.type != "Identifier" && !(isFor && (this$1.type === tt._in || this$1.isContextual("of")))) { + this$1.raise(this$1.lastTokEnd, "Complex binding patterns require an initialization value") + } else { + decl.init = null + } + node.declarations.push(this$1.finishNode(decl, "VariableDeclarator")) + if (!this$1.eat(tt.comma)) break + } + return node +} + +pp$1.parseVarId = function(decl) { + decl.id = this.parseBindingAtom() + this.checkLVal(decl.id, true) +} + +// Parse a function declaration or literal (depending on the +// `isStatement` parameter). + +pp$1.parseFunction = function(node, isStatement, allowExpressionBody) { + this.initFunction(node) + if (this.options.ecmaVersion >= 6) + node.generator = this.eat(tt.star) + var oldInGen = this.inGenerator + this.inGenerator = node.generator + if (isStatement || this.type === tt.name) + node.id = this.parseIdent() + this.parseFunctionParams(node) + this.parseFunctionBody(node, allowExpressionBody) + this.inGenerator = oldInGen + return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") +} + +pp$1.parseFunctionParams = function(node) { + this.expect(tt.parenL) + node.params = this.parseBindingList(tt.parenR, false, false, true) +} + +// Parse a class declaration or literal (depending on the +// `isStatement` parameter). + +pp$1.parseClass = function(node, isStatement) { + var this$1 = this; + + this.next() + this.parseClassId(node, isStatement) + this.parseClassSuper(node) + var classBody = this.startNode() + var hadConstructor = false + classBody.body = [] + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (this$1.eat(tt.semi)) continue + var method = this$1.startNode() + var isGenerator = this$1.eat(tt.star) + var isMaybeStatic = this$1.type === tt.name && this$1.value === "static" + this$1.parsePropertyName(method) + method.static = isMaybeStatic && this$1.type !== tt.parenL + if (method.static) { + if (isGenerator) this$1.unexpected() + isGenerator = this$1.eat(tt.star) + this$1.parsePropertyName(method) + } + method.kind = "method" + var isGetSet = false + if (!method.computed) { + var key = method.key; + if (!isGenerator && key.type === "Identifier" && this$1.type !== tt.parenL && (key.name === "get" || key.name === "set")) { + isGetSet = true + method.kind = key.name + key = this$1.parsePropertyName(method) + } + if (!method.static && (key.type === "Identifier" && key.name === "constructor" || + key.type === "Literal" && key.value === "constructor")) { + if (hadConstructor) this$1.raise(key.start, "Duplicate constructor in the same class") + if (isGetSet) this$1.raise(key.start, "Constructor can't have get/set modifier") + if (isGenerator) this$1.raise(key.start, "Constructor can't be a generator") + method.kind = "constructor" + hadConstructor = true + } + } + this$1.parseClassMethod(classBody, method, isGenerator) + if (isGetSet) { + var paramCount = method.kind === "get" ? 0 : 1 + if (method.value.params.length !== paramCount) { + var start = method.value.start + if (method.kind === "get") + this$1.raiseRecoverable(start, "getter should have no params") + else + this$1.raiseRecoverable(start, "setter should have exactly one param") + } + if (method.kind === "set" && method.value.params[0].type === "RestElement") + this$1.raise(method.value.params[0].start, "Setter cannot use rest params") + } + } + node.body = this.finishNode(classBody, "ClassBody") + return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") +} + +pp$1.parseClassMethod = function(classBody, method, isGenerator) { + method.value = this.parseMethod(isGenerator) + classBody.body.push(this.finishNode(method, "MethodDefinition")) +} + +pp$1.parseClassId = function(node, isStatement) { + node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null +} + +pp$1.parseClassSuper = function(node) { + node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null +} + +// Parses module export declaration. + +pp$1.parseExport = function(node) { + var this$1 = this; + + this.next() + // export * from '...' + if (this.eat(tt.star)) { + this.expectContextual("from") + node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() + this.semicolon() + return this.finishNode(node, "ExportAllDeclaration") + } + if (this.eat(tt._default)) { // export default ... + var parens = this.type == tt.parenL + var expr = this.parseMaybeAssign() + var needsSemi = true + if (!parens && (expr.type == "FunctionExpression" || + expr.type == "ClassExpression")) { + needsSemi = false + if (expr.id) { + expr.type = expr.type == "FunctionExpression" + ? "FunctionDeclaration" + : "ClassDeclaration" + } + } + node.declaration = expr + if (needsSemi) this.semicolon() + return this.finishNode(node, "ExportDefaultDeclaration") + } + // export var|const|let|function|class ... + if (this.shouldParseExportStatement()) { + node.declaration = this.parseStatement(true) + node.specifiers = [] + node.source = null + } else { // export { x, y as z } [from '...'] + node.declaration = null + node.specifiers = this.parseExportSpecifiers() + if (this.eatContextual("from")) { + node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() + } else { + // check for keywords used as local names + for (var i = 0; i < node.specifiers.length; i++) { + if (this$1.keywords.test(node.specifiers[i].local.name) || this$1.reservedWords.test(node.specifiers[i].local.name)) { + this$1.unexpected(node.specifiers[i].local.start) + } + } + + node.source = null + } + this.semicolon() + } + return this.finishNode(node, "ExportNamedDeclaration") +} + +pp$1.shouldParseExportStatement = function() { + return this.type.keyword || this.isLet() +} + +// Parses a comma-separated list of module exports. + +pp$1.parseExportSpecifiers = function() { + var this$1 = this; + + var nodes = [], first = true + // export { x, y as z } [from '...'] + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (!first) { + this$1.expect(tt.comma) + if (this$1.afterTrailingComma(tt.braceR)) break + } else first = false + + var node = this$1.startNode() + node.local = this$1.parseIdent(this$1.type === tt._default) + node.exported = this$1.eatContextual("as") ? this$1.parseIdent(true) : node.local + nodes.push(this$1.finishNode(node, "ExportSpecifier")) + } + return nodes +} + +// Parses import declaration. + +pp$1.parseImport = function(node) { + this.next() + // import '...' + if (this.type === tt.string) { + node.specifiers = empty + node.source = this.parseExprAtom() + } else { + node.specifiers = this.parseImportSpecifiers() + this.expectContextual("from") + node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() + } + this.semicolon() + return this.finishNode(node, "ImportDeclaration") +} + +// Parses a comma-separated list of module imports. + +pp$1.parseImportSpecifiers = function() { + var this$1 = this; + + var nodes = [], first = true + if (this.type === tt.name) { + // import defaultObj, { x, y as z } from '...' + var node = this.startNode() + node.local = this.parseIdent() + this.checkLVal(node.local, true) + nodes.push(this.finishNode(node, "ImportDefaultSpecifier")) + if (!this.eat(tt.comma)) return nodes + } + if (this.type === tt.star) { + var node$1 = this.startNode() + this.next() + this.expectContextual("as") + node$1.local = this.parseIdent() + this.checkLVal(node$1.local, true) + nodes.push(this.finishNode(node$1, "ImportNamespaceSpecifier")) + return nodes + } + this.expect(tt.braceL) + while (!this.eat(tt.braceR)) { + if (!first) { + this$1.expect(tt.comma) + if (this$1.afterTrailingComma(tt.braceR)) break + } else first = false + + var node$2 = this$1.startNode() + node$2.imported = this$1.parseIdent(true) + if (this$1.eatContextual("as")) { + node$2.local = this$1.parseIdent() + } else { + node$2.local = node$2.imported + if (this$1.isKeyword(node$2.local.name)) this$1.unexpected(node$2.local.start) + if (this$1.reservedWordsStrict.test(node$2.local.name)) this$1.raise(node$2.local.start, "The keyword '" + node$2.local.name + "' is reserved") + } + this$1.checkLVal(node$2.local, true) + nodes.push(this$1.finishNode(node$2, "ImportSpecifier")) + } + return nodes +} + +var pp$2 = Parser.prototype + +// Convert existing expression atom to assignable pattern +// if possible. + +pp$2.toAssignable = function(node, isBinding) { + var this$1 = this; + + if (this.options.ecmaVersion >= 6 && node) { + switch (node.type) { + case "Identifier": + case "ObjectPattern": + case "ArrayPattern": + break + + case "ObjectExpression": + node.type = "ObjectPattern" + for (var i = 0; i < node.properties.length; i++) { + var prop = node.properties[i] + if (prop.kind !== "init") this$1.raise(prop.key.start, "Object pattern can't contain getter or setter") + this$1.toAssignable(prop.value, isBinding) + } + break + + case "ArrayExpression": + node.type = "ArrayPattern" + this.toAssignableList(node.elements, isBinding) + break + + case "AssignmentExpression": + if (node.operator === "=") { + node.type = "AssignmentPattern" + delete node.operator + // falls through to AssignmentPattern + } else { + this.raise(node.left.end, "Only '=' operator can be used for specifying default value.") + break + } + + case "AssignmentPattern": + if (node.right.type === "YieldExpression") + this.raise(node.right.start, "Yield expression cannot be a default value") + break + + case "ParenthesizedExpression": + node.expression = this.toAssignable(node.expression, isBinding) + break + + case "MemberExpression": + if (!isBinding) break + + default: + this.raise(node.start, "Assigning to rvalue") + } + } + return node +} + +// Convert list of expression atoms to binding list. + +pp$2.toAssignableList = function(exprList, isBinding) { + var this$1 = this; + + var end = exprList.length + if (end) { + var last = exprList[end - 1] + if (last && last.type == "RestElement") { + --end + } else if (last && last.type == "SpreadElement") { + last.type = "RestElement" + var arg = last.argument + this.toAssignable(arg, isBinding) + if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") + this.unexpected(arg.start) + --end + } + + if (isBinding && last && last.type === "RestElement" && last.argument.type !== "Identifier") + this.unexpected(last.argument.start) + } + for (var i = 0; i < end; i++) { + var elt = exprList[i] + if (elt) this$1.toAssignable(elt, isBinding) + } + return exprList +} + +// Parses spread element. + +pp$2.parseSpread = function(refDestructuringErrors) { + var node = this.startNode() + this.next() + node.argument = this.parseMaybeAssign(false, refDestructuringErrors) + return this.finishNode(node, "SpreadElement") +} + +pp$2.parseRest = function(allowNonIdent) { + var node = this.startNode() + this.next() + + // RestElement inside of a function parameter must be an identifier + if (allowNonIdent) node.argument = this.type === tt.name ? this.parseIdent() : this.unexpected() + else node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected() + + return this.finishNode(node, "RestElement") +} + +// Parses lvalue (assignable) atom. + +pp$2.parseBindingAtom = function() { + if (this.options.ecmaVersion < 6) return this.parseIdent() + switch (this.type) { + case tt.name: + return this.parseIdent() + + case tt.bracketL: + var node = this.startNode() + this.next() + node.elements = this.parseBindingList(tt.bracketR, true, true) + return this.finishNode(node, "ArrayPattern") + + case tt.braceL: + return this.parseObj(true) + + default: + this.unexpected() + } +} + +pp$2.parseBindingList = function(close, allowEmpty, allowTrailingComma, allowNonIdent) { + var this$1 = this; + + var elts = [], first = true + while (!this.eat(close)) { + if (first) first = false + else this$1.expect(tt.comma) + if (allowEmpty && this$1.type === tt.comma) { + elts.push(null) + } else if (allowTrailingComma && this$1.afterTrailingComma(close)) { + break + } else if (this$1.type === tt.ellipsis) { + var rest = this$1.parseRest(allowNonIdent) + this$1.parseBindingListItem(rest) + elts.push(rest) + if (this$1.type === tt.comma) this$1.raise(this$1.start, "Comma is not permitted after the rest element") + this$1.expect(close) + break + } else { + var elem = this$1.parseMaybeDefault(this$1.start, this$1.startLoc) + this$1.parseBindingListItem(elem) + elts.push(elem) + } + } + return elts +} + +pp$2.parseBindingListItem = function(param) { + return param +} + +// Parses assignment pattern around given atom if possible. + +pp$2.parseMaybeDefault = function(startPos, startLoc, left) { + left = left || this.parseBindingAtom() + if (this.options.ecmaVersion < 6 || !this.eat(tt.eq)) return left + var node = this.startNodeAt(startPos, startLoc) + node.left = left + node.right = this.parseMaybeAssign() + return this.finishNode(node, "AssignmentPattern") +} + +// Verify that a node is an lval — something that can be assigned +// to. + +pp$2.checkLVal = function(expr, isBinding, checkClashes) { + var this$1 = this; + + switch (expr.type) { + case "Identifier": + if (this.strict && this.reservedWordsStrictBind.test(expr.name)) + this.raiseRecoverable(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode") + if (checkClashes) { + if (has(checkClashes, expr.name)) + this.raiseRecoverable(expr.start, "Argument name clash") + checkClashes[expr.name] = true + } + break + + case "MemberExpression": + if (isBinding) this.raiseRecoverable(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression") + break + + case "ObjectPattern": + for (var i = 0; i < expr.properties.length; i++) + this$1.checkLVal(expr.properties[i].value, isBinding, checkClashes) + break + + case "ArrayPattern": + for (var i$1 = 0; i$1 < expr.elements.length; i$1++) { + var elem = expr.elements[i$1] + if (elem) this$1.checkLVal(elem, isBinding, checkClashes) + } + break + + case "AssignmentPattern": + this.checkLVal(expr.left, isBinding, checkClashes) + break + + case "RestElement": + this.checkLVal(expr.argument, isBinding, checkClashes) + break + + case "ParenthesizedExpression": + this.checkLVal(expr.expression, isBinding, checkClashes) + break + + default: + this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue") + } +} + +var pp$3 = Parser.prototype + +// Check if property name clashes with already added. +// Object/class getters and setters are not allowed to clash — +// either with each other or with an init property — and in +// strict mode, init properties are also not allowed to be repeated. + +pp$3.checkPropClash = function(prop, propHash) { + if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand)) + return + var key = prop.key; + var name + switch (key.type) { + case "Identifier": name = key.name; break + case "Literal": name = String(key.value); break + default: return + } + var kind = prop.kind; + if (this.options.ecmaVersion >= 6) { + if (name === "__proto__" && kind === "init") { + if (propHash.proto) this.raiseRecoverable(key.start, "Redefinition of __proto__ property") + propHash.proto = true + } + return + } + name = "$" + name + var other = propHash[name] + if (other) { + var isGetSet = kind !== "init" + if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) + this.raiseRecoverable(key.start, "Redefinition of property") + } else { + other = propHash[name] = { + init: false, + get: false, + set: false + } + } + other[kind] = true +} + +// ### Expression parsing + +// These nest, from the most general expression type at the top to +// 'atomic', nondivisible expression types at the bottom. Most of +// the functions will simply let the function(s) below them parse, +// and, *if* the syntactic construct they handle is present, wrap +// the AST node that the inner parser gave them in another node. + +// Parse a full expression. The optional arguments are used to +// forbid the `in` operator (in for loops initalization expressions) +// and provide reference for storing '=' operator inside shorthand +// property assignment in contexts where both object expression +// and object pattern might appear (so it's possible to raise +// delayed syntax error at correct position). + +pp$3.parseExpression = function(noIn, refDestructuringErrors) { + var this$1 = this; + + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseMaybeAssign(noIn, refDestructuringErrors) + if (this.type === tt.comma) { + var node = this.startNodeAt(startPos, startLoc) + node.expressions = [expr] + while (this.eat(tt.comma)) node.expressions.push(this$1.parseMaybeAssign(noIn, refDestructuringErrors)) + return this.finishNode(node, "SequenceExpression") + } + return expr +} + +// Parse an assignment expression. This includes applications of +// operators like `+=`. + +pp$3.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { + if (this.inGenerator && this.isContextual("yield")) return this.parseYield() + + var ownDestructuringErrors = false + if (!refDestructuringErrors) { + refDestructuringErrors = new DestructuringErrors + ownDestructuringErrors = true + } + var startPos = this.start, startLoc = this.startLoc + if (this.type == tt.parenL || this.type == tt.name) + this.potentialArrowAt = this.start + var left = this.parseMaybeConditional(noIn, refDestructuringErrors) + if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc) + if (this.type.isAssign) { + this.checkPatternErrors(refDestructuringErrors, true) + if (!ownDestructuringErrors) DestructuringErrors.call(refDestructuringErrors) + var node = this.startNodeAt(startPos, startLoc) + node.operator = this.value + node.left = this.type === tt.eq ? this.toAssignable(left) : left + refDestructuringErrors.shorthandAssign = 0 // reset because shorthand default was used correctly + this.checkLVal(left) + this.next() + node.right = this.parseMaybeAssign(noIn) + return this.finishNode(node, "AssignmentExpression") + } else { + if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true) + } + return left +} + +// Parse a ternary conditional (`?:`) operator. + +pp$3.parseMaybeConditional = function(noIn, refDestructuringErrors) { + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseExprOps(noIn, refDestructuringErrors) + if (this.checkExpressionErrors(refDestructuringErrors)) return expr + if (this.eat(tt.question)) { + var node = this.startNodeAt(startPos, startLoc) + node.test = expr + node.consequent = this.parseMaybeAssign() + this.expect(tt.colon) + node.alternate = this.parseMaybeAssign(noIn) + return this.finishNode(node, "ConditionalExpression") + } + return expr +} + +// Start the precedence parser. + +pp$3.parseExprOps = function(noIn, refDestructuringErrors) { + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseMaybeUnary(refDestructuringErrors, false) + if (this.checkExpressionErrors(refDestructuringErrors)) return expr + return this.parseExprOp(expr, startPos, startLoc, -1, noIn) +} + +// Parse binary operators with the operator precedence parsing +// algorithm. `left` is the left-hand side of the operator. +// `minPrec` provides context that allows the function to stop and +// defer further parser to one of its callers when it encounters an +// operator that has a lower precedence than the set it is parsing. + +pp$3.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) { + var prec = this.type.binop + if (prec != null && (!noIn || this.type !== tt._in)) { + if (prec > minPrec) { + var logical = this.type === tt.logicalOR || this.type === tt.logicalAND + var op = this.value + this.next() + var startPos = this.start, startLoc = this.startLoc + var right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn) + var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical) + return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn) + } + } + return left +} + +pp$3.buildBinary = function(startPos, startLoc, left, right, op, logical) { + var node = this.startNodeAt(startPos, startLoc) + node.left = left + node.operator = op + node.right = right + return this.finishNode(node, logical ? "LogicalExpression" : "BinaryExpression") +} + +// Parse unary operators, both prefix and postfix. + +pp$3.parseMaybeUnary = function(refDestructuringErrors, sawUnary) { + var this$1 = this; + + var startPos = this.start, startLoc = this.startLoc, expr + if (this.type.prefix) { + var node = this.startNode(), update = this.type === tt.incDec + node.operator = this.value + node.prefix = true + this.next() + node.argument = this.parseMaybeUnary(null, true) + this.checkExpressionErrors(refDestructuringErrors, true) + if (update) this.checkLVal(node.argument) + else if (this.strict && node.operator === "delete" && + node.argument.type === "Identifier") + this.raiseRecoverable(node.start, "Deleting local variable in strict mode") + else sawUnary = true + expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression") + } else { + expr = this.parseExprSubscripts(refDestructuringErrors) + if (this.checkExpressionErrors(refDestructuringErrors)) return expr + while (this.type.postfix && !this.canInsertSemicolon()) { + var node$1 = this$1.startNodeAt(startPos, startLoc) + node$1.operator = this$1.value + node$1.prefix = false + node$1.argument = expr + this$1.checkLVal(expr) + this$1.next() + expr = this$1.finishNode(node$1, "UpdateExpression") + } + } + + if (!sawUnary && this.eat(tt.starstar)) + return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false), "**", false) + else + return expr +} + +// Parse call, dot, and `[]`-subscript expressions. + +pp$3.parseExprSubscripts = function(refDestructuringErrors) { + var startPos = this.start, startLoc = this.startLoc + var expr = this.parseExprAtom(refDestructuringErrors) + var skipArrowSubscripts = expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")" + if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr + return this.parseSubscripts(expr, startPos, startLoc) +} + +pp$3.parseSubscripts = function(base, startPos, startLoc, noCalls) { + var this$1 = this; + + for (;;) { + if (this$1.eat(tt.dot)) { + var node = this$1.startNodeAt(startPos, startLoc) + node.object = base + node.property = this$1.parseIdent(true) + node.computed = false + base = this$1.finishNode(node, "MemberExpression") + } else if (this$1.eat(tt.bracketL)) { + var node$1 = this$1.startNodeAt(startPos, startLoc) + node$1.object = base + node$1.property = this$1.parseExpression() + node$1.computed = true + this$1.expect(tt.bracketR) + base = this$1.finishNode(node$1, "MemberExpression") + } else if (!noCalls && this$1.eat(tt.parenL)) { + var node$2 = this$1.startNodeAt(startPos, startLoc) + node$2.callee = base + node$2.arguments = this$1.parseExprList(tt.parenR, false) + base = this$1.finishNode(node$2, "CallExpression") + } else if (this$1.type === tt.backQuote) { + var node$3 = this$1.startNodeAt(startPos, startLoc) + node$3.tag = base + node$3.quasi = this$1.parseTemplate() + base = this$1.finishNode(node$3, "TaggedTemplateExpression") + } else { + return base + } + } +} + +// Parse an atomic expression — either a single token that is an +// expression, an expression started by a keyword like `function` or +// `new`, or an expression wrapped in punctuation like `()`, `[]`, +// or `{}`. + +pp$3.parseExprAtom = function(refDestructuringErrors) { + var node, canBeArrow = this.potentialArrowAt == this.start + switch (this.type) { + case tt._super: + if (!this.inFunction) + this.raise(this.start, "'super' outside of function or class") + + case tt._this: + var type = this.type === tt._this ? "ThisExpression" : "Super" + node = this.startNode() + this.next() + return this.finishNode(node, type) + + case tt.name: + var startPos = this.start, startLoc = this.startLoc + var id = this.parseIdent(this.type !== tt.name) + if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) + return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]) + return id + + case tt.regexp: + var value = this.value + node = this.parseLiteral(value.value) + node.regex = {pattern: value.pattern, flags: value.flags} + return node + + case tt.num: case tt.string: + return this.parseLiteral(this.value) + + case tt._null: case tt._true: case tt._false: + node = this.startNode() + node.value = this.type === tt._null ? null : this.type === tt._true + node.raw = this.type.keyword + this.next() + return this.finishNode(node, "Literal") + + case tt.parenL: + return this.parseParenAndDistinguishExpression(canBeArrow) + + case tt.bracketL: + node = this.startNode() + this.next() + node.elements = this.parseExprList(tt.bracketR, true, true, refDestructuringErrors) + return this.finishNode(node, "ArrayExpression") + + case tt.braceL: + return this.parseObj(false, refDestructuringErrors) + + case tt._function: + node = this.startNode() + this.next() + return this.parseFunction(node, false) + + case tt._class: + return this.parseClass(this.startNode(), false) + + case tt._new: + return this.parseNew() + + case tt.backQuote: + return this.parseTemplate() + + default: + this.unexpected() + } +} + +pp$3.parseLiteral = function(value) { + var node = this.startNode() + node.value = value + node.raw = this.input.slice(this.start, this.end) + this.next() + return this.finishNode(node, "Literal") +} + +pp$3.parseParenExpression = function() { + this.expect(tt.parenL) + var val = this.parseExpression() + this.expect(tt.parenR) + return val +} + +pp$3.parseParenAndDistinguishExpression = function(canBeArrow) { + var this$1 = this; + + var startPos = this.start, startLoc = this.startLoc, val + if (this.options.ecmaVersion >= 6) { + this.next() + + var innerStartPos = this.start, innerStartLoc = this.startLoc + var exprList = [], first = true + var refDestructuringErrors = new DestructuringErrors, spreadStart, innerParenStart + while (this.type !== tt.parenR) { + first ? first = false : this$1.expect(tt.comma) + if (this$1.type === tt.ellipsis) { + spreadStart = this$1.start + exprList.push(this$1.parseParenItem(this$1.parseRest())) + break + } else { + if (this$1.type === tt.parenL && !innerParenStart) { + innerParenStart = this$1.start + } + exprList.push(this$1.parseMaybeAssign(false, refDestructuringErrors, this$1.parseParenItem)) + } + } + var innerEndPos = this.start, innerEndLoc = this.startLoc + this.expect(tt.parenR) + + if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { + this.checkPatternErrors(refDestructuringErrors, true) + if (innerParenStart) this.unexpected(innerParenStart) + return this.parseParenArrowList(startPos, startLoc, exprList) + } + + if (!exprList.length) this.unexpected(this.lastTokStart) + if (spreadStart) this.unexpected(spreadStart) + this.checkExpressionErrors(refDestructuringErrors, true) + + if (exprList.length > 1) { + val = this.startNodeAt(innerStartPos, innerStartLoc) + val.expressions = exprList + this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc) + } else { + val = exprList[0] + } + } else { + val = this.parseParenExpression() + } + + if (this.options.preserveParens) { + var par = this.startNodeAt(startPos, startLoc) + par.expression = val + return this.finishNode(par, "ParenthesizedExpression") + } else { + return val + } +} + +pp$3.parseParenItem = function(item) { + return item +} + +pp$3.parseParenArrowList = function(startPos, startLoc, exprList) { + return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList) +} + +// New's precedence is slightly tricky. It must allow its argument to +// be a `[]` or dot subscript expression, but not a call — at least, +// not without wrapping it in parentheses. Thus, it uses the noCalls +// argument to parseSubscripts to prevent it from consuming the +// argument list. + +var empty$1 = [] + +pp$3.parseNew = function() { + var node = this.startNode() + var meta = this.parseIdent(true) + if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { + node.meta = meta + node.property = this.parseIdent(true) + if (node.property.name !== "target") + this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target") + if (!this.inFunction) + this.raiseRecoverable(node.start, "new.target can only be used in functions") + return this.finishNode(node, "MetaProperty") + } + var startPos = this.start, startLoc = this.startLoc + node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true) + if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, false) + else node.arguments = empty$1 + return this.finishNode(node, "NewExpression") +} + +// Parse template expression. + +pp$3.parseTemplateElement = function() { + var elem = this.startNode() + elem.value = { + raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, '\n'), + cooked: this.value + } + this.next() + elem.tail = this.type === tt.backQuote + return this.finishNode(elem, "TemplateElement") +} + +pp$3.parseTemplate = function() { + var this$1 = this; + + var node = this.startNode() + this.next() + node.expressions = [] + var curElt = this.parseTemplateElement() + node.quasis = [curElt] + while (!curElt.tail) { + this$1.expect(tt.dollarBraceL) + node.expressions.push(this$1.parseExpression()) + this$1.expect(tt.braceR) + node.quasis.push(curElt = this$1.parseTemplateElement()) + } + this.next() + return this.finishNode(node, "TemplateLiteral") +} + +// Parse an object literal or binding pattern. + +pp$3.parseObj = function(isPattern, refDestructuringErrors) { + var this$1 = this; + + var node = this.startNode(), first = true, propHash = {} + node.properties = [] + this.next() + while (!this.eat(tt.braceR)) { + if (!first) { + this$1.expect(tt.comma) + if (this$1.afterTrailingComma(tt.braceR)) break + } else first = false + + var prop = this$1.startNode(), isGenerator, startPos, startLoc + if (this$1.options.ecmaVersion >= 6) { + prop.method = false + prop.shorthand = false + if (isPattern || refDestructuringErrors) { + startPos = this$1.start + startLoc = this$1.startLoc + } + if (!isPattern) + isGenerator = this$1.eat(tt.star) + } + this$1.parsePropertyName(prop) + this$1.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refDestructuringErrors) + this$1.checkPropClash(prop, propHash) + node.properties.push(this$1.finishNode(prop, "Property")) + } + return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression") +} + +pp$3.parsePropertyValue = function(prop, isPattern, isGenerator, startPos, startLoc, refDestructuringErrors) { + if (this.eat(tt.colon)) { + prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refDestructuringErrors) + prop.kind = "init" + } else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) { + if (isPattern) this.unexpected() + prop.kind = "init" + prop.method = true + prop.value = this.parseMethod(isGenerator) + } else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && + (prop.key.name === "get" || prop.key.name === "set") && + (this.type != tt.comma && this.type != tt.braceR)) { + if (isGenerator || isPattern) this.unexpected() + prop.kind = prop.key.name + this.parsePropertyName(prop) + prop.value = this.parseMethod(false) + var paramCount = prop.kind === "get" ? 0 : 1 + if (prop.value.params.length !== paramCount) { + var start = prop.value.start + if (prop.kind === "get") + this.raiseRecoverable(start, "getter should have no params") + else + this.raiseRecoverable(start, "setter should have exactly one param") + } + if (prop.kind === "set" && prop.value.params[0].type === "RestElement") + this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params") + } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { + if (this.keywords.test(prop.key.name) || + (this.strict ? this.reservedWordsStrictBind : this.reservedWords).test(prop.key.name) || + (this.inGenerator && prop.key.name == "yield")) + this.raiseRecoverable(prop.key.start, "'" + prop.key.name + "' can not be used as shorthand property") + prop.kind = "init" + if (isPattern) { + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key) + } else if (this.type === tt.eq && refDestructuringErrors) { + if (!refDestructuringErrors.shorthandAssign) + refDestructuringErrors.shorthandAssign = this.start + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key) + } else { + prop.value = prop.key + } + prop.shorthand = true + } else this.unexpected() +} + +pp$3.parsePropertyName = function(prop) { + if (this.options.ecmaVersion >= 6) { + if (this.eat(tt.bracketL)) { + prop.computed = true + prop.key = this.parseMaybeAssign() + this.expect(tt.bracketR) + return prop.key + } else { + prop.computed = false + } + } + return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true) +} + +// Initialize empty function node. + +pp$3.initFunction = function(node) { + node.id = null + if (this.options.ecmaVersion >= 6) { + node.generator = false + node.expression = false + } +} + +// Parse object or class method. + +pp$3.parseMethod = function(isGenerator) { + var node = this.startNode(), oldInGen = this.inGenerator + this.inGenerator = isGenerator + this.initFunction(node) + this.expect(tt.parenL) + node.params = this.parseBindingList(tt.parenR, false, false) + if (this.options.ecmaVersion >= 6) + node.generator = isGenerator + this.parseFunctionBody(node, false) + this.inGenerator = oldInGen + return this.finishNode(node, "FunctionExpression") +} + +// Parse arrow function expression with given parameters. + +pp$3.parseArrowExpression = function(node, params) { + var oldInGen = this.inGenerator + this.inGenerator = false + this.initFunction(node) + node.params = this.toAssignableList(params, true) + this.parseFunctionBody(node, true) + this.inGenerator = oldInGen + return this.finishNode(node, "ArrowFunctionExpression") +} + +// Parse function body and check parameters. + +pp$3.parseFunctionBody = function(node, isArrowFunction) { + var isExpression = isArrowFunction && this.type !== tt.braceL + + if (isExpression) { + node.body = this.parseMaybeAssign() + node.expression = true + } else { + // Start a new scope with regard to labels and the `inFunction` + // flag (restore them to their old value afterwards). + var oldInFunc = this.inFunction, oldLabels = this.labels + this.inFunction = true; this.labels = [] + node.body = this.parseBlock(true) + node.expression = false + this.inFunction = oldInFunc; this.labels = oldLabels + } + + // If this is a strict mode function, verify that argument names + // are not repeated, and it does not try to bind the words `eval` + // or `arguments`. + var useStrict = (!isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) ? node.body.body[0] : null; + if (this.strict || useStrict) { + var oldStrict = this.strict + this.strict = true + if (node.id) + this.checkLVal(node.id, true) + this.checkParams(node, useStrict) + this.strict = oldStrict + } else if (isArrowFunction) { + this.checkParams(node, useStrict) + } +} + +// Checks function params for various disallowed patterns such as using "eval" +// or "arguments" and duplicate parameters. + +pp$3.checkParams = function(node, useStrict) { + var this$1 = this; + + var nameHash = {} + for (var i = 0; i < node.params.length; i++) { + if (useStrict && this$1.options.ecmaVersion >= 7 && node.params[i].type !== "Identifier") + this$1.raiseRecoverable(useStrict.start, "Illegal 'use strict' directive in function with non-simple parameter list"); + this$1.checkLVal(node.params[i], true, nameHash) + } +} + +// Parses a comma-separated list of expressions, and returns them as +// an array. `close` is the token type that ends the list, and +// `allowEmpty` can be turned on to allow subsequent commas with +// nothing in between them to be parsed as `null` (which is needed +// for array literals). + +pp$3.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructuringErrors) { + var this$1 = this; + + var elts = [], first = true + while (!this.eat(close)) { + if (!first) { + this$1.expect(tt.comma) + if (allowTrailingComma && this$1.afterTrailingComma(close)) break + } else first = false + + var elt + if (allowEmpty && this$1.type === tt.comma) + elt = null + else if (this$1.type === tt.ellipsis) { + elt = this$1.parseSpread(refDestructuringErrors) + if (this$1.type === tt.comma && refDestructuringErrors && !refDestructuringErrors.trailingComma) { + refDestructuringErrors.trailingComma = this$1.lastTokStart + } + } else + elt = this$1.parseMaybeAssign(false, refDestructuringErrors) + elts.push(elt) + } + return elts +} + +// Parse the next token as an identifier. If `liberal` is true (used +// when parsing properties), it will also convert keywords into +// identifiers. + +pp$3.parseIdent = function(liberal) { + var node = this.startNode() + if (liberal && this.options.allowReserved == "never") liberal = false + if (this.type === tt.name) { + if (!liberal && (this.strict ? this.reservedWordsStrict : this.reservedWords).test(this.value) && + (this.options.ecmaVersion >= 6 || + this.input.slice(this.start, this.end).indexOf("\\") == -1)) + this.raiseRecoverable(this.start, "The keyword '" + this.value + "' is reserved") + if (!liberal && this.inGenerator && this.value === "yield") + this.raiseRecoverable(this.start, "Can not use 'yield' as identifier inside a generator") + node.name = this.value + } else if (liberal && this.type.keyword) { + node.name = this.type.keyword + } else { + this.unexpected() + } + this.next() + return this.finishNode(node, "Identifier") +} + +// Parses yield expression inside generator. + +pp$3.parseYield = function() { + var node = this.startNode() + this.next() + if (this.type == tt.semi || this.canInsertSemicolon() || (this.type != tt.star && !this.type.startsExpr)) { + node.delegate = false + node.argument = null + } else { + node.delegate = this.eat(tt.star) + node.argument = this.parseMaybeAssign() + } + return this.finishNode(node, "YieldExpression") +} + +var pp$4 = Parser.prototype + +// This function is used to raise exceptions on parse errors. It +// takes an offset integer (into the current `input`) to indicate +// the location of the error, attaches the position to the end +// of the error message, and then raises a `SyntaxError` with that +// message. + +pp$4.raise = function(pos, message) { + var loc = getLineInfo(this.input, pos) + message += " (" + loc.line + ":" + loc.column + ")" + var err = new SyntaxError(message) + err.pos = pos; err.loc = loc; err.raisedAt = this.pos + throw err +} + +pp$4.raiseRecoverable = pp$4.raise + +pp$4.curPosition = function() { + if (this.options.locations) { + return new Position(this.curLine, this.pos - this.lineStart) + } +} + +var Node = function Node(parser, pos, loc) { + this.type = "" + this.start = pos + this.end = 0 + if (parser.options.locations) + this.loc = new SourceLocation(parser, loc) + if (parser.options.directSourceFile) + this.sourceFile = parser.options.directSourceFile + if (parser.options.ranges) + this.range = [pos, 0] +}; + +// Start an AST node, attaching a start offset. + +var pp$5 = Parser.prototype + +pp$5.startNode = function() { + return new Node(this, this.start, this.startLoc) +} + +pp$5.startNodeAt = function(pos, loc) { + return new Node(this, pos, loc) +} + +// Finish an AST node, adding `type` and `end` properties. + +function finishNodeAt(node, type, pos, loc) { + node.type = type + node.end = pos + if (this.options.locations) + node.loc.end = loc + if (this.options.ranges) + node.range[1] = pos + return node +} + +pp$5.finishNode = function(node, type) { + return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc) +} + +// Finish node at given position + +pp$5.finishNodeAt = function(node, type, pos, loc) { + return finishNodeAt.call(this, node, type, pos, loc) +} + +var TokContext = function TokContext(token, isExpr, preserveSpace, override) { + this.token = token + this.isExpr = !!isExpr + this.preserveSpace = !!preserveSpace + this.override = override +}; + +var types = { + b_stat: new TokContext("{", false), + b_expr: new TokContext("{", true), + b_tmpl: new TokContext("${", true), + p_stat: new TokContext("(", false), + p_expr: new TokContext("(", true), + q_tmpl: new TokContext("`", true, true, function (p) { return p.readTmplToken(); }), + f_expr: new TokContext("function", true) +} + +var pp$6 = Parser.prototype + +pp$6.initialContext = function() { + return [types.b_stat] +} + +pp$6.braceIsBlock = function(prevType) { + if (prevType === tt.colon) { + var parent = this.curContext() + if (parent === types.b_stat || parent === types.b_expr) + return !parent.isExpr + } + if (prevType === tt._return) + return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) + if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR) + return true + if (prevType == tt.braceL) + return this.curContext() === types.b_stat + return !this.exprAllowed +} + +pp$6.updateContext = function(prevType) { + var update, type = this.type + if (type.keyword && prevType == tt.dot) + this.exprAllowed = false + else if (update = type.updateContext) + update.call(this, prevType) + else + this.exprAllowed = type.beforeExpr +} + +// Token-specific context update code + +tt.parenR.updateContext = tt.braceR.updateContext = function() { + if (this.context.length == 1) { + this.exprAllowed = true + return + } + var out = this.context.pop() + if (out === types.b_stat && this.curContext() === types.f_expr) { + this.context.pop() + this.exprAllowed = false + } else if (out === types.b_tmpl) { + this.exprAllowed = true + } else { + this.exprAllowed = !out.isExpr + } +} + +tt.braceL.updateContext = function(prevType) { + this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr) + this.exprAllowed = true +} + +tt.dollarBraceL.updateContext = function() { + this.context.push(types.b_tmpl) + this.exprAllowed = true +} + +tt.parenL.updateContext = function(prevType) { + var statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while + this.context.push(statementParens ? types.p_stat : types.p_expr) + this.exprAllowed = true +} + +tt.incDec.updateContext = function() { + // tokExprAllowed stays unchanged +} + +tt._function.updateContext = function(prevType) { + if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else && + !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat)) + this.context.push(types.f_expr) + this.exprAllowed = false +} + +tt.backQuote.updateContext = function() { + if (this.curContext() === types.q_tmpl) + this.context.pop() + else + this.context.push(types.q_tmpl) + this.exprAllowed = false +} + +// Object type used to represent tokens. Note that normally, tokens +// simply exist as properties on the parser object. This is only +// used for the onToken callback and the external tokenizer. + +var Token = function Token(p) { + this.type = p.type + this.value = p.value + this.start = p.start + this.end = p.end + if (p.options.locations) + this.loc = new SourceLocation(p, p.startLoc, p.endLoc) + if (p.options.ranges) + this.range = [p.start, p.end] +}; + +// ## Tokenizer + +var pp$7 = Parser.prototype + +// Are we running under Rhino? +var isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]" + +// Move to the next token + +pp$7.next = function() { + if (this.options.onToken) + this.options.onToken(new Token(this)) + + this.lastTokEnd = this.end + this.lastTokStart = this.start + this.lastTokEndLoc = this.endLoc + this.lastTokStartLoc = this.startLoc + this.nextToken() +} + +pp$7.getToken = function() { + this.next() + return new Token(this) +} + +// If we're in an ES6 environment, make parsers iterable +if (typeof Symbol !== "undefined") + pp$7[Symbol.iterator] = function () { + var self = this + return {next: function () { + var token = self.getToken() + return { + done: token.type === tt.eof, + value: token + } + }} + } + +// Toggle strict mode. Re-reads the next number or string to please +// pedantic tests (`"use strict"; 010;` should fail). + +pp$7.setStrict = function(strict) { + var this$1 = this; + + this.strict = strict + if (this.type !== tt.num && this.type !== tt.string) return + this.pos = this.start + if (this.options.locations) { + while (this.pos < this.lineStart) { + this$1.lineStart = this$1.input.lastIndexOf("\n", this$1.lineStart - 2) + 1 + --this$1.curLine + } + } + this.nextToken() +} + +pp$7.curContext = function() { + return this.context[this.context.length - 1] +} + +// Read a single token, updating the parser object's token-related +// properties. + +pp$7.nextToken = function() { + var curContext = this.curContext() + if (!curContext || !curContext.preserveSpace) this.skipSpace() + + this.start = this.pos + if (this.options.locations) this.startLoc = this.curPosition() + if (this.pos >= this.input.length) return this.finishToken(tt.eof) + + if (curContext.override) return curContext.override(this) + else this.readToken(this.fullCharCodeAtPos()) +} + +pp$7.readToken = function(code) { + // Identifier or keyword. '\uXXXX' sequences are allowed in + // identifiers, so '\' also dispatches to that. + if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) + return this.readWord() + + return this.getTokenFromCode(code) +} + +pp$7.fullCharCodeAtPos = function() { + var code = this.input.charCodeAt(this.pos) + if (code <= 0xd7ff || code >= 0xe000) return code + var next = this.input.charCodeAt(this.pos + 1) + return (code << 10) + next - 0x35fdc00 +} + +pp$7.skipBlockComment = function() { + var this$1 = this; + + var startLoc = this.options.onComment && this.curPosition() + var start = this.pos, end = this.input.indexOf("*/", this.pos += 2) + if (end === -1) this.raise(this.pos - 2, "Unterminated comment") + this.pos = end + 2 + if (this.options.locations) { + lineBreakG.lastIndex = start + var match + while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) { + ++this$1.curLine + this$1.lineStart = match.index + match[0].length + } + } + if (this.options.onComment) + this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, + startLoc, this.curPosition()) +} + +pp$7.skipLineComment = function(startSkip) { + var this$1 = this; + + var start = this.pos + var startLoc = this.options.onComment && this.curPosition() + var ch = this.input.charCodeAt(this.pos+=startSkip) + while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { + ++this$1.pos + ch = this$1.input.charCodeAt(this$1.pos) + } + if (this.options.onComment) + this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, + startLoc, this.curPosition()) +} + +// Called at the start of the parse and after every token. Skips +// whitespace and comments, and. + +pp$7.skipSpace = function() { + var this$1 = this; + + loop: while (this.pos < this.input.length) { + var ch = this$1.input.charCodeAt(this$1.pos) + switch (ch) { + case 32: case 160: // ' ' + ++this$1.pos + break + case 13: + if (this$1.input.charCodeAt(this$1.pos + 1) === 10) { + ++this$1.pos + } + case 10: case 8232: case 8233: + ++this$1.pos + if (this$1.options.locations) { + ++this$1.curLine + this$1.lineStart = this$1.pos + } + break + case 47: // '/' + switch (this$1.input.charCodeAt(this$1.pos + 1)) { + case 42: // '*' + this$1.skipBlockComment() + break + case 47: + this$1.skipLineComment(2) + break + default: + break loop + } + break + default: + if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { + ++this$1.pos + } else { + break loop + } + } + } +} + +// Called at the end of every token. Sets `end`, `val`, and +// maintains `context` and `exprAllowed`, and skips the space after +// the token, so that the next one's `start` will point at the +// right position. + +pp$7.finishToken = function(type, val) { + this.end = this.pos + if (this.options.locations) this.endLoc = this.curPosition() + var prevType = this.type + this.type = type + this.value = val + + this.updateContext(prevType) +} + +// ### Token reading + +// This is the function that is called to fetch the next token. It +// is somewhat obscure, because it works in character codes rather +// than characters, and because operator parsing has been inlined +// into it. +// +// All in the name of speed. +// +pp$7.readToken_dot = function() { + var next = this.input.charCodeAt(this.pos + 1) + if (next >= 48 && next <= 57) return this.readNumber(true) + var next2 = this.input.charCodeAt(this.pos + 2) + if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.' + this.pos += 3 + return this.finishToken(tt.ellipsis) + } else { + ++this.pos + return this.finishToken(tt.dot) + } +} + +pp$7.readToken_slash = function() { // '/' + var next = this.input.charCodeAt(this.pos + 1) + if (this.exprAllowed) {++this.pos; return this.readRegexp()} + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.slash, 1) +} + +pp$7.readToken_mult_modulo_exp = function(code) { // '%*' + var next = this.input.charCodeAt(this.pos + 1) + var size = 1 + var tokentype = code === 42 ? tt.star : tt.modulo + + // exponentiation operator ** and **= + if (this.options.ecmaVersion >= 7 && next === 42) { + ++size + tokentype = tt.starstar + next = this.input.charCodeAt(this.pos + 2) + } + + if (next === 61) return this.finishOp(tt.assign, size + 1) + return this.finishOp(tokentype, size) +} + +pp$7.readToken_pipe_amp = function(code) { // '|&' + var next = this.input.charCodeAt(this.pos + 1) + if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2) + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1) +} + +pp$7.readToken_caret = function() { // '^' + var next = this.input.charCodeAt(this.pos + 1) + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.bitwiseXOR, 1) +} + +pp$7.readToken_plus_min = function(code) { // '+-' + var next = this.input.charCodeAt(this.pos + 1) + if (next === code) { + if (next == 45 && this.input.charCodeAt(this.pos + 2) == 62 && + lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) { + // A `-->` line comment + this.skipLineComment(3) + this.skipSpace() + return this.nextToken() + } + return this.finishOp(tt.incDec, 2) + } + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.plusMin, 1) +} + +pp$7.readToken_lt_gt = function(code) { // '<>' + var next = this.input.charCodeAt(this.pos + 1) + var size = 1 + if (next === code) { + size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2 + if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1) + return this.finishOp(tt.bitShift, size) + } + if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && + this.input.charCodeAt(this.pos + 3) == 45) { + if (this.inModule) this.unexpected() + // `` line comment + this.skipLineComment(3) + this.skipSpace() + return this.nextToken() + } + return this.finishOp(tt.incDec, 2) + } + if (next === 61) return this.finishOp(tt.assign, 2) + return this.finishOp(tt.plusMin, 1) + } -pp.readToken = function (code) { - // Identifier or keyword. '\uXXXX' sequences are allowed in - // identifiers, so '\' also dispatches to that. - if (_identifier.isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) return this.readWord(); - - return this.getTokenFromCode(code); -}; - -pp.fullCharCodeAtPos = function () { - var code = this.input.charCodeAt(this.pos); - if (code <= 0xd7ff || code >= 0xe000) return code; - var next = this.input.charCodeAt(this.pos + 1); - return (code << 10) + next - 0x35fdc00; -}; - -pp.skipBlockComment = function () { - var startLoc = this.options.onComment && this.curPosition(); - var start = this.pos, - end = this.input.indexOf("*/", this.pos += 2); - if (end === -1) this.raise(this.pos - 2, "Unterminated comment"); - this.pos = end + 2; - if (this.options.locations) { - _whitespace.lineBreakG.lastIndex = start; - var match = undefined; - while ((match = _whitespace.lineBreakG.exec(this.input)) && match.index < this.pos) { - ++this.curLine; - this.lineStart = match.index + match[0].length; - } - } - if (this.options.onComment) this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, startLoc, this.curPosition()); -}; - -pp.skipLineComment = function (startSkip) { - var start = this.pos; - var startLoc = this.options.onComment && this.curPosition(); - var ch = this.input.charCodeAt(this.pos += startSkip); - while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { - ++this.pos; - ch = this.input.charCodeAt(this.pos); - } - if (this.options.onComment) this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, startLoc, this.curPosition()); -}; - -// Called at the start of the parse and after every token. Skips -// whitespace and comments, and. - -pp.skipSpace = function () { - loop: while (this.pos < this.input.length) { - var ch = this.input.charCodeAt(this.pos); - switch (ch) { - case 32:case 160: - // ' ' - ++this.pos; - break; - case 13: - if (this.input.charCodeAt(this.pos + 1) === 10) { - ++this.pos; - } - case 10:case 8232:case 8233: - ++this.pos; - if (this.options.locations) { - ++this.curLine; - this.lineStart = this.pos; - } - break; - case 47: - // '/' - switch (this.input.charCodeAt(this.pos + 1)) { - case 42: - // '*' - this.skipBlockComment(); - break; - case 47: - this.skipLineComment(2); - break; - default: - break loop; - } - break; - default: - if (ch > 8 && ch < 14 || ch >= 5760 && _whitespace.nonASCIIwhitespace.test(String.fromCharCode(ch))) { - ++this.pos; - } else { - break loop; - } + pp$7.readToken_lt_gt = function(code) { // '<>' + var next = this.input.charCodeAt(this.pos + 1) + var size = 1 + if (next === code) { + size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2 + if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1) + return this.finishOp(tt.bitShift, size) + } + if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && + this.input.charCodeAt(this.pos + 3) == 45) { + if (this.inModule) this.unexpected() + // `` line comment - this.skipLineComment(3); - this.skipSpace(); - return this.nextToken(); - } - return this.finishOp(_tokentype.types.incDec, 2); - } - if (next === 61) return this.finishOp(_tokentype.types.assign, 2); - return this.finishOp(_tokentype.types.plusMin, 1); -}; - -pp.readToken_lt_gt = function (code) { - // '<>' - var next = this.input.charCodeAt(this.pos + 1); - var size = 1; - if (next === code) { - size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; - if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(_tokentype.types.assign, size + 1); - return this.finishOp(_tokentype.types.bitShift, size); - } - if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) { - if (this.inModule) this.unexpected(); - // ` - + + @@ -80,9 +83,11 @@ "$(WixToolPath)\torch.exe" -t language "$(TargetDir)en-US\$(TargetFileName)" "$(TargetDir)de-de\$(TargetFileName)" -out "$(TargetDir)transforms\de-de.mst" "$(WixToolPath)\torch.exe" -t language "$(TargetDir)en-US\$(TargetFileName)" "$(TargetDir)it-it\$(TargetFileName)" -out "$(TargetDir)transforms\it-it.mst" + "$(WixToolPath)\torch.exe" -t language "$(TargetDir)en-US\$(TargetFileName)" "$(TargetDir)zh-cn\$(TargetFileName)" -out "$(TargetDir)transforms\zh-cn.mst" cscript.exe "$(WindowsSDK80Path)bin\$(Platform)\WiSubStg.vbs" "$(TargetDir)en-US\$(TargetFileName)" "$(TargetDir)transforms\de-de.mst" 1031 - cscript.exe "$(WindowsSDK80Path)bin\$(Platform)\WiSubStg.vbs" "$(TargetDir)en-US\$(TargetFileName)" "$(TargetDir)transforms\it-it.mst" 1031 - cscript.exe "$(WindowsSDK80Path)bin\$(Platform)\WiLangId.vbs" "$(TargetDir)en-US\$(TargetFileName)" Package 1033,1031 + cscript.exe "$(WindowsSDK80Path)bin\$(Platform)\WiSubStg.vbs" "$(TargetDir)en-US\$(TargetFileName)" "$(TargetDir)transforms\it-it.mst" 1040 + cscript.exe "$(WindowsSDK80Path)bin\$(Platform)\WiSubStg.vbs" "$(TargetDir)en-US\$(TargetFileName)" "$(TargetDir)transforms\zh-cn.mst" 2052 + cscript.exe "$(WindowsSDK80Path)bin\$(Platform)\WiLangId.vbs" "$(TargetDir)en-US\$(TargetFileName)" Package 1031,1033,1040,2052 --> diff --git a/tools/test.py b/tools/test.py index 06a67421c53..11bb8db0225 100755 --- a/tools/test.py +++ b/tools/test.py @@ -196,7 +196,7 @@ def Done(self): print failed.output.stdout.strip() print "Command: %s" % EscapeCommand(failed.command) if failed.HasCrashed(): - print "--- CRASHED ---" + print "--- %s ---" % PrintCrashed(failed.output.exit_code) if failed.HasTimedOut(): print "--- TIMEOUT ---" if len(self.failed) == 0: @@ -285,6 +285,9 @@ def HasRun(self, output): logger.info(status_line) self._printDiagnostic("\n".join(output.diagnostic)) + if output.HasCrashed(): + self._printDiagnostic(PrintCrashed(output.output.exit_code)) + if output.HasTimedOut(): self._printDiagnostic('TIMEOUT') @@ -347,7 +350,7 @@ def HasRun(self, output): print self.templates['stderr'] % stderr print "Command: %s" % EscapeCommand(output.command) if output.HasCrashed(): - print "--- CRASHED ---" + print "--- %s ---" % PrintCrashed(output.output.exit_code) if output.HasTimedOut(): print "--- TIMEOUT ---" @@ -1479,6 +1482,13 @@ def FormatTime(d): return time.strftime("%M:%S.", time.gmtime(d)) + ("%03i" % millis) +def PrintCrashed(code): + if utils.IsWindows(): + return "CRASHED" + else: + return "CRASHED (Signal: %d)" % -code + + def Main(): parser = BuildOptions() (options, args) = parser.parse_args() diff --git a/vcbuild.bat b/vcbuild.bat index 711cb74caa8..fd25a5da1a6 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -38,6 +38,7 @@ set build_release= set enable_vtune_arg= set configure_flags= set build_addons= +set dll= set engine=v8 :next-arg @@ -81,6 +82,7 @@ if /i "%1"=="without-intl" set i18n_arg=%1&goto arg-ok if /i "%1"=="download-all" set download_arg="--download=all"&goto arg-ok if /i "%1"=="ignore-flaky" set test_args=%test_args% --flaky-tests=dontcare&goto arg-ok if /i "%1"=="enable-vtune" set enable_vtune_arg=1&goto arg-ok +if /i "%1"=="dll" set dll=1&goto arg-ok if /i "%1"=="v8" set engine=v8&goto arg-ok if /i "%1"=="chakracore" set engine=chakracore&set chakra_jslint=deps\chakrashim\lib&goto arg-ok @@ -112,6 +114,7 @@ if defined noperfctr set configure_flags=%configure_flags% --without-perfctr& se if defined release_urlbase set release_urlbase_arg=--release-urlbase=%release_urlbase% if defined download_arg set configure_flags=%configure_flags% %download_arg% if defined enable_vtune_arg set configure_flags=%configure_flags% --enable-vtune-profiling +if defined dll set configure_flags=%configure_flags% --shared if "%i18n_arg%"=="full-icu" set configure_flags=%configure_flags% --with-intl=full-icu if "%i18n_arg%"=="small-icu" set configure_flags=%configure_flags% --with-intl=small-icu @@ -353,7 +356,7 @@ goto jslint :jslint if defined jslint_ci goto jslint-ci if not defined jslint goto exit -if not exist tools\eslint\bin\eslint.js goto no-lint +if not exist tools\eslint\lib\eslint.js goto no-lint echo running jslint %config%\node tools\jslint.js -J benchmark lib src test %chakra_jslint% tools goto exit