diff --git a/.eslintrc.js b/.eslintrc.js index 59d585b9d355bd..ba94036b0f50bc 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -85,6 +85,7 @@ module.exports = { 'comma-style': 'error', 'computed-property-spacing': 'error', 'constructor-super': 'error', + 'default-case-last': 'error', 'dot-location': ['error', 'property'], 'dot-notation': 'error', 'eol-last': 'error', @@ -273,6 +274,7 @@ module.exports = { functions: false, variables: false, }], + 'no-useless-backreference': 'error', 'no-useless-call': 'error', 'no-useless-catch': 'error', 'no-useless-concat': 'error', diff --git a/.mailmap b/.mailmap index e140392b723514..15962df50bdb94 100644 --- a/.mailmap +++ b/.mailmap @@ -423,6 +423,7 @@ Wilson Lin Wyatt Preul geek Xavier J Ortiz xiaoyu <306766053@qq.com> Poker <306766053@qq.com> +Yael Hermon Yazhong Liu Yazhong Liu Yazhong Liu Yorkie Yazhong Liu Yorkie diff --git a/AUTHORS b/AUTHORS index adb8aef88a44d5..539f311a0dcb9f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2636,7 +2636,7 @@ Charles Samborski zhmushan yoshimoto koki Ilarion Halushka -Yael Hermon +Yael Hermon Mitch Hankins Mikko Rantanen wenjun ye <1728914873@qq.com> diff --git a/CHANGELOG.md b/CHANGELOG.md index cd5600535009ec..ca3a8d3872bbf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,19 +2,19 @@ Select a Node.js version below to view the changelog history: -* [Node.js 13](doc/changelogs/CHANGELOG_V13.md) - **Current** -* [Node.js 12](doc/changelogs/CHANGELOG_V12.md) - **Long Term Support** -* [Node.js 11](doc/changelogs/CHANGELOG_V11.md) - End-of-Life -* [Node.js 10](doc/changelogs/CHANGELOG_V10.md) — Long Term Support -* [Node.js 9](doc/changelogs/CHANGELOG_V9.md) — End-of-Life -* [Node.js 8](doc/changelogs/CHANGELOG_V8.md) — Long Term Support -* [Node.js 7](doc/changelogs/CHANGELOG_V7.md) — End-of-Life -* [Node.js 6](doc/changelogs/CHANGELOG_V6.md) — End-of-Life -* [Node.js 5](doc/changelogs/CHANGELOG_V5.md) — End-of-Life -* [Node.js 4](doc/changelogs/CHANGELOG_V4.md) — End-of-Life -* [io.js](doc/changelogs/CHANGELOG_IOJS.md) — End-of-Life -* [Node.js 0.12](doc/changelogs/CHANGELOG_V012.md) — End-of-Life -* [Node.js 0.10](doc/changelogs/CHANGELOG_V010.md) — End-of-Life +* [Node.js 13](doc/changelogs/CHANGELOG_V13.md) **Current** +* [Node.js 12](doc/changelogs/CHANGELOG_V12.md) **Long Term Support** +* [Node.js 11](doc/changelogs/CHANGELOG_V11.md) End-of-Life +* [Node.js 10](doc/changelogs/CHANGELOG_V10.md) Long Term Support +* [Node.js 9](doc/changelogs/CHANGELOG_V9.md) End-of-Life +* [Node.js 8](doc/changelogs/CHANGELOG_V8.md) End-of-Life +* [Node.js 7](doc/changelogs/CHANGELOG_V7.md) End-of-Life +* [Node.js 6](doc/changelogs/CHANGELOG_V6.md) End-of-Life +* [Node.js 5](doc/changelogs/CHANGELOG_V5.md) End-of-Life +* [Node.js 4](doc/changelogs/CHANGELOG_V4.md) End-of-Life +* [io.js](doc/changelogs/CHANGELOG_IOJS.md) End-of-Life +* [Node.js 0.12](doc/changelogs/CHANGELOG_V012.md) End-of-Life +* [Node.js 0.10](doc/changelogs/CHANGELOG_V010.md) End-of-Life * [Archive](doc/changelogs/CHANGELOG_ARCHIVE.md) Please use the following table to find the changelog for a specific Node.js @@ -30,7 +30,8 @@ release. -13.10.1
+13.11.0
+13.10.1
13.10.0
13.9.0
13.8.0
diff --git a/README.md b/README.md index 0576cd5132e6a8..b073c034b7eb3a 100644 --- a/README.md +++ b/README.md @@ -181,8 +181,6 @@ For information about the governance of the Node.js project, see **Sam Roberts** <vieuxtech@gmail.com> * [targos](https://github.com/targos) - **Michaël Zasso** <targos@protonmail.com> (he/him) -* [thefourtheye](https://github.com/thefourtheye) - -**Sakthipriyan Vairamani** <thechargingvolcano@gmail.com> (he/him) * [tniessen](https://github.com/tniessen) - **Tobias Nießen** <tniessen@tnie.de> * [Trott](https://github.com/Trott) - @@ -222,6 +220,8 @@ For information about the governance of the Node.js project, see **Rod Vagg** <r@va.gg> * [shigeki](https://github.com/shigeki) - **Shigeki Ohtsu** <ohtsu@ohtsu.org> (he/him) +* [thefourtheye](https://github.com/thefourtheye) - +**Sakthipriyan Vairamani** <thechargingvolcano@gmail.com> (he/him) * [TimothyGu](https://github.com/TimothyGu) - **Tiancheng "Timothy" Gu** <timothygu99@gmail.com> (he/him) * [trevnorris](https://github.com/trevnorris) - diff --git a/android-configure b/android-configure index 59f0a40c1ac214..a7cb2b9c8b4a78 100755 --- a/android-configure +++ b/android-configure @@ -8,29 +8,39 @@ # modules with npm. Also, don't forget to set the arch in npm config using # 'npm config set arch=' +if [ $# -ne 3 ]; then + echo "$0 should have 3 parameters: ndk_path, target_arch and sdk_version" + exit 1 +fi + +NDK_PATH=$1 +ARCH="$2" +ANDROID_SDK_VERSION=$3 -if [ -z "$2" ]; then - ARCH=arm -else - ARCH="$2" +if [ $ANDROID_SDK_VERSION -lt 23 ]; then + echo "$ANDROID_SDK_VERSION should equal or later than 23(Android 6.0)" fi CC_VER="4.9" + case $ARCH in arm) - DEST_CPU="$ARCH" - SUFFIX="$ARCH-linux-androideabi" - TOOLCHAIN_NAME="$SUFFIX" + DEST_CPU="arm" + TOOLCHAIN_NAME="armv7-linux-androideabi" ;; x86) DEST_CPU="ia32" - SUFFIX="i686-linux-android" - TOOLCHAIN_NAME="$ARCH" + TOOLCHAIN_NAME="i686-linux-android" ;; x86_64) - DEST_CPU="ia32" - SUFFIX="$ARCH-linux-android" - TOOLCHAIN_NAME="$ARCH" + DEST_CPU="x64" + TOOLCHAIN_NAME="x86_64-linux-android" + ARCH="x64" + ;; + arm64|aarch64) + DEST_CPU="arm64" + TOOLCHAIN_NAME="aarch64-linux-android" + ARCH="arm64" ;; *) echo "Unsupported architecture provided: $ARCH" @@ -38,36 +48,31 @@ case $ARCH in ;; esac -NDK_PATH=$1 -function make_toolchain { - $NDK_PATH/build/tools/make-standalone-toolchain.sh \ - --toolchain=$TOOLCHAIN_NAME-$CC_VER \ - --arch=$ARCH \ - --install-dir=$TOOLCHAIN \ - --platform=android-21 -} +HOST_OS="linux" +HOST_ARCH="x86_64" +export CC_host=$(which gcc) +export CXX_host=$(which g++) -export TOOLCHAIN=$PWD/android-toolchain -if [ -d "$TOOLCHAIN" ]; then - read -r -p "NDK toolchain already exists. Replace it? [y/N]" response - case "$response" in - [Yy]) - rm -rf "$TOOLCHAIN" - make_toolchain - esac -else - make_toolchain +host_gcc_version=$($CC_host --version | grep gcc | awk '{print $NF}') +major=$(echo $host_gcc_version | awk -F . '{print $1}') +minor=$(echo $host_gcc_version | awk -F . '{print $2}') +if [ -z $major ] || [ -z $minor ] || [ $major -lt 6 ] || [ $major -eq 6 -a $minor -lt 3 ]; then + echo "host gcc $host_gcc_version is too old, need gcc 6.3.0" + exit 1 fi + +SUFFIX="$TOOLCHAIN_NAME$ANDROID_SDK_VERSION" +TOOLCHAIN=$NDK_PATH/toolchains/llvm/prebuilt/$HOST_OS-$HOST_ARCH + export PATH=$TOOLCHAIN/bin:$PATH -export AR=$TOOLCHAIN/bin/$SUFFIX-ar -export CC=$TOOLCHAIN/bin/$SUFFIX-gcc -export CXX=$TOOLCHAIN/bin/$SUFFIX-g++ -export LINK=$TOOLCHAIN/bin/$SUFFIX-g++ +export CC=$TOOLCHAIN/bin/$SUFFIX-clang +export CXX=$TOOLCHAIN/bin/$SUFFIX-clang++ + GYP_DEFINES="target_arch=$ARCH" GYP_DEFINES+=" v8_target_arch=$ARCH" GYP_DEFINES+=" android_target_arch=$ARCH" -GYP_DEFINES+=" host_os=linux OS=android" +GYP_DEFINES+=" host_os=$HOST_OS OS=android" export GYP_DEFINES if [ -f "configure" ]; then @@ -75,5 +80,6 @@ if [ -f "configure" ]; then --dest-cpu=$DEST_CPU \ --dest-os=android \ --without-snapshot \ - --openssl-no-asm + --openssl-no-asm \ + --cross-compiling fi diff --git a/benchmark/README.md b/benchmark/README.md index cb7c1506eb6235..6a40d7af3e1fcf 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -76,17 +76,17 @@ writing benchmarks. ### `createBenchmark(fn, configs[, options])` -See [the guide on writing benchmarks](../doc/guides/contributing/writing-and-running-benchmarks.md#basics-of-a-benchmark). +See [the guide on writing benchmarks](../doc/guides/writing-and-running-benchmarks.md#basics-of-a-benchmark). ### `default_http_benchmarker` The default benchmarker used to run HTTP benchmarks. -See [the guide on writing HTTP benchmarks](../doc/guides/contributing/writing-and-running-benchmarks.md#creating-an-http-benchmark). +See [the guide on writing HTTP benchmarks](../doc/guides/writing-and-running-benchmarks.md#creating-an-http-benchmark). ### `PORT` The default port used to run HTTP benchmarks. -See [the guide on writing HTTP benchmarks](../doc/guides/contributing/writing-and-running-benchmarks.md#creating-an-http-benchmark). +See [the guide on writing HTTP benchmarks](../doc/guides/writing-and-running-benchmarks.md#creating-an-http-benchmark). ### `sendResult(data)` diff --git a/benchmark/_cli.js b/benchmark/_cli.js index 771cc72bff1964..eb6c4add9799a4 100644 --- a/benchmark/_cli.js +++ b/benchmark/_cli.js @@ -6,15 +6,16 @@ const path = require('path'); // Create an object of all benchmark scripts const benchmarks = {}; fs.readdirSync(__dirname) - .filter((name) => fs.statSync(path.resolve(__dirname, name)).isDirectory()) + .filter((name) => { + return name !== 'fixtures' && + fs.statSync(path.resolve(__dirname, name)).isDirectory(); + }) .forEach((category) => { benchmarks[category] = fs.readdirSync(path.resolve(__dirname, category)) .filter((filename) => filename[0] !== '.' && filename[0] !== '_'); }); function CLI(usage, settings) { - if (!(this instanceof CLI)) return new CLI(usage, settings); - if (process.argv.length < 3) { this.abort(usage); // Abort will exit the process } @@ -22,6 +23,7 @@ function CLI(usage, settings) { this.usage = usage; this.optional = {}; this.items = []; + this.test = false; for (const argName of settings.arrayArgs) { this.optional[argName] = []; @@ -34,7 +36,7 @@ function CLI(usage, settings) { if (arg === '--') { // Only items can follow -- mode = 'item'; - } else if ('both' === mode && arg[0] === '-') { + } else if (mode === 'both' && arg[0] === '-') { // Optional arguments declaration if (arg[1] === '-') { @@ -61,6 +63,8 @@ function CLI(usage, settings) { // The next value can be either an option or an item mode = 'both'; + } else if (arg === 'test') { + this.test = true; } else if (['both', 'item'].includes(mode)) { // item arguments this.items.push(arg); @@ -83,9 +87,15 @@ CLI.prototype.abort = function(msg) { CLI.prototype.benchmarks = function() { const paths = []; + if (this.items.includes('all')) { + this.items = Object.keys(benchmarks); + } + for (const category of this.items) { - if (benchmarks[category] === undefined) - continue; + if (benchmarks[category] === undefined) { + console.error(`The "${category}" category does not exist.`); + process.exit(1); + } for (const scripts of benchmarks[category]) { if (this.shouldSkip(scripts)) continue; diff --git a/benchmark/_http-benchmarkers.js b/benchmark/_http-benchmarkers.js index 821dab2d55e683..d0f192e75948b6 100644 --- a/benchmark/_http-benchmarkers.js +++ b/benchmark/_http-benchmarkers.js @@ -43,9 +43,8 @@ class AutocannonBenchmarker { } if (!result || !result.requests || !result.requests.average) { return undefined; - } else { - return result.requests.average; } + return result.requests.average; } } @@ -58,10 +57,13 @@ class WrkBenchmarker { } create(options) { + const duration = typeof options.duration === 'number' ? + Math.max(options.duration, 1) : + options.duration; const args = [ - '-d', options.duration, + '-d', duration, '-c', options.connections, - '-t', 8, + '-t', Math.min(options.connections, require('os').cpus().length || 8), `http://127.0.0.1:${options.port}${options.path}`, ]; for (const field in options.headers) { @@ -77,9 +79,8 @@ class WrkBenchmarker { const throughput = match && +match[1]; if (!isFinite(throughput)) { return undefined; - } else { - return throughput; } + return throughput; } } @@ -89,7 +90,8 @@ class WrkBenchmarker { */ class TestDoubleBenchmarker { constructor(type) { - // `type` is the type ofbenchmarker. Possible values are 'http' and 'http2'. + // `type` is the type of benchmarker. Possible values are 'http' and + // 'http2'. this.name = `test-double-${type}`; this.executable = path.resolve(__dirname, '_test-double-benchmarker.js'); this.present = fs.existsSync(this.executable); @@ -97,10 +99,12 @@ class TestDoubleBenchmarker { } create(options) { - const env = Object.assign({ - duration: options.duration, + process.env.duration = process.env.duration || options.duration || 5; + + const env = { test_url: `http://127.0.0.1:${options.port}${options.path}`, - }, process.env); + ...process.env + }; const child = child_process.fork(this.executable, [this.type], @@ -189,13 +193,14 @@ http_benchmarkers.forEach((benchmarker) => { }); exports.run = function(options, callback) { - options = Object.assign({ + options = { port: exports.PORT, path: '/', connections: 100, duration: 5, benchmarker: exports.default_http_benchmarker, - }, options); + ...options + }; if (!options.benchmarker) { callback(new Error('Could not locate required http benchmarker. See ' + `${requirementsURL} for further instructions.`)); @@ -220,7 +225,8 @@ exports.run = function(options, callback) { child.stderr.pipe(process.stderr); let stdout = ''; - child.stdout.on('data', (chunk) => stdout += chunk.toString()); + child.stdout.setEncoding('utf8'); + child.stdout.on('data', (chunk) => stdout += chunk); child.once('close', (code) => { const elapsed = process.hrtime(benchmarker_start); diff --git a/benchmark/_test-double-benchmarker.js b/benchmark/_test-double-benchmarker.js index b9379b907ffa07..60264dfd46a606 100644 --- a/benchmark/_test-double-benchmarker.js +++ b/benchmark/_test-double-benchmarker.js @@ -7,7 +7,7 @@ if (!['http', 'http2'].includes(myModule)) { const http = require(myModule); -const duration = process.env.duration || 0; +const duration = +process.env.duration; const url = process.env.test_url; const start = process.hrtime(); @@ -18,13 +18,15 @@ function request(res, client) { res.on('error', () => {}); res.on('end', () => { throughput++; - const diff = process.hrtime(start); - if (duration > 0 && diff[0] < duration) { + const [sec, nanosec] = process.hrtime(start); + const ms = sec * 1000 + nanosec / 1e6; + if (ms < duration * 1000) { run(); } else { console.log(JSON.stringify({ throughput })); if (client) { client.destroy(); + process.exit(0); } } }); @@ -33,7 +35,7 @@ function request(res, client) { function run() { if (http.get) { // HTTP http.get(url, request); - } else { // HTTP/2 + } else { // HTTP/2 const client = http.connect(url); client.on('error', (e) => { throw e; }); request(client.request(), client); diff --git a/benchmark/assert/deepequal-buffer.js b/benchmark/assert/deepequal-buffer.js index 6d9162f15173f9..69cca91cc6d752 100644 --- a/benchmark/assert/deepequal-buffer.js +++ b/benchmark/assert/deepequal-buffer.js @@ -6,12 +6,10 @@ const bench = common.createBenchmark(main, { n: [2e4], len: [1e2, 1e3], strict: [0, 1], - method: [ 'deepEqual', 'notDeepEqual' ], + method: ['deepEqual', 'notDeepEqual'], }); function main({ len, n, method, strict }) { - if (!method) - method = 'deepEqual'; const data = Buffer.allocUnsafe(len + 1); const actual = Buffer.alloc(len); const expected = Buffer.alloc(len); diff --git a/benchmark/assert/deepequal-map.js b/benchmark/assert/deepequal-map.js index b88ecf7ce127f9..77408e3d103475 100644 --- a/benchmark/assert/deepequal-map.js +++ b/benchmark/assert/deepequal-map.js @@ -34,8 +34,6 @@ function main({ n, len, method, strict }) { const array = Array(len).fill(1); switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'deepEqual_primitiveOnly': { const values = array.map((_, i) => [`str_${i}`, 123]); benchmark(strict ? deepStrictEqual : deepEqual, n, values); diff --git a/benchmark/assert/deepequal-object.js b/benchmark/assert/deepequal-object.js index e23f6692b3decd..a8c539426a8156 100644 --- a/benchmark/assert/deepequal-object.js +++ b/benchmark/assert/deepequal-object.js @@ -7,7 +7,7 @@ const bench = common.createBenchmark(main, { n: [5e3], size: [1e2, 1e3, 5e4], strict: [0, 1], - method: [ 'deepEqual', 'notDeepEqual' ], + method: ['deepEqual', 'notDeepEqual'], }); function createObj(source, add = '') { @@ -27,9 +27,6 @@ function main({ size, n, method, strict }) { // TODO: Fix this "hack". `n` should not be manipulated. n = Math.min(Math.ceil(n / size), 20); - if (!method) - method = 'deepEqual'; - const source = Array.apply(null, Array(size)); const actual = createObj(source); const expected = createObj(source); diff --git a/benchmark/assert/deepequal-prims-and-objs-big-array-set.js b/benchmark/assert/deepequal-prims-and-objs-big-array-set.js index 0e0ce450bb1a98..ad049ded02ce9d 100644 --- a/benchmark/assert/deepequal-prims-and-objs-big-array-set.js +++ b/benchmark/assert/deepequal-prims-and-objs-big-array-set.js @@ -52,8 +52,6 @@ function main({ n, len, primitive, method, strict }) { const expectedWrongSet = new Set(expectedWrong); switch (method) { - // Empty string falls through to next line as default, mostly for tests. - case '': case 'deepEqual_Array': run(strict ? deepStrictEqual : deepEqual, n, actual, expected); break; diff --git a/benchmark/assert/deepequal-prims-and-objs-big-loop.js b/benchmark/assert/deepequal-prims-and-objs-big-loop.js index 32140f08ded6fb..2d01431b1fc563 100644 --- a/benchmark/assert/deepequal-prims-and-objs-big-loop.js +++ b/benchmark/assert/deepequal-prims-and-objs-big-loop.js @@ -13,12 +13,10 @@ const bench = common.createBenchmark(main, { primitive: Object.keys(primValues), n: [2e4], strict: [0, 1], - method: [ 'deepEqual', 'notDeepEqual' ], + method: ['deepEqual', 'notDeepEqual'], }); function main({ n, primitive, method, strict }) { - if (!method) - method = 'deepEqual'; const prim = primValues[primitive]; const actual = prim; const expected = prim; diff --git a/benchmark/assert/deepequal-set.js b/benchmark/assert/deepequal-set.js index 561a951e6834cc..27ca7c92bce1b0 100644 --- a/benchmark/assert/deepequal-set.js +++ b/benchmark/assert/deepequal-set.js @@ -34,8 +34,6 @@ function main({ n, len, method, strict }) { const array = Array(len).fill(1); switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'deepEqual_primitiveOnly': { const values = array.map((_, i) => `str_${i}`); benchmark(strict ? deepStrictEqual : deepEqual, n, values); diff --git a/benchmark/assert/deepequal-typedarrays.js b/benchmark/assert/deepequal-typedarrays.js index 10ba21a25759e2..188cfce695ed61 100644 --- a/benchmark/assert/deepequal-typedarrays.js +++ b/benchmark/assert/deepequal-typedarrays.js @@ -20,8 +20,6 @@ const bench = common.createBenchmark(main, { }); function main({ type, n, len, method, strict }) { - if (!method) - method = 'deepEqual'; const clazz = global[type]; const actual = new clazz(len); const expected = new clazz(len); diff --git a/benchmark/assert/throws.js b/benchmark/assert/throws.js index c80518377a8742..978ad2f1b8bef0 100644 --- a/benchmark/assert/throws.js +++ b/benchmark/assert/throws.js @@ -15,8 +15,6 @@ function main({ n, method }) { const message = 'failure'; switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'doesNotThrow': bench.start(); for (let i = 0; i < n; ++i) { diff --git a/benchmark/async_hooks/async-resource-vs-destroy.js b/benchmark/async_hooks/async-resource-vs-destroy.js index c9b9a81c5b7c7f..da0b52afa0ec40 100644 --- a/benchmark/async_hooks/async-resource-vs-destroy.js +++ b/benchmark/async_hooks/async-resource-vs-destroy.js @@ -13,14 +13,12 @@ const { } = require('async_hooks'); const { createServer } = require('http'); -// Configuration for the http server -// there is no need for parameters in this test -const connections = 500; -const path = '/'; - const bench = common.createBenchmark(main, { type: ['async-resource', 'destroy', 'async-local-storage'], asyncMethod: ['callbacks', 'async'], + path: '/', + connections: 500, + duration: 5, n: [1e6] }); @@ -165,7 +163,7 @@ const asyncMethods = { 'async': getServeAwait }; -function main({ type, asyncMethod }) { +function main({ type, asyncMethod, connections, duration, path }) { const { server, close } = types[type](asyncMethods[asyncMethod]); server @@ -174,7 +172,8 @@ function main({ type, asyncMethod }) { bench.http({ path, - connections + connections, + duration }, () => { close(); }); diff --git a/benchmark/async_hooks/http-server.js b/benchmark/async_hooks/http-server.js index 9e1c1214240eaa..c8e44849b7466f 100644 --- a/benchmark/async_hooks/http-server.js +++ b/benchmark/async_hooks/http-server.js @@ -3,10 +3,11 @@ const common = require('../common.js'); const bench = common.createBenchmark(main, { asyncHooks: ['init', 'before', 'after', 'all', 'disabled', 'none'], - connections: [50, 500] + connections: [50, 500], + duration: 5 }); -function main({ asyncHooks, connections }) { +function main({ asyncHooks, connections, duration }) { if (asyncHooks !== 'none') { let hooks = { init() {}, @@ -33,6 +34,7 @@ function main({ asyncHooks, connections }) { bench.http({ connections, path, + duration }, () => { server.close(); }); diff --git a/benchmark/buffers/buffer-base64-encode.js b/benchmark/buffers/buffer-base64-encode.js index d8b601bbd181f4..9837828a353c2d 100644 --- a/benchmark/buffers/buffer-base64-encode.js +++ b/benchmark/buffers/buffer-base64-encode.js @@ -25,6 +25,8 @@ const common = require('../common.js'); const bench = common.createBenchmark(main, { len: [64 * 1024 * 1024], n: [32] +}, { + test: { len: 256 } }); function main({ n, len }) { diff --git a/benchmark/buffers/buffer-bytelength.js b/benchmark/buffers/buffer-bytelength.js index 1b324a49f89de8..fbbe0f040da56a 100644 --- a/benchmark/buffers/buffer-bytelength.js +++ b/benchmark/buffers/buffer-bytelength.js @@ -17,9 +17,9 @@ const chars = [ function main({ n, len, encoding }) { let strings = []; - let results = [ len * 16 ]; + let results = [len * 16]; if (encoding === 'buffer') { - strings = [ Buffer.alloc(len * 16, 'a') ]; + strings = [Buffer.alloc(len * 16, 'a')]; } else { for (const string of chars) { // Strings must be built differently, depending on encoding diff --git a/benchmark/buffers/buffer-creation.js b/benchmark/buffers/buffer-creation.js index 38d80da915c070..862bff4fbabe58 100644 --- a/benchmark/buffers/buffer-creation.js +++ b/benchmark/buffers/buffer-creation.js @@ -16,7 +16,6 @@ const bench = common.createBenchmark(main, { function main({ len, n, type }) { let fn, i; switch (type) { - case '': case 'fast-alloc': fn = Buffer.alloc; break; diff --git a/benchmark/buffers/buffer-fill.js b/benchmark/buffers/buffer-fill.js index 02bc2a206c6fe3..8d4d4996068224 100644 --- a/benchmark/buffers/buffer-fill.js +++ b/benchmark/buffers/buffer-fill.js @@ -22,7 +22,7 @@ function main({ n, type, size }) { const buffer = Buffer.allocUnsafe(size); const testFunction = new Function('b', ` for (var i = 0; i < ${n}; i++) { - b.${type || 'fill(0)'}; + b.${type}; } `); bench.start(); diff --git a/benchmark/buffers/buffer-iterate.js b/benchmark/buffers/buffer-iterate.js index de002108a95d65..3e2a897903d435 100644 --- a/benchmark/buffers/buffer-iterate.js +++ b/benchmark/buffers/buffer-iterate.js @@ -21,7 +21,7 @@ function main({ size, type, method, n }) { Buffer.alloc(size) : SlowBuffer(size).fill(0); - const fn = methods[method || 'for']; + const fn = methods[method]; bench.start(); fn(buffer, n); diff --git a/benchmark/buffers/buffer-read-float.js b/benchmark/buffers/buffer-read-float.js index e8c4f8bf549628..656762d1d4f1d0 100644 --- a/benchmark/buffers/buffer-read-float.js +++ b/benchmark/buffers/buffer-read-float.js @@ -9,7 +9,6 @@ const bench = common.createBenchmark(main, { }); function main({ n, type, endian, value }) { - type = type || 'Double'; const buff = Buffer.alloc(8); const fn = `read${type}${endian}`; const values = { diff --git a/benchmark/buffers/buffer-read-with-byteLength.js b/benchmark/buffers/buffer-read-with-byteLength.js index 6ba1594b8ac6eb..c51ab11ae986d7 100644 --- a/benchmark/buffers/buffer-read-with-byteLength.js +++ b/benchmark/buffers/buffer-read-with-byteLength.js @@ -19,7 +19,7 @@ function main({ n, buf, type, byteLength }) { const buff = buf === 'fast' ? Buffer.alloc(8) : require('buffer').SlowBuffer(8); - const fn = `read${type || 'IntBE'}`; + const fn = `read${type}`; buff.writeDoubleLE(0, 0); bench.start(); diff --git a/benchmark/buffers/buffer-read.js b/benchmark/buffers/buffer-read.js index 2ddca60df44c29..e0ec13992c2fae 100644 --- a/benchmark/buffers/buffer-read.js +++ b/benchmark/buffers/buffer-read.js @@ -28,7 +28,7 @@ function main({ n, buf, type }) { const buff = buf === 'fast' ? Buffer.alloc(8) : require('buffer').SlowBuffer(8); - const fn = `read${type || 'UInt8'}`; + const fn = `read${type}`; buff.writeDoubleLE(0, 0); bench.start(); diff --git a/benchmark/buffers/buffer-swap.js b/benchmark/buffers/buffer-swap.js index a33bac4ae3ed78..e43957efbdb095 100644 --- a/benchmark/buffers/buffer-swap.js +++ b/benchmark/buffers/buffer-swap.js @@ -7,6 +7,8 @@ const bench = common.createBenchmark(main, { method: ['swap16', 'swap32', 'swap64'/* , 'htons', 'htonl', 'htonll' */], len: [64, 256, 768, 1024, 2056, 8192], n: [1e6] +}, { + test: { len: 16 } }); // The htons and htonl methods below are used to benchmark the @@ -74,7 +76,7 @@ function genMethod(method) { function main({ method, len, n, aligned = 'true' }) { const buf = createBuffer(len, aligned === 'true'); - const bufferSwap = genMethod(method || 'swap16'); + const bufferSwap = genMethod(method); bufferSwap(n, buf); bench.start(); diff --git a/benchmark/buffers/buffer-write.js b/benchmark/buffers/buffer-write.js index db5a57d0023e72..5025dd2bca0407 100644 --- a/benchmark/buffers/buffer-write.js +++ b/benchmark/buffers/buffer-write.js @@ -74,7 +74,7 @@ function main({ n, buf, type }) { const buff = buf === 'fast' ? Buffer.alloc(8) : require('buffer').SlowBuffer(8); - const fn = `write${type || 'UInt8'}`; + const fn = `write${type}`; if (!/\d/.test(fn)) benchSpecialInt(buff, fn, n); diff --git a/benchmark/buffers/dataview-set.js b/benchmark/buffers/dataview-set.js index a741d11356ea32..b7914fe45f175b 100644 --- a/benchmark/buffers/dataview-set.js +++ b/benchmark/buffers/dataview-set.js @@ -40,7 +40,6 @@ const mod = { }; function main({ n, type }) { - type = type || 'Uint8'; const ab = new ArrayBuffer(8); const dv = new DataView(ab, 0, 8); const le = /LE$/.test(type); diff --git a/benchmark/common.js b/benchmark/common.js index c5791c2bacfd5d..d2103704ab2838 100644 --- a/benchmark/common.js +++ b/benchmark/common.js @@ -3,222 +3,263 @@ const child_process = require('child_process'); const http_benchmarkers = require('./_http-benchmarkers.js'); -exports.buildType = process.features.debug ? 'Debug' : 'Release'; +class Benchmark { + // Used to make sure a benchmark only start a timer once + #started = false; -exports.createBenchmark = function(fn, configs, options) { - return new Benchmark(fn, configs, options); -}; + // Indicate that the benchmark ended + #ended = false; -function Benchmark(fn, configs, options) { - // Use the file name as the name of the benchmark - this.name = require.main.filename.slice(__dirname.length + 1); - // Parse job-specific configuration from the command line arguments - const parsed_args = this._parseArgs(process.argv.slice(2), configs); - this.options = parsed_args.cli; - this.extra_options = parsed_args.extra; - // The configuration list as a queue of jobs - this.queue = this._queue(this.options); - // The configuration of the current job, head of the queue - this.config = this.queue[0]; - // Execution arguments i.e. flags used to run the jobs - this.flags = []; - if (options && options.flags) { - this.flags = this.flags.concat(options.flags); - } - if (process.env.NODE_BENCHMARK_FLAGS) { - const flags = process.env.NODE_BENCHMARK_FLAGS.split(/\s+/); - this.flags = this.flags.concat(flags); - } // Holds process.hrtime value - this._time = [0, 0]; - // Used to make sure a benchmark only start a timer once - this._started = false; - this._ended = false; + #time = [0, 0]; - // this._run will use fork() to create a new process for each configuration - // combination. - if (process.env.hasOwnProperty('NODE_RUN_BENCHMARK_FN')) { - process.nextTick(() => fn(this.config)); - } else { - process.nextTick(() => this._run()); - } -} + // Use the file name as the name of the benchmark + name = require.main.filename.slice(__dirname.length + 1); -Benchmark.prototype._parseArgs = function(argv, configs) { - const cliOptions = {}; - const extraOptions = {}; - const validArgRE = /^(.+?)=([\s\S]*)$/; - // Parse configuration arguments - for (const arg of argv) { - const match = arg.match(validArgRE); - if (!match) { - console.error(`bad argument: ${arg}`); - process.exit(1); - } - const config = match[1]; - - if (configs[config]) { - // Infer the type from the config object and parse accordingly - const isNumber = typeof configs[config][0] === 'number'; - const value = isNumber ? +match[2] : match[2]; - if (!cliOptions[config]) - cliOptions[config] = []; - cliOptions[config].push(value); - } else { - extraOptions[config] = match[2]; + // Execution arguments i.e. flags used to run the jobs + flags = process.env.NODE_BENCHMARK_FLAGS ? + process.env.NODE_BENCHMARK_FLAGS.split(/\s+/) : + []; + + constructor(fn, configs, options = {}) { + // Parse job-specific configuration from the command line arguments + const argv = process.argv.slice(2); + const parsed_args = this._parseArgs(argv, configs, options); + this.options = parsed_args.cli; + this.extra_options = parsed_args.extra; + if (options.flags) { + this.flags = this.flags.concat(options.flags); } - } - return { cli: Object.assign({}, configs, cliOptions), extra: extraOptions }; -}; -Benchmark.prototype._queue = function(options) { - const queue = []; - const keys = Object.keys(options); + // The configuration list as a queue of jobs + this.queue = this._queue(this.options); - // 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]; - const values = options[key]; - const type = typeof values[0]; + // The configuration of the current job, head of the queue + this.config = this.queue[0]; - for (const value of values) { - if (typeof value !== 'number' && typeof value !== 'string') { - throw new TypeError(`configuration "${key}" had type ${typeof value}`); - } - if (typeof value !== type) { - // This is a requirement for being able to consistently and predictably - // parse CLI provided configuration values. - throw new TypeError(`configuration "${key}" has mixed types`); + process.nextTick(() => { + if (process.env.hasOwnProperty('NODE_RUN_BENCHMARK_FN')) { + fn(this.config); + } else { + // _run will use fork() to create a new process for each configuration + // combination. + this._run(); } + }); + } - const currConfig = Object.assign({ [key]: value }, prevConfig); + _parseArgs(argv, configs, options) { + const cliOptions = {}; + + // Check for the test mode first. + const testIndex = argv.indexOf('--test'); + if (testIndex !== -1) { + for (const [key, rawValue] of Object.entries(configs)) { + let value = Array.isArray(rawValue) ? rawValue[0] : rawValue; + // Set numbers to one by default to reduce the runtime. + if (typeof value === 'number') { + if (key === 'dur' || key === 'duration') { + value = 0.05; + } else if (value > 1) { + value = 1; + } + } + cliOptions[key] = [value]; + } + // Override specific test options. + if (options.test) { + for (const [key, value] of Object.entries(options.test)) { + cliOptions[key] = Array.isArray(value) ? value : [value]; + } + } + argv.splice(testIndex, 1); + } else { + // Accept single values instead of arrays. + for (const [key, value] of Object.entries(configs)) { + if (!Array.isArray(value)) + configs[key] = [value]; + } + } - if (keyIndex + 1 < keys.length) { - recursive(keyIndex + 1, currConfig); + const extraOptions = {}; + const validArgRE = /^(.+?)=([\s\S]*)$/; + // Parse configuration arguments + for (const arg of argv) { + const match = arg.match(validArgRE); + if (!match) { + console.error(`bad argument: ${arg}`); + process.exit(1); + } + const [, key, value] = match; + if (Object.prototype.hasOwnProperty.call(configs, key)) { + if (!cliOptions[key]) + cliOptions[key] = []; + cliOptions[key].push( + // Infer the type from the config object and parse accordingly + typeof configs[key][0] === 'number' ? +value : value + ); } else { - queue.push(currConfig); + extraOptions[key] = value; } } + return { cli: { ...configs, ...cliOptions }, extra: extraOptions }; } - if (keys.length > 0) { - recursive(0, {}); - } else { - queue.push({}); - } - - return queue; -}; - -// Benchmark an http server. -exports.default_http_benchmarker = - http_benchmarkers.default_http_benchmarker; -exports.PORT = http_benchmarkers.PORT; - -Benchmark.prototype.http = function(options, cb) { - const self = this; - const http_options = Object.assign({ }, options); - http_options.benchmarker = http_options.benchmarker || - self.config.benchmarker || - self.extra_options.benchmarker || - exports.default_http_benchmarker; - http_benchmarkers.run( - http_options, (error, code, used_benchmarker, result, elapsed) => { - if (cb) { - cb(code); - } - if (error) { - console.error(error); - process.exit(code || 1); + _queue(options) { + const queue = []; + const keys = Object.keys(options); + + // Perform a depth-first walk through all options to generate a + // configuration list that contains all combinations. + function recursive(keyIndex, prevConfig) { + const key = keys[keyIndex]; + const values = options[key]; + + for (const value of values) { + if (typeof value !== 'number' && typeof value !== 'string') { + throw new TypeError( + `configuration "${key}" had type ${typeof value}`); + } + if (typeof value !== typeof values[0]) { + // This is a requirement for being able to consistently and + // predictably parse CLI provided configuration values. + throw new TypeError(`configuration "${key}" has mixed types`); + } + + const currConfig = { [key]: value, ...prevConfig }; + + if (keyIndex + 1 < keys.length) { + recursive(keyIndex + 1, currConfig); + } else { + queue.push(currConfig); + } } - self.config.benchmarker = used_benchmarker; - self.report(result, elapsed); } - ); -}; -Benchmark.prototype._run = function() { - const self = this; - // If forked, report to the parent. - if (process.send) { - process.send({ - type: 'config', - name: this.name, - queueLength: this.queue.length, - }); - } + if (keys.length > 0) { + recursive(0, {}); + } else { + queue.push({}); + } - (function recursive(queueIndex) { - const config = self.queue[queueIndex]; + return queue; + } - // Set NODE_RUN_BENCHMARK_FN to indicate that the child shouldn't construct - // a configuration queue, but just execute the benchmark function. - const childEnv = Object.assign({}, process.env); - childEnv.NODE_RUN_BENCHMARK_FN = ''; + http(options, cb) { + const http_options = { ...options }; + http_options.benchmarker = http_options.benchmarker || + this.config.benchmarker || + this.extra_options.benchmarker || + http_benchmarkers.default_http_benchmarker; + http_benchmarkers.run( + http_options, (error, code, used_benchmarker, result, elapsed) => { + if (cb) { + cb(code); + } + if (error) { + console.error(error); + process.exit(code || 1); + } + this.config.benchmarker = used_benchmarker; + this.report(result, elapsed); + } + ); + } - // Create configuration arguments - const childArgs = []; - for (const key of Object.keys(config)) { - childArgs.push(`${key}=${config[key]}`); - } - for (const key of Object.keys(self.extra_options)) { - childArgs.push(`${key}=${self.extra_options[key]}`); + _run() { + // If forked, report to the parent. + if (process.send) { + process.send({ + type: 'config', + name: this.name, + queueLength: this.queue.length, + }); } - const child = child_process.fork(require.main.filename, childArgs, { - env: childEnv, - execArgv: self.flags.concat(process.execArgv), - }); - child.on('message', sendResult); - child.on('close', (code) => { - if (code) { - process.exit(code); - } + const recursive = (queueIndex) => { + const config = this.queue[queueIndex]; + + // Set NODE_RUN_BENCHMARK_FN to indicate that the child shouldn't + // construct a configuration queue, but just execute the benchmark + // function. + const childEnv = { ...process.env }; + childEnv.NODE_RUN_BENCHMARK_FN = ''; - if (queueIndex + 1 < self.queue.length) { - recursive(queueIndex + 1); + // Create configuration arguments + const childArgs = []; + for (const [key, value] of Object.entries(config)) { + childArgs.push(`${key}=${value}`); + } + for (const [key, value] of Object.entries(this.extra_options)) { + childArgs.push(`${key}=${value}`); } - }); - })(0); -}; -Benchmark.prototype.start = function() { - if (this._started) { - throw new Error('Called start more than once in a single benchmark'); + const child = child_process.fork(require.main.filename, childArgs, { + env: childEnv, + execArgv: this.flags.concat(process.execArgv), + }); + child.on('message', sendResult); + child.on('close', (code) => { + if (code) { + process.exit(code); + } + + if (queueIndex + 1 < this.queue.length) { + recursive(queueIndex + 1); + } + }); + }; + + recursive(0); } - this._started = true; - this._time = process.hrtime(); -}; - -Benchmark.prototype.end = function(operations) { - // Get elapsed time now and do error checking later for accuracy. - const elapsed = process.hrtime(this._time); - if (!this._started) { - throw new Error('called end without start'); - } - if (this._ended) { - throw new Error('called end multiple times'); - } - if (typeof operations !== 'number') { - throw new Error('called end() without specifying operation count'); - } - if (!process.env.NODEJS_BENCHMARK_ZERO_ALLOWED && operations <= 0) { - throw new Error('called end() with operation count <= 0'); + start() { + if (this.#started) { + throw new Error('Called start more than once in a single benchmark'); + } + this.#started = true; + this.#time = process.hrtime(); } - if (elapsed[0] === 0 && elapsed[1] === 0) { - if (!process.env.NODEJS_BENCHMARK_ZERO_ALLOWED) - throw new Error('insufficient clock precision for short benchmark'); - // Avoid dividing by zero - elapsed[1] = 1; + + end(operations) { + // Get elapsed time now and do error checking later for accuracy. + const elapsed = process.hrtime(this.#time); + + if (!this.#started) { + throw new Error('called end without start'); + } + if (this.#ended) { + throw new Error('called end multiple times'); + } + if (typeof operations !== 'number') { + throw new Error('called end() without specifying operation count'); + } + if (!process.env.NODEJS_BENCHMARK_ZERO_ALLOWED && operations <= 0) { + throw new Error('called end() with operation count <= 0'); + } + if (elapsed[0] === 0 && elapsed[1] === 0) { + if (!process.env.NODEJS_BENCHMARK_ZERO_ALLOWED) + throw new Error('insufficient clock precision for short benchmark'); + // Avoid dividing by zero + elapsed[1] = 1; + } + + this.#ended = true; + const time = elapsed[0] + elapsed[1] / 1e9; + const rate = operations / time; + this.report(rate, elapsed); } - this._ended = true; - const time = elapsed[0] + elapsed[1] / 1e9; - const rate = operations / time; - this.report(rate, elapsed); -}; + report(rate, elapsed) { + sendResult({ + name: this.name, + conf: this.config, + rate, + time: elapsed[0] + elapsed[1] / 1e9, + type: 'report', + }); + } +} function formatResult(data) { // Construct configuration string, " A=a, B=b, ..." @@ -242,27 +283,6 @@ function sendResult(data) { console.log(formatResult(data)); } } -exports.sendResult = sendResult; - -Benchmark.prototype.report = function(rate, elapsed) { - sendResult({ - name: this.name, - conf: this.config, - rate: rate, - time: elapsed[0] + elapsed[1] / 1e9, - type: 'report', - }); -}; - -exports.binding = function(bindingName) { - try { - const { internalBinding } = require('internal/test/binding'); - - return internalBinding(bindingName); - } catch { - return process.binding(bindingName); - } -}; const urls = { long: 'http://nodejs.org:89/docs/latest/api/foo/bar/qua/13949281/0f28b/' + @@ -278,7 +298,6 @@ const urls = { percent: 'https://%E4%BD%A0/foo', dot: 'https://example.org/./a/../b/./c', }; -exports.urls = urls; const searchParams = { noencode: 'foo=bar&baz=quux&xyzzy=thud', @@ -293,7 +312,6 @@ const searchParams = { manyblankpairs: '&&&&&&&&&&&&&&&&&&&&&&&&', altspaces: 'foo+bar=baz+quux&xyzzy+thud=quuy+quuz&abc=def+ghi', }; -exports.searchParams = searchParams; function getUrlData(withBase) { const data = require('../test/fixtures/wpt/url/resources/urltestdata.json'); @@ -309,8 +327,6 @@ function getUrlData(withBase) { return result; } -exports.urlDataTypes = Object.keys(urls).concat(['wpt']); - /** * Generate an array of data for URL benchmarks to use. * The size of the resulting data set is the original data size * 2 ** `e`. @@ -354,4 +370,26 @@ function bakeUrlData(type, e = 0, withBase = false, asUrl = false) { } return result; } -exports.bakeUrlData = bakeUrlData; + +module.exports = { + Benchmark, + PORT: http_benchmarkers.PORT, + bakeUrlData, + binding(bindingName) { + try { + const { internalBinding } = require('internal/test/binding'); + + return internalBinding(bindingName); + } catch { + return process.binding(bindingName); + } + }, + buildType: process.features.debug ? 'Debug' : 'Release', + createBenchmark(fn, configs, options) { + return new Benchmark(fn, configs, options); + }, + sendResult, + searchParams, + urlDataTypes: Object.keys(urls).concat(['wpt']), + urls, +}; diff --git a/benchmark/compare.js b/benchmark/compare.js index 53f82bb4b9f1b9..5c9cd03be3fdee 100644 --- a/benchmark/compare.js +++ b/benchmark/compare.js @@ -9,7 +9,7 @@ const BenchmarkProgress = require('./_benchmark_progress.js'); // // Parse arguments // -const cli = CLI(`usage: ./node compare.js [options] [--] ... +const cli = new CLI(`usage: ./node compare.js [options] [--] ... Run each benchmark in the directory many times using two different node versions. More than one directory can be specified. The output is formatted as csv, which can be processed using for diff --git a/benchmark/crypto/aes-gcm-throughput.js b/benchmark/crypto/aes-gcm-throughput.js index b1b08c481700ea..3f2b9ba45eb3f2 100644 --- a/benchmark/crypto/aes-gcm-throughput.js +++ b/benchmark/crypto/aes-gcm-throughput.js @@ -9,9 +9,6 @@ const bench = common.createBenchmark(main, { }); function main({ n, len, cipher }) { - // Default cipher for tests. - if (cipher === '') - cipher = 'aes-128-gcm'; const message = Buffer.alloc(len, 'b'); const key = crypto.randomBytes(keylen[cipher]); const iv = crypto.randomBytes(12); diff --git a/benchmark/crypto/cipher-stream.js b/benchmark/crypto/cipher-stream.js index 4bb1695e2d20cc..47a8931a540447 100644 --- a/benchmark/crypto/cipher-stream.js +++ b/benchmark/crypto/cipher-stream.js @@ -3,16 +3,15 @@ const common = require('../common.js'); const bench = common.createBenchmark(main, { writes: [500], - cipher: [ 'AES192', 'AES256' ], + cipher: ['AES192', 'AES256'], type: ['asc', 'utf', 'buf'], len: [2, 1024, 102400, 1024 * 1024], api: ['legacy', 'stream'] +}, { + flags: ['--no-warnings'] }); function main({ api, cipher, type, len, writes }) { - // Default cipher for tests. - if (cipher === '') - cipher = 'AES192'; if (api === 'stream' && /^v0\.[0-8]\./.test(process.version)) { console.error('Crypto streams not available until v0.10'); // Use the legacy, just so that we can compare them. @@ -27,7 +26,6 @@ function main({ api, cipher, type, len, writes }) { alice.generateKeys(); bob.generateKeys(); - const pubEnc = /^v0\.[0-8]/.test(process.version) ? 'binary' : null; const alice_secret = alice.computeSecret(bob.getPublicKey(), pubEnc, 'hex'); const bob_secret = bob.computeSecret(alice.getPublicKey(), pubEnc, 'hex'); diff --git a/benchmark/es/defaultparams-bench.js b/benchmark/es/defaultparams-bench.js index ab9cc45749c996..fde4cb11ad448a 100644 --- a/benchmark/es/defaultparams-bench.js +++ b/benchmark/es/defaultparams-bench.js @@ -36,8 +36,6 @@ function runDefaultParams(n) { function main({ n, method }) { switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'withoutdefaults': runOldStyleDefaults(n); break; diff --git a/benchmark/es/destructuring-bench.js b/benchmark/es/destructuring-bench.js index f1b484bd47e08f..c07c0383da91ac 100644 --- a/benchmark/es/destructuring-bench.js +++ b/benchmark/es/destructuring-bench.js @@ -36,8 +36,6 @@ function runSwapDestructured(n) { function main({ n, method }) { switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'swap': runSwapManual(n); break; diff --git a/benchmark/es/destructuring-object-bench.js b/benchmark/es/destructuring-object-bench.js index 68dc17073badc2..29c83bd188e89d 100644 --- a/benchmark/es/destructuring-object-bench.js +++ b/benchmark/es/destructuring-object-bench.js @@ -33,8 +33,6 @@ function runDestructured(n) { function main({ n, method }) { switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'normal': runNormal(n); break; diff --git a/benchmark/es/foreach-bench.js b/benchmark/es/foreach-bench.js index 88bfed00fbc27c..6992a1a5749438 100644 --- a/benchmark/es/foreach-bench.js +++ b/benchmark/es/foreach-bench.js @@ -54,8 +54,6 @@ function main({ n, count, method }) { items[i] = i; switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'for': fn = useFor; break; diff --git a/benchmark/es/map-bench.js b/benchmark/es/map-bench.js index 1b3ba4789db073..d0b8534cf7c906 100644 --- a/benchmark/es/map-bench.js +++ b/benchmark/es/map-bench.js @@ -104,8 +104,6 @@ function runMap(n) { function main({ n, method }) { switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'object': runObject(n); break; diff --git a/benchmark/es/restparams-bench.js b/benchmark/es/restparams-bench.js index d568e28744541f..8129bc92533332 100644 --- a/benchmark/es/restparams-bench.js +++ b/benchmark/es/restparams-bench.js @@ -51,8 +51,6 @@ function runUseArguments(n) { function main({ n, method }) { let fn; switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'copy': fn = runCopyArguments; break; diff --git a/benchmark/es/spread-assign.js b/benchmark/es/spread-assign.js index 97a5c5458e396b..970512aa6b93d4 100644 --- a/benchmark/es/spread-assign.js +++ b/benchmark/es/spread-assign.js @@ -18,8 +18,6 @@ function main({ n, context, count, rest, method }) { let obj; // eslint-disable-line no-unused-vars switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case '_extend': bench.start(); for (let i = 0; i < n; i++) diff --git a/benchmark/es/spread-bench.js b/benchmark/es/spread-bench.js index fc56c9433f2add..ae5b4abbb99c02 100644 --- a/benchmark/es/spread-bench.js +++ b/benchmark/es/spread-bench.js @@ -32,8 +32,6 @@ function main({ n, context, count, rest, method }) { args[i] = i; switch (method) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'apply': bench.start(); for (let i = 0; i < n; i++) diff --git a/benchmark/es/string-concatenations.js b/benchmark/es/string-concatenations.js index 72fb7f9969b604..3c0b27e05019d1 100644 --- a/benchmark/es/string-concatenations.js +++ b/benchmark/es/string-concatenations.js @@ -23,8 +23,6 @@ function main({ n, mode }) { let string; switch (mode) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'multi-concat': bench.start(); for (let i = 0; i < n; i++) diff --git a/benchmark/es/string-repeat.js b/benchmark/es/string-repeat.js index 9e33e4acf47118..f4bd616e4ada4b 100644 --- a/benchmark/es/string-repeat.js +++ b/benchmark/es/string-repeat.js @@ -18,8 +18,6 @@ function main({ n, size, encoding, mode }) { let str; switch (mode) { - case '': - // Empty string falls through to next line as default, mostly for tests. case 'Array': bench.start(); for (let i = 0; i < n; i++) diff --git a/benchmark/fs/read-stream-throughput.js b/benchmark/fs/read-stream-throughput.js index 34c25760ea9c38..5984317ff91743 100644 --- a/benchmark/fs/read-stream-throughput.js +++ b/benchmark/fs/read-stream-throughput.js @@ -11,19 +11,18 @@ tmpdir.refresh(); const filename = path.resolve(tmpdir.path, `.removeme-benchmark-garbage-${process.pid}`); -let encodingType, encoding, size, filesize; - const bench = common.createBenchmark(main, { encodingType: ['buf', 'asc', 'utf'], - filesize: [1000 * 1024 * 1024], - size: [1024, 4096, 65535, 1024 * 1024] + filesize: [1000 * 1024], + highWaterMark: [1024, 4096, 65535, 1024 * 1024], + n: 1024 }); function main(conf) { - encodingType = conf.encodingType; - size = conf.size; - filesize = conf.filesize; + const { encodingType, highWaterMark, filesize } = conf; + let { n } = conf; + let encoding = ''; switch (encodingType) { case 'buf': encoding = null; @@ -38,34 +37,8 @@ function main(conf) { throw new Error(`invalid encodingType: ${encodingType}`); } - makeFile(); -} - -function runTest() { - assert(fs.statSync(filename).size === filesize); - const rs = fs.createReadStream(filename, { - highWaterMark: size, - encoding: encoding - }); - - rs.on('open', () => { - bench.start(); - }); - - let bytes = 0; - rs.on('data', (chunk) => { - bytes += chunk.length; - }); - - rs.on('end', () => { - try { fs.unlinkSync(filename); } catch {} - // MB/sec - bench.end(bytes / (1024 * 1024)); - }); -} - -function makeFile() { - const buf = Buffer.allocUnsafe(filesize / 1024); + // Make file + const buf = Buffer.allocUnsafe(filesize); if (encoding === 'utf8') { // ü for (let i = 0; i < buf.length; i++) { @@ -78,16 +51,38 @@ function makeFile() { } try { fs.unlinkSync(filename); } catch {} - let w = 1024; const ws = fs.createWriteStream(filename); - ws.on('close', runTest); + ws.on('close', runTest.bind(null, filesize, highWaterMark, encoding, n)); ws.on('drain', write); write(); function write() { do { - w--; - } while (false !== ws.write(buf) && w > 0); - if (w === 0) + n--; + } while (false !== ws.write(buf) && n > 0); + if (n === 0) ws.end(); } } + +function runTest(filesize, highWaterMark, encoding, n) { + assert(fs.statSync(filename).size === filesize * n); + const rs = fs.createReadStream(filename, { + highWaterMark, + encoding + }); + + rs.on('open', () => { + bench.start(); + }); + + let bytes = 0; + rs.on('data', (chunk) => { + bytes += chunk.length; + }); + + rs.on('end', () => { + try { fs.unlinkSync(filename); } catch {} + // MB/sec + bench.end(bytes / (1024 * 1024)); + }); +} diff --git a/benchmark/fs/readfile.js b/benchmark/fs/readfile.js index 361ffbff597d6e..3f996e02ede876 100644 --- a/benchmark/fs/readfile.js +++ b/benchmark/fs/readfile.js @@ -14,12 +14,12 @@ const filename = path.resolve(tmpdir.path, `.removeme-benchmark-garbage-${process.pid}`); const bench = common.createBenchmark(main, { - dur: [5], + duration: [5], len: [1024, 16 * 1024 * 1024], concurrent: [1, 10] }); -function main({ len, dur, concurrent }) { +function main({ len, duration, concurrent }) { try { fs.unlinkSync(filename); } catch {} let data = Buffer.alloc(len, 'x'); fs.writeFileSync(filename, data); @@ -33,7 +33,7 @@ function main({ len, dur, concurrent }) { bench.end(reads); try { fs.unlinkSync(filename); } catch {} process.exit(0); - }, dur * 1000); + }, duration * 1000); function read() { fs.readFile(filename, afterRead); diff --git a/benchmark/http/chunked.js b/benchmark/http/chunked.js index 52b4605715c322..9ae7bb7495f29a 100644 --- a/benchmark/http/chunked.js +++ b/benchmark/http/chunked.js @@ -13,10 +13,11 @@ const common = require('../common.js'); const bench = common.createBenchmark(main, { n: [1, 4, 8, 16], len: [1, 64, 256], - c: [100] + c: [100], + duration: 5 }); -function main({ len, n, c }) { +function main({ len, n, c, duration }) { const http = require('http'); const chunk = Buffer.alloc(len, '8'); @@ -33,7 +34,8 @@ function main({ len, n, c }) { server.listen(common.PORT, () => { bench.http({ - connections: c + connections: c, + duration }, () => { server.close(); }); diff --git a/benchmark/http/cluster.js b/benchmark/http/cluster.js index 3bcd061a0894c5..0d97b516ec506b 100644 --- a/benchmark/http/cluster.js +++ b/benchmark/http/cluster.js @@ -9,14 +9,15 @@ if (cluster.isMaster) { // Unicode confuses ab on os x. type: ['bytes', 'buffer'], len: [4, 1024, 102400], - c: [50, 500] + c: [50, 500], + duration: 5, }); } else { const port = parseInt(process.env.PORT || PORT); require('../fixtures/simple-http-server.js').listen(port); } -function main({ type, len, c }) { +function main({ type, len, c, duration }) { process.env.PORT = PORT; let workers = 0; const w1 = cluster.fork(); @@ -32,7 +33,8 @@ function main({ type, len, c }) { bench.http({ path: path, - connections: c + connections: c, + duration }, () => { w1.destroy(); w2.destroy(); diff --git a/benchmark/http/end-vs-write-end.js b/benchmark/http/end-vs-write-end.js index 38e9b89a97a6b4..60174ef3adf4f2 100644 --- a/benchmark/http/end-vs-write-end.js +++ b/benchmark/http/end-vs-write-end.js @@ -14,10 +14,11 @@ const bench = common.createBenchmark(main, { type: ['asc', 'utf', 'buf'], len: [64 * 1024, 128 * 1024, 256 * 1024, 1024 * 1024], c: [100], - method: ['write', 'end'] + method: ['write', 'end'], + duration: 5 }); -function main({ len, type, method, c }) { +function main({ len, type, method, c, duration }) { const http = require('http'); let chunk; switch (type) { @@ -49,7 +50,8 @@ function main({ len, type, method, c }) { server.listen(common.PORT, () => { bench.http({ - connections: c + connections: c, + duration }, () => { server.close(); }); diff --git a/benchmark/http/headers.js b/benchmark/http/headers.js index f8014a6a085d19..b83ac17e742a2e 100644 --- a/benchmark/http/headers.js +++ b/benchmark/http/headers.js @@ -6,9 +6,10 @@ const http = require('http'); const bench = common.createBenchmark(main, { n: [10, 1000], len: [1, 100], + duration: 5 }); -function main({ len, n }) { +function main({ len, n, duration }) { const headers = { 'Connection': 'keep-alive', 'Transfer-Encoding': 'chunked', @@ -29,7 +30,8 @@ function main({ len, n }) { server.listen(common.PORT, () => { bench.http({ path: '/', - connections: 10 + connections: 10, + duration }, () => { server.close(); }); diff --git a/benchmark/http/incoming_headers.js b/benchmark/http/incoming_headers.js index 810c92687bd981..983bd5632fcb7d 100644 --- a/benchmark/http/incoming_headers.js +++ b/benchmark/http/incoming_headers.js @@ -3,12 +3,13 @@ const common = require('../common.js'); const http = require('http'); const bench = common.createBenchmark(main, { - c: [50], // Concurrent connections - n: [20], // Number of header lines to append after the common headers - w: [0, 6], // Amount of trailing whitespace + connections: [50], // Concurrent connections + headers: [20], // Number of header lines to append after the common headers + w: [0, 6], // Amount of trailing whitespace + duration: 5 }); -function main({ c, n, w }) { +function main({ connections, headers, w, duration }) { const server = http.createServer((req, res) => { res.end(); }); @@ -21,7 +22,7 @@ function main({ c, n, w }) { 'Date': new Date().toString(), 'Cache-Control': 'no-cache' }; - for (let i = 0; i < n; i++) { + for (let i = 0; i < headers; i++) { // Note: // - autocannon does not send header values with OWS // - wrk can only send trailing OWS. This is a side-effect of wrk @@ -31,8 +32,9 @@ function main({ c, n, w }) { } bench.http({ path: '/', - connections: c, - headers + connections, + headers, + duration }, () => { server.close(); }); diff --git a/benchmark/http/set-header.js b/benchmark/http/set-header.js index 1909c0991dfc71..48e0163a6ced10 100644 --- a/benchmark/http/set-header.js +++ b/benchmark/http/set-header.js @@ -3,7 +3,8 @@ const common = require('../common.js'); const PORT = common.PORT; const bench = common.createBenchmark(main, { - res: ['normal', 'setHeader', 'setHeaderWH'] + res: ['normal', 'setHeader', 'setHeaderWH'], + duration: 5 }); const type = 'bytes'; @@ -15,16 +16,17 @@ const c = 50; // normal: writeHead(status, {...}) // setHeader: statusCode = status, setHeader(...) x2 // setHeaderWH: setHeader(...), writeHead(status, ...) -function main({ res }) { +function main({ res, duration }) { process.env.PORT = PORT; const server = require('../fixtures/simple-http-server.js') .listen(PORT) .on('listening', () => { - const path = `/${type}/${len}/${chunks}/normal/${chunkedEnc}`; + const path = `/${type}/${len}/${chunks}/${res}/${chunkedEnc}`; bench.http({ path: path, - connections: c + connections: c, + duration }, () => { server.close(); }); diff --git a/benchmark/http/simple.js b/benchmark/http/simple.js index 95409faa9a869c..095b15ca4465fb 100644 --- a/benchmark/http/simple.js +++ b/benchmark/http/simple.js @@ -7,18 +7,20 @@ const bench = common.createBenchmark(main, { len: [4, 1024, 102400], chunks: [1, 4], c: [50, 500], - chunkedEnc: [1, 0] + chunkedEnc: [1, 0], + duration: 5 }); -function main({ type, len, chunks, c, chunkedEnc, res }) { +function main({ type, len, chunks, c, chunkedEnc, duration }) { const server = require('../fixtures/simple-http-server.js') .listen(common.PORT) .on('listening', () => { const path = `/${type}/${len}/${chunks}/normal/${chunkedEnc}`; bench.http({ - path: path, - connections: c + path, + connections: c, + duration }, () => { server.close(); }); diff --git a/benchmark/http2/compat.js b/benchmark/http2/compat.js index 5d06ccf3178257..2c7e732b07f0a5 100644 --- a/benchmark/http2/compat.js +++ b/benchmark/http2/compat.js @@ -9,10 +9,11 @@ const bench = common.createBenchmark(main, { requests: [100, 1000, 5000], streams: [1, 10, 20, 40, 100, 200], clients: [2], - benchmarker: ['h2load'] + benchmarker: ['test-double-http2'], + duration: 5 }, { flags: ['--no-warnings'] }); -function main({ requests, streams, clients }) { +function main({ requests, streams, clients, duration }) { const http2 = require('http2'); const server = http2.createServer(); server.on('request', (req, res) => { @@ -29,7 +30,8 @@ function main({ requests, streams, clients }) { requests, maxConcurrentStreams: streams, clients, - threads: clients + threads: clients, + duration }, () => { server.close(); }); }); } diff --git a/benchmark/http2/respond-with-fd.js b/benchmark/http2/respond-with-fd.js index 35856490f7e4a2..5bf5988d16a64c 100644 --- a/benchmark/http2/respond-with-fd.js +++ b/benchmark/http2/respond-with-fd.js @@ -10,10 +10,11 @@ const bench = common.createBenchmark(main, { requests: [100, 1000, 5000], streams: [1, 10, 20, 40, 100, 200], clients: [2], - benchmarker: ['h2load'] + benchmarker: ['test-double-http2'], + duration: 5 }, { flags: ['--no-warnings'] }); -function main({ requests, streams, clients }) { +function main({ requests, streams, clients, duration }) { fs.open(file, 'r', (err, fd) => { if (err) throw err; @@ -30,6 +31,7 @@ function main({ requests, streams, clients }) { requests, maxConcurrentStreams: streams, clients, + duration, threads: clients }, () => server.close()); }); diff --git a/benchmark/http2/simple.js b/benchmark/http2/simple.js index aab7c6b609b715..929c4c655e1295 100644 --- a/benchmark/http2/simple.js +++ b/benchmark/http2/simple.js @@ -9,10 +9,11 @@ const bench = common.createBenchmark(main, { requests: [100, 1000, 5000], streams: [1, 10, 20, 40, 100, 200], clients: [2], - benchmarker: ['h2load'] + benchmarker: ['test-double-http2'], + duration: 5 }, { flags: ['--no-warnings'] }); -function main({ requests, streams, clients }) { +function main({ requests, streams, clients, duration }) { const http2 = require('http2'); const server = http2.createServer(); server.on('stream', (stream) => { @@ -27,6 +28,7 @@ function main({ requests, streams, clients }) { requests, maxConcurrentStreams: streams, clients, + duration, threads: clients }, () => { server.close(); }); }); diff --git a/benchmark/http2/write.js b/benchmark/http2/write.js index fc3203c6e55451..7ea8b2c02da650 100644 --- a/benchmark/http2/write.js +++ b/benchmark/http2/write.js @@ -6,10 +6,11 @@ const bench = common.createBenchmark(main, { streams: [100, 200, 1000], length: [64 * 1024, 128 * 1024, 256 * 1024, 1024 * 1024], size: [100000], - benchmarker: ['h2load'] + benchmarker: ['test-double-http2'], + duration: 5 }, { flags: ['--no-warnings'] }); -function main({ streams, length, size }) { +function main({ streams, length, size, duration }) { const http2 = require('http2'); const server = http2.createServer(); server.on('stream', (stream) => { @@ -29,6 +30,7 @@ function main({ streams, length, size }) { bench.http({ path: '/', requests: 10000, + duration, maxConcurrentStreams: streams, }, () => { server.close(); }); }); diff --git a/benchmark/misc/arguments.js b/benchmark/misc/arguments.js index 8fefe617a51d56..39f4020b1ad20e 100644 --- a/benchmark/misc/arguments.js +++ b/benchmark/misc/arguments.js @@ -34,8 +34,6 @@ function usingPredefined() { function main({ n, method, args }) { let fn; switch (method) { - // '' is a default case for tests - case '': case 'restAndSpread': fn = usingRestAndSpread; break; diff --git a/benchmark/misc/getstringwidth.js b/benchmark/misc/getstringwidth.js index c10f7af8483cf9..9dd4b47df7182e 100644 --- a/benchmark/misc/getstringwidth.js +++ b/benchmark/misc/getstringwidth.js @@ -10,8 +10,6 @@ const bench = common.createBenchmark(main, { }); function main({ n, type }) { - // Default value for testing purposes. - type = type || 'ascii'; const { getStringWidth } = require('internal/util/inspect'); const str = ({ diff --git a/benchmark/misc/object-property-bench.js b/benchmark/misc/object-property-bench.js index 0a4d004999ed23..9b33ac9a636889 100644 --- a/benchmark/misc/object-property-bench.js +++ b/benchmark/misc/object-property-bench.js @@ -64,8 +64,6 @@ function runSymbol(n) { function main({ n, method }) { switch (method) { - // '' is a default case for tests - case '': case 'property': runProperty(n); break; diff --git a/benchmark/misc/punycode.js b/benchmark/misc/punycode.js index 5f85df758ef7e3..9c674b5deefb8c 100644 --- a/benchmark/misc/punycode.js +++ b/benchmark/misc/punycode.js @@ -62,8 +62,6 @@ function runICU(n, val) { function main({ n, val, method }) { switch (method) { - // '' is a default case for tests - case '': case 'punycode': runPunycode(n, val); break; diff --git a/benchmark/misc/trace.js b/benchmark/misc/trace.js index bdbf547007e72e..8620e99329b224 100644 --- a/benchmark/misc/trace.js +++ b/benchmark/misc/trace.js @@ -6,7 +6,11 @@ const bench = common.createBenchmark(main, { n: [100000], method: ['trace', 'isTraceCategoryEnabled'] }, { - flags: ['--expose-internals', '--trace-event-categories', 'foo'] + flags: [ + '--expose-internals', + '--no-warnings', + '--trace-event-categories', 'foo', + ] }); const { @@ -37,7 +41,6 @@ function main({ n, method }) { } = common.binding('trace_events'); switch (method) { - case '': case 'trace': doTrace(n, trace); break; diff --git a/benchmark/misc/util-extend-vs-object-assign.js b/benchmark/misc/util-extend-vs-object-assign.js index b3d95f0e2d97a4..83aec7b9c82231 100644 --- a/benchmark/misc/util-extend-vs-object-assign.js +++ b/benchmark/misc/util-extend-vs-object-assign.js @@ -9,10 +9,6 @@ const bench = common.createBenchmark(main, { }); function main({ n, type }) { - // Default value for tests. - if (type === '') - type = 'extend'; - let fn; if (type === 'extend') { fn = util._extend; diff --git a/benchmark/net/net-c2s.js b/benchmark/net/net-c2s.js index cacd6815630b2e..424c8f6dd072b3 100644 --- a/benchmark/net/net-c2s.js +++ b/benchmark/net/net-c2s.js @@ -9,6 +9,8 @@ const bench = common.createBenchmark(main, { len: [64, 102400, 1024 * 1024 * 16], type: ['utf', 'asc', 'buf'], dur: [5], +}, { + test: { len: 1024 } }); let chunk; diff --git a/benchmark/net/net-pipe.js b/benchmark/net/net-pipe.js index d86ff73041d845..32e1085299a2ce 100644 --- a/benchmark/net/net-pipe.js +++ b/benchmark/net/net-pipe.js @@ -9,6 +9,8 @@ const bench = common.createBenchmark(main, { len: [2, 64, 102400, 1024 * 1024 * 16], type: ['utf', 'asc', 'buf'], dur: [5], +}, { + test: { len: 1024 } }); let chunk; diff --git a/benchmark/net/net-s2c.js b/benchmark/net/net-s2c.js index 789eadf0a18dba..835cc67567bcf2 100644 --- a/benchmark/net/net-s2c.js +++ b/benchmark/net/net-s2c.js @@ -10,6 +10,8 @@ const bench = common.createBenchmark(main, { recvbuflen: [0, 64 * 1024, 1024 * 1024], recvbufgenfn: ['true', 'false'], dur: [5] +}, { + test: { sendchunklen: 256 } }); let chunk; diff --git a/benchmark/net/net-wrap-js-stream-passthrough.js b/benchmark/net/net-wrap-js-stream-passthrough.js index 0d7be36c6aa545..3824cfb9c0e03c 100644 --- a/benchmark/net/net-wrap-js-stream-passthrough.js +++ b/benchmark/net/net-wrap-js-stream-passthrough.js @@ -9,6 +9,7 @@ const bench = common.createBenchmark(main, { type: ['utf', 'asc', 'buf'], dur: [5], }, { + test: { len: 64 }, flags: ['--expose-internals'] }); diff --git a/benchmark/net/tcp-raw-c2s.js b/benchmark/net/tcp-raw-c2s.js index b8af124a7f40fc..9547c01f38bc32 100644 --- a/benchmark/net/tcp-raw-c2s.js +++ b/benchmark/net/tcp-raw-c2s.js @@ -12,7 +12,10 @@ const bench = common.createBenchmark(main, { len: [102400, 1024 * 1024 * 16], type: ['utf', 'asc', 'buf'], dur: [5] -}, { flags: [ '--expose-internals', '--no-warnings' ] }); +}, { + test: { len: 1024 }, + flags: [ '--expose-internals', '--no-warnings' ] +}); function main({ dur, len, type }) { const { diff --git a/benchmark/net/tcp-raw-pipe.js b/benchmark/net/tcp-raw-pipe.js index 249b61046a84cf..e422ff749fd545 100644 --- a/benchmark/net/tcp-raw-pipe.js +++ b/benchmark/net/tcp-raw-pipe.js @@ -13,6 +13,7 @@ const bench = common.createBenchmark(main, { type: ['utf', 'asc', 'buf'], dur: [5] }, { + test: { len: 1024 }, flags: [ '--expose-internals', '--no-warnings' ] }); diff --git a/benchmark/net/tcp-raw-s2c.js b/benchmark/net/tcp-raw-s2c.js index 393cf060489cb8..be7279ca0c315c 100644 --- a/benchmark/net/tcp-raw-s2c.js +++ b/benchmark/net/tcp-raw-s2c.js @@ -13,6 +13,7 @@ const bench = common.createBenchmark(main, { type: ['utf', 'asc', 'buf'], dur: [5] }, { + test: { len: 1024 }, flags: [ '--expose-internals', '--no-warnings' ] }); diff --git a/benchmark/run.js b/benchmark/run.js index 8e81a2c5e16ab7..c2e38ce96d7895 100644 --- a/benchmark/run.js +++ b/benchmark/run.js @@ -4,7 +4,7 @@ const path = require('path'); const fork = require('child_process').fork; const CLI = require('./_cli.js'); -const cli = CLI(`usage: ./node run.js [options] [--] ... +const cli = new CLI(`usage: ./node run.js [options] [--] ... Run each benchmark in the directory a single time, more than one directory can be specified. @@ -14,6 +14,9 @@ const cli = CLI(`usage: ./node run.js [options] [--] ... repeated) --set variable=value set benchmark variable (can be repeated) --format [simple|csv] optional value that specifies the output format + test only run a single configuration from the options + matrix + all each benchmark category is run one after the other `, { arrayArgs: ['set', 'filter', 'exclude'] }); const benchmarks = cli.benchmarks(); @@ -37,7 +40,11 @@ if (format === 'csv') { (function recursive(i) { const filename = benchmarks[i]; - const child = fork(path.resolve(__dirname, filename), cli.optional.set); + const child = fork( + path.resolve(__dirname, filename), + cli.test ? ['--test'] : [], + cli.optional.set + ); if (format !== 'csv') { console.log(); @@ -51,10 +58,10 @@ if (format === 'csv') { // Construct configuration string, " A=a, B=b, ..." let conf = ''; for (const key of Object.keys(data.conf)) { - conf += ` ${key}=${JSON.stringify(data.conf[key])}`; + if (conf !== '') + conf += ' '; + conf += `${key}=${JSON.stringify(data.conf[key])}`; } - // Delete first space of the configuration - conf = conf.slice(1); if (format === 'csv') { // Escape quotes (") for correct csv formatting conf = conf.replace(/"/g, '""'); diff --git a/benchmark/scatter.js b/benchmark/scatter.js index 10649e6bb51e97..ecbf8e0041c837 100644 --- a/benchmark/scatter.js +++ b/benchmark/scatter.js @@ -7,7 +7,7 @@ const CLI = require('./_cli.js'); // // Parse arguments // -const cli = CLI(`usage: ./node scatter.js [options] [--] +const cli = new CLI(`usage: ./node scatter.js [options] [--] Run the benchmark script many times and output the rate (ops/s) together with the benchmark variables as a csv. diff --git a/benchmark/tls/secure-pair.js b/benchmark/tls/secure-pair.js index c52f4cbf918a1d..76658fc3c42ad7 100644 --- a/benchmark/tls/secure-pair.js +++ b/benchmark/tls/secure-pair.js @@ -3,7 +3,9 @@ const common = require('../common.js'); const bench = common.createBenchmark(main, { dur: [5], securing: ['SecurePair', 'TLSSocket', 'clear'], - size: [2, 100, 1024, 1024 * 1024] + size: [100, 1024, 1024 * 1024] +}, { + flags: ['--no-warnings'] }); const fixtures = require('../../test/common/fixtures'); diff --git a/benchmark/tls/throughput.js b/benchmark/tls/throughput.js index 727d20e460008d..3ea84aa84ef453 100644 --- a/benchmark/tls/throughput.js +++ b/benchmark/tls/throughput.js @@ -3,7 +3,7 @@ const common = require('../common.js'); const bench = common.createBenchmark(main, { dur: [5], type: ['buf', 'asc', 'utf'], - size: [2, 1024, 1024 * 1024, 4 * 1024 * 1024, 16 * 1024 * 1024] + size: [100, 1024, 1024 * 1024, 4 * 1024 * 1024, 16 * 1024 * 1024] }); const fixtures = require('../../test/common/fixtures'); diff --git a/benchmark/url/url-format.js b/benchmark/url/url-format.js index 3e91cefd363c37..be5632d2b67367 100644 --- a/benchmark/url/url-format.js +++ b/benchmark/url/url-format.js @@ -13,7 +13,7 @@ const bench = common.createBenchmark(main, { }); function main({ type, n }) { - const input = inputs[type] || ''; + const input = inputs[type]; // Force-optimize url.format() so that the benchmark doesn't get // disrupted by the optimizer kicking in halfway through. diff --git a/benchmark/url/url-parse.js b/benchmark/url/url-parse.js index 751a11201b11e2..b3e83188b2192f 100644 --- a/benchmark/url/url-parse.js +++ b/benchmark/url/url-parse.js @@ -13,7 +13,7 @@ const bench = common.createBenchmark(main, { }); function main({ type, n }) { - const input = inputs[type] || ''; + const input = inputs[type]; bench.start(); for (let i = 0; i < n; i += 1) diff --git a/benchmark/util/format.js b/benchmark/util/format.js index 976e0f4e655486..f7a6caa81c96b6 100644 --- a/benchmark/util/format.js +++ b/benchmark/util/format.js @@ -23,8 +23,7 @@ const bench = common.createBenchmark(main, { }); function main({ n, type }) { - // For testing, if supplied with an empty type, default to string. - const [first, second] = inputs[type || 'string']; + const [first, second] = inputs[type]; bench.start(); for (let i = 0; i < n; i++) { diff --git a/benchmark/util/inspect-array.js b/benchmark/util/inspect-array.js index 4fd73785f789d1..987b40479184d2 100644 --- a/benchmark/util/inspect-array.js +++ b/benchmark/util/inspect-array.js @@ -23,8 +23,6 @@ function main({ n, len, type }) { opts = { showHidden: true }; arr = arr.fill('denseArray'); break; - // For testing, if supplied with an empty type, default to denseArray. - case '': case 'denseArray': arr = arr.fill('denseArray'); break; diff --git a/benchmark/util/type-check.js b/benchmark/util/type-check.js index 5b992e729e63ae..792f61cf6fb217 100644 --- a/benchmark/util/type-check.js +++ b/benchmark/util/type-check.js @@ -31,13 +31,10 @@ const bench = common.createBenchmark(main, { argument: ['true', 'false-primitive', 'false-object'], n: [1e5] }, { - flags: ['--expose-internals'] + flags: ['--expose-internals', '--no-warnings'] }); function main({ type, argument, version, n }) { - // For testing, if supplied with an empty type, default to ArrayBufferView. - type = type || 'ArrayBufferView'; - const util = common.binding('util'); const types = require('internal/util/types'); diff --git a/benchmark/zlib/pipe.js b/benchmark/zlib/pipe.js index 6a1c427bc8380b..76b0ddc6c65a25 100644 --- a/benchmark/zlib/pipe.js +++ b/benchmark/zlib/pipe.js @@ -8,6 +8,11 @@ const bench = common.createBenchmark(main, { duration: [5], type: ['string', 'buffer'], algorithm: ['gzip', 'brotli'] +}, { + test: { + inputLen: 1024, + duration: 0.2 + } }); function main({ inputLen, duration, type, algorithm }) { diff --git a/common.gypi b/common.gypi index 0f52e138ca2fe0..cd6a8649ac69a1 100644 --- a/common.gypi +++ b/common.gypi @@ -102,6 +102,9 @@ 'obj_dir%': '<(PRODUCT_DIR)/obj.target', 'v8_base': '<(PRODUCT_DIR)/libv8_snapshot.a', }], + ['target_arch in "ppc64 s390x"', { + 'v8_enable_backtrace': 1, + }], ], }, @@ -414,6 +417,10 @@ 'defines': [ '_GLIBCXX_USE_C99_MATH' ], 'libraries': [ '-llog' ], }], + ['_toolset=="host"', { + 'cflags': [ '-pthread' ], + 'ldflags': [ '-pthread' ], + }], ], }], ['OS=="mac"', { diff --git a/configure b/configure index 39decd9a55ccc7..bc0a01d985520b 100755 --- a/configure +++ b/configure @@ -7,6 +7,7 @@ # pyenv will alert which shims are available and then will fail the build. _=[ 'exec' '/bin/sh' '-c' ''' test ${TRAVIS} && exec python "$0" "$@" # workaround for pyenv on Travis CI +test ${FORCE_PYTHON2} && exec python2 "$0" "$@" # workaround for gclient which python3.8 >/dev/null && exec python3.8 "$0" "$@" which python3.7 >/dev/null && exec python3.7 "$0" "$@" which python3.6 >/dev/null && exec python3.6 "$0" "$@" diff --git a/configure.py b/configure.py index beb08df0884f76..0190e31b41a214 100755 --- a/configure.py +++ b/configure.py @@ -301,6 +301,27 @@ dest='shared_zlib_libpath', help='a directory to search for the shared zlib DLL') +shared_optgroup.add_option('--shared-brotli', + action='store_true', + dest='shared_brotli', + help='link to a shared brotli DLL instead of static linking') + +shared_optgroup.add_option('--shared-brotli-includes', + action='store', + dest='shared_brotli_includes', + help='directory containing brotli header files') + +shared_optgroup.add_option('--shared-brotli-libname', + action='store', + dest='shared_brotli_libname', + default='brotlidec,brotlienc', + help='alternative lib name to link to [default: %default]') + +shared_optgroup.add_option('--shared-brotli-libpath', + action='store', + dest='shared_brotli_libpath', + help='a directory to search for the shared brotli DLL') + shared_optgroup.add_option('--shared-cares', action='store_true', dest='shared_cares', @@ -680,7 +701,11 @@ def pkg_config(pkg): retval = () for flag in ['--libs-only-l', '--cflags-only-I', '--libs-only-L', '--modversion']: - args += [flag, pkg] + args += [flag] + if isinstance(pkg, list): + args += pkg + else: + args += [pkg] try: proc = subprocess.Popen(shlex.split(pkg_config) + args, stdout=subprocess.PIPE) @@ -1688,6 +1713,7 @@ def make_bin_override(): configure_library('zlib', output) configure_library('http_parser', output) configure_library('libuv', output) +configure_library('brotli', output, pkgname=['libbrotlidec', 'libbrotlienc']) configure_library('cares', output, pkgname='libcares') configure_library('nghttp2', output, pkgname='libnghttp2') configure_v8(output) diff --git a/deps/cares/config/android/ares_config.h b/deps/cares/config/android/ares_config.h index 1a5265a5098d3c..50c8114396b0fd 100644 --- a/deps/cares/config/android/ares_config.h +++ b/deps/cares/config/android/ares_config.h @@ -128,7 +128,7 @@ #define HAVE_GETNAMEINFO 1 /* Define to 1 if you have the getservbyport_r function. */ -#define HAVE_GETSERVBYPORT_R 1 +/* #undef HAVE_GETSERVBYPORT_R */ /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 diff --git a/deps/openssl/openssl-cl_no_asm.gypi b/deps/openssl/openssl-cl_no_asm.gypi index bb9e55de91e3f2..2e12816aa3ebfd 100644 --- a/deps/openssl/openssl-cl_no_asm.gypi +++ b/deps/openssl/openssl-cl_no_asm.gypi @@ -12,9 +12,9 @@ 'includes': ['config/archs/linux-ppc64/no-asm/openssl-cl.gypi'], }, 'target_arch=="s390x" and OS=="linux"', { 'includes': ['config/archs/linux64-s390x/no-asm/openssl-cl.gypi'], - }, 'target_arch=="arm" and OS=="linux"', { + }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl-cl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl-cl.gypi'], }, 'target_arch=="arm64" and OS=="win"', { 'includes': ['config/archs/VC-WIN64-ARM/no-asm/openssl-cl.gypi'], diff --git a/deps/openssl/openssl_no_asm.gypi b/deps/openssl/openssl_no_asm.gypi index 8eb61d970380c3..858c7d895eaee8 100644 --- a/deps/openssl/openssl_no_asm.gypi +++ b/deps/openssl/openssl_no_asm.gypi @@ -13,9 +13,9 @@ 'includes': ['config/archs/linux-ppc64/no-asm/openssl.gypi'], }, 'target_arch=="s390x" and OS=="linux"', { 'includes': ['config/archs/linux64-s390x/no-asm/openssl.gypi'], - }, 'target_arch=="arm" and OS=="linux"', { + }, 'target_arch=="arm" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-armv4/no-asm/openssl.gypi'], - }, 'target_arch=="arm64" and OS=="linux"', { + }, 'target_arch=="arm64" and OS in ("linux", "android")', { 'includes': ['config/archs/linux-aarch64/no-asm/openssl.gypi'], }, 'target_arch=="ia32" and OS=="freebsd"', { 'includes': ['config/archs/BSD-x86/no-asm/openssl.gypi'], diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 116b7537195618..fa0a001527d790 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -261,6 +261,7 @@ 'src/unix/android-ifaddrs.c', 'src/unix/procfs-exepath.c', 'src/unix/random-getrandom.c', + 'src/unix/random-getentropy.c', 'src/unix/random-sysctl-linux.c', 'src/unix/sysinfo-loadavg.c', ], diff --git a/doc/api/addons.md b/doc/api/addons.md index 6b77338348ed96..e6b5704e8fbdd5 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -8,8 +8,8 @@ Addons are dynamically-linked shared objects written in C++. The Addons provide an interface between JavaScript and C/C++ libraries. There are three options for implementing Addons: N-API, nan, or direct -use of internal V8, libuv and Node.js libraries. Unless you need direct -access to functionality which is not exposed by N-API, use N-API. +use of internal V8, libuv and Node.js libraries. Unless there is a need for +direct access to functionality which is not exposed by N-API, use N-API. Refer to [C/C++ Addons with N-API](n-api.html) for more information on N-API. When not using N-API, implementing Addons is complicated, @@ -313,7 +313,7 @@ require('./build/Release/addon'); Once the source code has been written, it must be compiled into the binary `addon.node` file. To do so, create a file called `binding.gyp` in the top-level of the project describing the build configuration of the module -using a JSON-like format. This file is used by [node-gyp][] — a tool written +using a JSON-like format. This file is used by [node-gyp][], a tool written specifically to compile Node.js Addons. ```json diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 59902917169ed1..2d4fc0498b0218 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -170,6 +170,11 @@ provided by AsyncHooks itself. The logging should then be skipped when it was the logging itself that caused AsyncHooks callback to call. By doing this the otherwise infinite recursion is broken. +### Class: `AsyncHook` + +The class `AsyncHook` exposes an interface for tracking lifetime events +of asynchronous operations. + #### `asyncHook.enable()` * Returns: {AsyncHook} A reference to `asyncHook`. @@ -950,6 +955,48 @@ If this method is called outside of an asynchronous context initialized by calling `asyncLocalStorage.run` or `asyncLocalStorage.runAndReturn`, it will return `undefined`. +### `asyncLocalStorage.enterWith(store)` + + +* `store` {any} + +Calling `asyncLocalStorage.enterWith(store)` will transition into the context +for the remainder of the current synchronous execution and will persist +through any following asynchronous calls. + +Example: + +```js +const store = { id: 1 }; +asyncLocalStorage.enterWith(store); +asyncLocalStorage.getStore(); // Returns the store object +someAsyncOperation(() => { + asyncLocalStorage.getStore(); // Returns the same object +}); +``` + +This transition will continue for the _entire_ synchronous execution. +This means that if, for example, the context is entered within an event +handler subsequent event handlers will also run within that context unless +specifically bound to another context with an `AsyncResource`. + +```js +const store = { id: 1 }; + +emitter.on('my-event', () => { + asyncLocalStorage.enterWith(store); +}); +emitter.on('my-event', () => { + asyncLocalStorage.getStore(); // Returns the same object +}); + +asyncLocalStorage.getStore(); // Returns undefined +emitter.emit('my-event'); +asyncLocalStorage.getStore(); // Returns the same object +``` + ### `asyncLocalStorage.run(store, callback[, ...args])` - -Node.js can be started using the `--zero-fill-buffers` command line option to -cause all newly-allocated `Buffer` instances to be zero-filled upon creation by -default. Without the option, buffers created with [`Buffer.allocUnsafe()`][], -[`Buffer.allocUnsafeSlow()`][], and `new SlowBuffer(size)` are not zero-filled. -Use of this flag can have a significant negative impact on performance. Use the -`--zero-fill-buffers` option only when necessary to enforce that newly allocated -`Buffer` instances cannot contain old data that is potentially sensitive. - -```console -$ node --zero-fill-buffers -> Buffer.allocUnsafe(5); - +// Creates a Buffer containing the Latin-1 bytes [0x74, 0xe9, 0x73, 0x74]. +const buf7 = Buffer.from('tést', 'latin1'); ``` -### What makes `Buffer.allocUnsafe()` and `Buffer.allocUnsafeSlow()` "unsafe"? - -When calling [`Buffer.allocUnsafe()`][] and [`Buffer.allocUnsafeSlow()`][], the -segment of allocated memory is *uninitialized* (it is not zeroed-out). While -this design makes the allocation of memory quite fast, the allocated segment of -memory might contain old data that is potentially sensitive. Using a `Buffer` -created by [`Buffer.allocUnsafe()`][] without *completely* overwriting the -memory can allow this old data to be leaked when the `Buffer` memory is read. - -While there are clear performance advantages to using -[`Buffer.allocUnsafe()`][], extra care *must* be taken in order to avoid -introducing security vulnerabilities into an application. - ## Buffers and Character Encodings -When string data is stored in or extracted out of a `Buffer` instance, a -character encoding may be specified. +When converting between `Buffer`s and strings, a character encoding may be +specified. If no character encoding is specified, UTF-8 will be used as the +default. ```js -const buf = Buffer.from('hello world', 'ascii'); +const buf = Buffer.from('hello world', 'utf8'); console.log(buf.toString('hex')); // Prints: 68656c6c6f20776f726c64 console.log(buf.toString('base64')); // Prints: aGVsbG8gd29ybGQ= -console.log(Buffer.from('fhqwhgads', 'ascii')); +console.log(Buffer.from('fhqwhgads', 'utf8')); // Prints: console.log(Buffer.from('fhqwhgads', 'utf16le')); // Prints: ``` -The character encodings currently supported by Node.js include: +The character encodings currently supported by Node.js are the following: -* `'ascii'`: For 7-bit ASCII data only. This encoding is fast and will strip - the high bit if set. +* `'utf8'`: Multi-byte encoded Unicode characters. Many web pages and other + document formats use [UTF-8][]. This is the default character encoding. + When decoding a `Buffer` into a string that does not exclusively contain + valid UTF-8 data, the Unicode replacement character `U+FFFD` � will be used + to represent those errors. -* `'utf8'`: Multibyte encoded Unicode characters. Many web pages and other - document formats use UTF-8. +* `'utf16le'`: Multi-byte encoded Unicode characters. Unlike `'utf8'`, each + character in the string will be encoded using either 2 or 4 bytes. + Node.js only supports the [little-endian][endianness] variant of [UTF-16][]. -* `'utf16le'`: 2 or 4 bytes, little-endian encoded Unicode characters. - Surrogate pairs (U+10000 to U+10FFFF) are supported. +* `'latin1'`: Latin-1 stands for [ISO-8859-1][]. This character encoding only + supports the Unicode characters from `U+0000` to `U+00FF`. Each character is + encoded using a single byte. Characters that do not fit into that range are + truncated and will be mapped to characters in that range. -* `'ucs2'`: Alias of `'utf16le'`. +Converting a `Buffer` into a string using one of the above is referred to as +decoding, and converting a string into a `Buffer` is referred to as encoding. -* `'base64'`: Base64 encoding. When creating a `Buffer` from a string, +Node.js also supports the following two binary-to-text encodings. For +binary-to-text encodings, the naming convention is reversed: Converting a +`Buffer` into a string is typically referred to as encoding, and converting a +string into a `Buffer` as decoding. + +* `'base64'`: [Base64][] encoding. When creating a `Buffer` from a string, this encoding will also correctly accept "URL and Filename Safe Alphabet" as specified in [RFC 4648, Section 5][]. -* `'latin1'`: A way of encoding the `Buffer` into a one-byte encoded string - (as defined by the IANA in [RFC 1345][], - page 63, to be the Latin-1 supplement block and C0/C1 control codes). +* `'hex'`: Encode each byte as two hexadecimal characters. Data truncation + may occur when decoding string that do exclusively contain valid hexadecimal + characters. See below for an example. + +The following legacy character encodings are also supported: -* `'binary'`: Alias for `'latin1'`. +* `'ascii'`: For 7-bit [ASCII][] data only. When encoding a string into a + `Buffer`, this is equivalent to using `'latin1'`. When decoding a `Buffer` + into a string, using encoding this will additionally unset the highest bit of + each byte before decoding as `'latin1'`. + Generally, there should be no reason to use this encoding, as `'utf8'` + (or, if the data is known to always be ASCII-only, `'latin1'`) will be a + better choice when encoding or decoding ASCII-only text. It is only provided + for legacy compatibility. -* `'hex'`: Encode each byte as two hexadecimal characters. Data truncation - may occur for unsanitized input. For example: +* `'binary'`: Alias for `'latin1'`. See [binary strings][] for more background + on this topic. The name of this encoding can be very misleading, as all of the + encodings listed here convert between strings and binary data. For converting + between strings and `Buffer`s, typically `'utf-8'` is the right choice. + +* `'ucs2'`: Alias of `'utf16le'`. UCS-2 used to refer to a variant of UTF-16 + that did not support characters that had code points larger than U+FFFF. + In Node.js, these code points are always supported. ```js Buffer.from('1ag', 'hex'); @@ -222,7 +154,7 @@ the WHATWG specification it is possible that the server actually returned `'win-1252'`-encoded data, and using `'latin1'` encoding may incorrectly decode the characters. -## Buffers and TypedArray +## Buffers and TypedArrays -`Buffer` instances are also [`Uint8Array`][] instances. However, there are -subtle incompatibilities with [`TypedArray`][]. For example, while -[`ArrayBuffer#slice()`][] creates a copy of the slice, the implementation of -[`Buffer#slice()`][`buf.slice()`] creates a view over the existing `Buffer` -without copying, making [`Buffer#slice()`][`buf.slice()`] far more efficient. +`Buffer` instances are also [`Uint8Array`][] instances, which is the language’s +built-in class for working with binary data. [`Uint8Array`][] in turn is a +subclass of [`TypedArray`][]. Therefore, all [`TypedArray`][] methods are also +available on `Buffer`s. However, there are subtle incompatibilities between +the `Buffer` API and the [`TypedArray`][] API. + +In particular: -It is also possible to create new [`TypedArray`][] instances from a `Buffer` -with the following caveats: +* While [`TypedArray#slice()`][] creates a copy of part of the `TypedArray`, + [`Buffer#slice()`][`buf.slice()`] creates a view over the existing `Buffer` + without copying. This behavior can be surprising, and only exists for legacy + compatibility. [`TypedArray#subarray()`][] can be used to achieve the behavior + of [`Buffer#slice()`][`buf.slice()`] on both `Buffer`s and other + `TypedArray`s. +* [`buf.toString()`][] is incompatible with its `TypedArray` equivalent. +* A number of methods, e.g. [`buf.indexOf()`][], support additional arguments. -1. The `Buffer` object's memory is copied to the [`TypedArray`][], not shared. +There are two ways to create new [`TypedArray`][] instances from a `Buffer`. -2. The `Buffer` object's memory is interpreted as an array of distinct -elements, and not as a byte array of the target type. That is, +When passing a `Buffer` to a [`TypedArray`][] constructor, the `Buffer`’s +elements will be copied, interpreted as an array of integers, and not as a byte +array of the target type. For example, `new Uint32Array(Buffer.from([1, 2, 3, 4]))` creates a 4-element -[`Uint32Array`][] with elements `[1, 2, 3, 4]`, not a [`Uint32Array`][] with a -single element `[0x1020304]` or `[0x4030201]`. +[`Uint32Array`][] with elements `[1, 2, 3, 4]`, rather than a +[`Uint32Array`][] with a single element `[0x1020304]` or `[0x4030201]`. -It is possible to create a new `Buffer` that shares the same allocated memory as -a [`TypedArray`][] instance by using the `TypedArray` object's `.buffer` -property. +In order to create a [`TypedArray`][] that shares its memory with the `Buffer`, +the underlying [`ArrayBuffer`][] can be passed to the [`TypedArray`][] +constructor instead: + +```js +const buf = Buffer.from('hello', 'utf16le'); +const uint16arr = new Uint16Array( + buf.buffer, buf.byteOffset, buf.length / Uint16Array.BYTES_PER_ELEMENT); +``` + +It is also possible to create a new `Buffer` that shares the same allocated +memory as a [`TypedArray`][] instance by using the `TypedArray` object’s +`.buffer` property in the same way. [`Buffer.from()`][`Buffer.from(arrayBuf)`] +behaves like `new Uint8Array()` in this context. ```js const arr = new Uint16Array(2); @@ -326,298 +278,101 @@ Additionally, the [`buf.values()`][], [`buf.keys()`][], and The `Buffer` class is a global type for dealing with binary data directly. It can be constructed in a variety of ways. -### `new Buffer(array)` +### Class Method: `Buffer.alloc(size[, fill[, encoding]])` -> Stability: 0 - Deprecated: Use [`Buffer.from(array)`][] instead. - -* `array` {integer[]} An array of bytes to copy from. +* `size` {integer} The desired length of the new `Buffer`. +* `fill` {string|Buffer|Uint8Array|integer} A value to pre-fill the new `Buffer` + with. **Default:** `0`. +* `encoding` {string} If `fill` is a string, this is its encoding. + **Default:** `'utf8'`. -Allocates a new `Buffer` using an `array` of octets. +Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the +`Buffer` will be zero-filled. ```js -// Creates a new Buffer containing the UTF-8 bytes of the string 'buffer'. -const buf = new Buffer([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); +const buf = Buffer.alloc(5); + +console.log(buf); +// Prints: ``` -### `new Buffer(arrayBuffer[, byteOffset[, length]])` - +If `size` is larger than +[`buffer.constants.MAX_LENGTH`][] or smaller than 0, [`ERR_INVALID_OPT_VALUE`][] +is thrown. -> Stability: 0 - Deprecated: Use -> [`Buffer.from(arrayBuffer[, byteOffset[, length]])`][`Buffer.from(arrayBuf)`] -> instead. +If `fill` is specified, the allocated `Buffer` will be initialized by calling +[`buf.fill(fill)`][`buf.fill()`]. -* `arrayBuffer` {ArrayBuffer|SharedArrayBuffer} An [`ArrayBuffer`][], - [`SharedArrayBuffer`][] or the `.buffer` property of a [`TypedArray`][]. -* `byteOffset` {integer} Index of first byte to expose. **Default:** `0`. -* `length` {integer} Number of bytes to expose. - **Default:** `arrayBuffer.byteLength - byteOffset`. +```js +const buf = Buffer.alloc(5, 'a'); -This creates a view of the [`ArrayBuffer`][] or [`SharedArrayBuffer`][] without -copying the underlying memory. For example, when passed a reference to the -`.buffer` property of a [`TypedArray`][] instance, the newly created `Buffer` -will share the same allocated memory as the [`TypedArray`][]. +console.log(buf); +// Prints: +``` -The optional `byteOffset` and `length` arguments specify a memory range within -the `arrayBuffer` that will be shared by the `Buffer`. +If both `fill` and `encoding` are specified, the allocated `Buffer` will be +initialized by calling [`buf.fill(fill, encoding)`][`buf.fill()`]. ```js -const arr = new Uint16Array(2); - -arr[0] = 5000; -arr[1] = 4000; - -// Shares memory with `arr`. -const buf = new Buffer(arr.buffer); +const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64'); console.log(buf); -// Prints: +// Prints: +``` -// Changing the original Uint16Array changes the Buffer also. -arr[1] = 6000; +Calling [`Buffer.alloc()`][] can be measurably slower than the alternative +[`Buffer.allocUnsafe()`][] but ensures that the newly created `Buffer` instance +contents will never contain sensitive data from previous allocations, including +data that might not have been allocated for `Buffer`s. -console.log(buf); -// Prints: -``` +A `TypeError` will be thrown if `size` is not a number. -### `new Buffer(buffer)` +### Class Method: `Buffer.allocUnsafe(size)` -> Stability: 0 - Deprecated: Use [`Buffer.from(buffer)`][] instead. +* `size` {integer} The desired length of the new `Buffer`. -* `buffer` {Buffer|Uint8Array} An existing `Buffer` or [`Uint8Array`][] from - which to copy data. +Allocates a new `Buffer` of `size` bytes. If `size` is larger than +[`buffer.constants.MAX_LENGTH`][] or smaller than 0, [`ERR_INVALID_OPT_VALUE`][] +is thrown. -Copies the passed `buffer` data onto a new `Buffer` instance. +The underlying memory for `Buffer` instances created in this way is *not +initialized*. The contents of the newly created `Buffer` are unknown and +*may contain sensitive data*. Use [`Buffer.alloc()`][] instead to initialize +`Buffer` instances with zeroes. ```js -const buf1 = new Buffer('buffer'); -const buf2 = new Buffer(buf1); +const buf = Buffer.allocUnsafe(10); -buf1[0] = 0x61; +console.log(buf); +// Prints (contents may vary): -console.log(buf1.toString()); -// Prints: auffer -console.log(buf2.toString()); -// Prints: buffer -``` - -### `new Buffer(size)` - - -> Stability: 0 - Deprecated: Use [`Buffer.alloc()`][] instead (also see -> [`Buffer.allocUnsafe()`][]). - -* `size` {integer} The desired length of the new `Buffer`. - -Allocates a new `Buffer` of `size` bytes. If `size` is larger than -[`buffer.constants.MAX_LENGTH`][] or smaller than 0, [`ERR_INVALID_OPT_VALUE`][] -is thrown. A zero-length `Buffer` is created if `size` is 0. - -Prior to Node.js 8.0.0, the underlying memory for `Buffer` instances -created in this way is *not initialized*. The contents of a newly created -`Buffer` are unknown and *may contain sensitive data*. Use -[`Buffer.alloc(size)`][`Buffer.alloc()`] instead to initialize a `Buffer` -with zeroes. - -```js -const buf = new Buffer(10); - -console.log(buf); -// Prints: -``` - -### `new Buffer(string[, encoding])` - - -> 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'`. - -Creates a new `Buffer` containing `string`. The `encoding` parameter identifies -the character encoding of `string`. - -```js -const buf1 = new Buffer('this is a tést'); -const buf2 = new Buffer('7468697320697320612074c3a97374', 'hex'); - -console.log(buf1.toString()); -// Prints: this is a tést -console.log(buf2.toString()); -// Prints: this is a tést -console.log(buf1.toString('ascii')); -// Prints: this is a tC)st -``` - -### Class Method: `Buffer.alloc(size[, fill[, encoding]])` - - -* `size` {integer} The desired length of the new `Buffer`. -* `fill` {string|Buffer|Uint8Array|integer} A value to pre-fill the new `Buffer` - with. **Default:** `0`. -* `encoding` {string} If `fill` is a string, this is its encoding. - **Default:** `'utf8'`. - -Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the -`Buffer` will be *zero-filled*. - -```js -const buf = Buffer.alloc(5); - -console.log(buf); -// Prints: -``` - -If `size` is larger than -[`buffer.constants.MAX_LENGTH`][] or smaller than 0, [`ERR_INVALID_OPT_VALUE`][] -is thrown. A zero-length `Buffer` is created if `size` is 0. - -If `fill` is specified, the allocated `Buffer` will be initialized by calling -[`buf.fill(fill)`][`buf.fill()`]. - -```js -const buf = Buffer.alloc(5, 'a'); - -console.log(buf); -// Prints: -``` - -If both `fill` and `encoding` are specified, the allocated `Buffer` will be -initialized by calling [`buf.fill(fill, encoding)`][`buf.fill()`]. - -```js -const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64'); - -console.log(buf); -// Prints: -``` - -Calling [`Buffer.alloc()`][] can be significantly slower than the alternative -[`Buffer.allocUnsafe()`][] but ensures that the newly created `Buffer` instance -contents will *never contain sensitive data*. - -A `TypeError` will be thrown if `size` is not a number. - -### Class Method: `Buffer.allocUnsafe(size)` - - -* `size` {integer} The desired length of the new `Buffer`. - -Allocates a new `Buffer` of `size` bytes. If `size` is larger than -[`buffer.constants.MAX_LENGTH`][] or smaller than 0, [`ERR_INVALID_OPT_VALUE`][] -is thrown. A zero-length `Buffer` is created if `size` is 0. - -The underlying memory for `Buffer` instances created in this way is *not -initialized*. The contents of the newly created `Buffer` are unknown and -*may contain sensitive data*. Use [`Buffer.alloc()`][] instead to initialize -`Buffer` instances with zeroes. - -```js -const buf = Buffer.allocUnsafe(10); - -console.log(buf); -// Prints (contents may vary): - -buf.fill(0); - -console.log(buf); -// Prints: +buf.fill(0); + +console.log(buf); +// Prints: ``` A `TypeError` will be thrown if `size` is not a number. @@ -657,7 +412,7 @@ allocations under 4KB are sliced from a single pre-allocated `Buffer`. This allows applications to avoid the garbage collection overhead of creating many individually allocated `Buffer` instances. This approach improves both performance and memory usage by eliminating the need to track and clean up as -many persistent objects. +many individual `ArrayBuffer` objects. However, in the case where a developer may need to retain a small chunk of memory from a pool for an indeterminate amount of time, it may be appropriate @@ -682,9 +437,6 @@ socket.on('readable', () => { }); ``` -`Buffer.allocUnsafeSlow()` should be used only as a last resort after a -developer has observed undue memory retention in their applications. - A `TypeError` will be thrown if `size` is not a number. ### Class Method: `Buffer.byteLength(string[, encoding])` @@ -706,12 +458,12 @@ changes: **Default:** `'utf8'`. * Returns: {integer} The number of bytes contained within `string`. -Returns the actual byte length of a string. This is not the same as -[`String.prototype.length`][] since that returns the number of *characters* in -a string. +Returns the byte length of a string when encoded using `encoding`. +This is not the same as [`String.prototype.length`][], which does not account +for the encoding that is used to convert the string into bytes. For `'base64'` and `'hex'`, this function assumes valid input. For strings that -contain non-Base64/Hex-encoded data (e.g. whitespace), the return value might be +contain non-base64/hex-encoded data (e.g. whitespace), the return value might be greater than the length of a `Buffer` created from the string. ```js @@ -723,7 +475,8 @@ console.log(`${str}: ${str.length} characters, ` + ``` When `string` is a `Buffer`/[`DataView`][]/[`TypedArray`][]/[`ArrayBuffer`][]/ -[`SharedArrayBuffer`][], the actual byte length is returned. +[`SharedArrayBuffer`][], the byte length as reported by `.byteLength` +is returned. ### Class Method: `Buffer.compare(buf1, buf2)` * `list` {Buffer[] | Uint8Array[]} List of `Buffer` or [`Uint8Array`][] - instances to concat. + instances to concatenate. * `totalLength` {integer} Total length of the `Buffer` instances in `list` when concatenated. * Returns: {Buffer} @@ -774,9 +528,7 @@ If the list has no items, or if the `totalLength` is 0, then a new zero-length `Buffer` is returned. If `totalLength` is not provided, it is calculated from the `Buffer` instances -in `list`. This however causes an additional loop to be executed in order to -calculate the `totalLength`, so it is faster to provide the length explicitly if -it is already known. +in `list` by adding their lengths. If `totalLength` is provided, it is coerced to an unsigned integer. If the combined length of the `Buffer`s in `list` exceeds `totalLength`, the result is @@ -808,10 +560,11 @@ added: v5.10.0 * `array` {integer[]} -Allocates a new `Buffer` using an `array` of octets. +Allocates a new `Buffer` using an `array` of bytes in the range `0` – `255`. +Array entries outside that range will be truncated to fit into it. ```js -// Creates a new Buffer containing UTF-8 bytes of the string 'buffer'. +// Creates a new Buffer containing the UTF-8 bytes of the string 'buffer'. const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); ``` @@ -824,7 +577,8 @@ added: v5.10.0 --> * `arrayBuffer` {ArrayBuffer|SharedArrayBuffer} An [`ArrayBuffer`][], - [`SharedArrayBuffer`][], or the `.buffer` property of a [`TypedArray`][]. + [`SharedArrayBuffer`][], for example the `.buffer` property of a + [`TypedArray`][]. * `byteOffset` {integer} Index of first byte to expose. **Default:** `0`. * `length` {integer} Number of bytes to expose. **Default:** `arrayBuffer.byteLength - byteOffset`. @@ -938,7 +692,7 @@ added: v5.10.0 * `encoding` {string} The encoding of `string`. **Default:** `'utf8'`. Creates a new `Buffer` containing `string`. The `encoding` parameter identifies -the character encoding of `string`. +the character encoding to be used when converting `string` into bytes. ```js const buf1 = Buffer.from('this is a tést'); @@ -948,8 +702,8 @@ console.log(buf1.toString()); // Prints: this is a tést console.log(buf2.toString()); // Prints: this is a tést -console.log(buf1.toString('ascii')); -// Prints: this is a tC)st +console.log(buf1.toString('latin1')); +// Prints: this is a tést ``` A `TypeError` will be thrown if `string` is not a string or other type @@ -973,8 +727,8 @@ added: v0.9.1 * `encoding` {string} A character encoding name to check. * Returns: {boolean} -Returns `true` if `encoding` contains a supported character encoding, or `false` -otherwise. +Returns `true` if `encoding` is the name of a supported character encoding, +or `false` otherwise. ```js console.log(Buffer.isEncoding('utf-8')); @@ -1013,11 +767,15 @@ The index operator `[index]` can be used to get and set the octet at position range is between `0x00` and `0xFF` (hex) or `0` and `255` (decimal). This operator is inherited from `Uint8Array`, so its behavior on out-of-bounds -access is the same as `UInt8Array`. In other words, getting returns `undefined` -and setting does nothing. +access is the same as `Uint8Array`. In other words, `buf[index]` returns +`undefined` when `index` is negative or `>= buf.length`, and +`buf[index] = value` does not modify the buffer if `index` is negative or +`>= buf.length`. ```js // Copy an ASCII string into a `Buffer` one byte at a time. +// (This only works for ASCII-only strings. In general, one should use +// `Buffer.from()` to perform this conversion.) const str = 'Node.js'; const buf = Buffer.allocUnsafe(str.length); @@ -1026,7 +784,7 @@ for (let i = 0; i < str.length; i++) { buf[i] = str.charCodeAt(i); } -console.log(buf.toString('ascii')); +console.log(buf.toString('utf8')); // Prints: Node.js ``` @@ -1051,23 +809,24 @@ console.log(buffer.buffer === arrayBuffer); * {integer} The `byteOffset` on the underlying `ArrayBuffer` object based on which this `Buffer` object is created. -When setting `byteOffset` in `Buffer.from(ArrayBuffer, byteOffset, length)` -or sometimes when allocating a buffer smaller than `Buffer.poolSize` the +When setting `byteOffset` in `Buffer.from(ArrayBuffer, byteOffset, length)`, +or sometimes when allocating a buffer smaller than `Buffer.poolSize`, the buffer doesn't start from a zero offset on the underlying `ArrayBuffer`. This can cause problems when accessing the underlying `ArrayBuffer` directly -using `buf.buffer`, as the first bytes in this `ArrayBuffer` may be unrelated +using `buf.buffer`, as other parts of the `ArrayBuffer` may be unrelated to the `buf` object itself. -A common issue is when casting a `Buffer` object to a `TypedArray` object, -in this case one needs to specify the `byteOffset` correctly: +A common issue when creating a `TypedArray` object that shares its memory with +a `Buffer` is that in this case one needs to specify the `byteOffset` correctly: ```js // Create a buffer smaller than `Buffer.poolSize`. const nodeBuffer = new Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); -// When casting the Node.js Buffer to an Int8 TypedArray remember to use the -// byteOffset. +// When casting the Node.js Buffer to an Int8Array, use the byteOffset +// to refer only to the part of `nodeBuffer.buffer` that contains the memory +// for `nodeBuffer`. new Int8Array(nodeBuffer.buffer, nodeBuffer.byteOffset, nodeBuffer.length); ``` @@ -1156,9 +915,13 @@ added: v0.1.90 inclusive). **Default:** [`buf.length`][]. * Returns: {integer} The number of bytes copied. -Copies data from a region of `buf` to a region in `target` even if the `target` +Copies data from a region of `buf` to a region in `target`, even if the `target` memory region overlaps with `buf`. +[`TypedArray#set()`][] performs the same operation, and is available for all +TypedArrays, including Node.js `Buffer`s, although it takes different +function arguments. + ```js // Create two `Buffer` instances. const buf1 = Buffer.allocUnsafe(26); @@ -1171,6 +934,8 @@ for (let i = 0; i < 26; i++) { // Copy `buf1` bytes 16 through 19 into `buf2` starting at byte 8 of `buf2`. buf1.copy(buf2, 8, 16, 20); +// This is equivalent to: +// buf2.set(buf1.subarray(16, 20), 8); console.log(buf2.toString('ascii', 0, 25)); // Prints: !!!!!!!!qrst!!!!!!!!!!!!! @@ -1234,7 +999,8 @@ changes: * Returns: {boolean} Returns `true` if both `buf` and `otherBuffer` have exactly the same bytes, -`false` otherwise. +`false` otherwise. Equivalent to +[`buf.compare(otherBuffer) === 0`][`buf.compare()`]. ```js const buf1 = Buffer.from('ABC'); @@ -1299,10 +1065,10 @@ If the final write of a `fill()` operation falls on a multi-byte character, then only the bytes of that character that fit into `buf` are written: ```js -// Fill a `Buffer` with a two-byte character. +// Fill a `Buffer` with character that takes up two bytes in UTF-8. -console.log(Buffer.allocUnsafe(3).fill('\u0222')); -// Prints: +console.log(Buffer.allocUnsafe(5).fill('\u0222')); +// Prints: ``` If `value` contains invalid characters, it is truncated; if no valid @@ -1543,42 +1309,22 @@ added: v0.1.90 * {integer} -Returns the amount of memory allocated for `buf` in bytes. This -does not necessarily reflect the amount of "usable" data within `buf`. +Returns the number of bytes in `buf`. ```js -// Create a `Buffer` and write a shorter ASCII string to it. +// Create a `Buffer` and write a shorter string to it using UTF-8. const buf = Buffer.alloc(1234); console.log(buf.length); // Prints: 1234 -buf.write('some string', 0, 'ascii'); +buf.write('some string', 0, 'utf8'); console.log(buf.length); // Prints: 1234 ``` -While the `length` property is not immutable, changing the value of `length` -can result in undefined and inconsistent behavior. Applications that wish to -modify the length of a `Buffer` should therefore treat `length` as read-only and -use [`buf.slice()`][] to create a new `Buffer`. - -```js -let buf = Buffer.allocUnsafe(10); - -buf.write('abcdefghj', 0, 'ascii'); - -console.log(buf.length); -// Prints: 10 - -buf = buf.slice(0, 5); - -console.log(buf.length); -// Prints: 5 -``` - ### `buf.parent` + +> Stability: 0 - Deprecated: Use [`Buffer.from(array)`][] instead. + +* `array` {integer[]} An array of bytes to copy from. + +See [`Buffer.from(array)`][]. + +### `new Buffer(arrayBuffer[, byteOffset[, length]])` + + +> Stability: 0 - Deprecated: Use +> [`Buffer.from(arrayBuffer[, byteOffset[, length]])`][`Buffer.from(arrayBuf)`] +> instead. + +* `arrayBuffer` {ArrayBuffer|SharedArrayBuffer} An [`ArrayBuffer`][], + [`SharedArrayBuffer`][] or the `.buffer` property of a [`TypedArray`][]. +* `byteOffset` {integer} Index of first byte to expose. **Default:** `0`. +* `length` {integer} Number of bytes to expose. + **Default:** `arrayBuffer.byteLength - byteOffset`. + +See +[`Buffer.from(arrayBuffer[, byteOffset[, length]])`][`Buffer.from(arrayBuf)`]. + +### `new Buffer(buffer)` + + +> Stability: 0 - Deprecated: Use [`Buffer.from(buffer)`][] instead. + +* `buffer` {Buffer|Uint8Array} An existing `Buffer` or [`Uint8Array`][] from + which to copy data. + +See [`Buffer.from(buffer)`][]. + +### `new Buffer(size)` + + +> Stability: 0 - Deprecated: Use [`Buffer.alloc()`][] instead (also see +> [`Buffer.allocUnsafe()`][]). + +* `size` {integer} The desired length of the new `Buffer`. + +See [`Buffer.alloc()`][] and [`Buffer.allocUnsafe()`][]. This variant of the +constructor is equivalent to [`Buffer.allocUnsafe()`][], although using +[`Buffer.alloc()`][] is recommended in code paths that are not critical to +performance. + +### `new Buffer(string[, encoding])` + + +> 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'`. + +See [`Buffer.from(string[, encoding])`][`Buffer.from(string)`]. + ## `buffer.INSPECT_MAX_BYTES` + +Node.js can be started using the `--zero-fill-buffers` command line option to +cause all newly-allocated `Buffer` instances to be zero-filled upon creation by +default. Without the option, buffers created with [`Buffer.allocUnsafe()`][], +[`Buffer.allocUnsafeSlow()`][], and `new SlowBuffer(size)` are not zero-filled. +Use of this flag can have a measurable negative impact on performance. Use the +`--zero-fill-buffers` option only when necessary to enforce that newly allocated +`Buffer` instances cannot contain old data that is potentially sensitive. + +```console +$ node --zero-fill-buffers +> Buffer.allocUnsafe(5); + +``` + +### What makes `Buffer.allocUnsafe()` and `Buffer.allocUnsafeSlow()` "unsafe"? + +When calling [`Buffer.allocUnsafe()`][] and [`Buffer.allocUnsafeSlow()`][], the +segment of allocated memory is *uninitialized* (it is not zeroed-out). While +this design makes the allocation of memory quite fast, the allocated segment of +memory might contain old data that is potentially sensitive. Using a `Buffer` +created by [`Buffer.allocUnsafe()`][] without *completely* overwriting the +memory can allow this old data to be leaked when the `Buffer` memory is read. + +While there are clear performance advantages to using +[`Buffer.allocUnsafe()`][], extra care *must* be taken in order to avoid +introducing security vulnerabilities into an application. + [RFC 4648, Section 5]: https://tools.ietf.org/html/rfc4648#section-5 [WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/ -[`ArrayBuffer#slice()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/slice [`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer [`Buffer.alloc()`]: #buffer_class_method_buffer_alloc_size_fill_encoding [`Buffer.allocUnsafe()`]: #buffer_class_method_buffer_allocunsafe_size @@ -2847,6 +2784,9 @@ This value may depend on the JS engine that is being used. [`String#lastIndexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf [`String.prototype.length`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length [`TypedArray.from()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from +[`TypedArray#set()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set +[`TypedArray#slice()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice +[`TypedArray#subarray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray [`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray [`Uint32Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array [`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array @@ -2858,9 +2798,17 @@ This value may depend on the JS engine that is being used. [`buf.keys()`]: #buffer_buf_keys [`buf.length`]: #buffer_buf_length [`buf.slice()`]: #buffer_buf_slice_start_end +[`buf.toString()`]: #buffer_buf_tostring_encoding_start_end [`buf.values()`]: #buffer_buf_values [`buffer.constants.MAX_LENGTH`]: #buffer_buffer_constants_max_length [`buffer.constants.MAX_STRING_LENGTH`]: #buffer_buffer_constants_max_string_length [`buffer.kMaxLength`]: #buffer_buffer_kmaxlength [`util.inspect()`]: util.html#util_util_inspect_object_options +[ASCII]: https://en.wikipedia.org/wiki/ASCII +[Base64]: https://en.wikipedia.org/wiki/Base64 +[ISO-8859-1]: https://en.wikipedia.org/wiki/ISO-8859-1 +[UTF-8]: https://en.wikipedia.org/wiki/UTF-8 +[UTF-16]: https://en.wikipedia.org/wiki/UTF-16 +[binary strings]: https://developer.mozilla.org/en-US/docs/Web/API/DOMString/Binary +[endianness]: https://en.wikipedia.org/wiki/Endianness [iterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 2baa98f06f516a..137c6901d24632 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -33,6 +33,14 @@ process will block waiting for the pipe buffer to accept more data. This is identical to the behavior of pipes in the shell. Use the `{ stdio: 'ignore' }` option if the output will not be consumed. +The command lookup will be performed using `options.env.PATH` environment +variable if passed in `options` object, otherwise `process.env.PATH` will be +used. To account for the fact that Windows environment variables are +case-insensitive Node.js will lexicographically sort all `env` keys and choose +the first one case-insensitively matching `PATH` to perform command lookup. +This may lead to issues on Windows when passing objects to `env` option that +have multiple variants of `PATH` variable. + The [`child_process.spawn()`][] method spawns the child process asynchronously, without blocking the Node.js event loop. The [`child_process.spawnSync()`][] function provides equivalent functionality in a synchronous manner that blocks diff --git a/doc/api/cli.md b/doc/api/cli.md index 8b45a4b5bb3b99..66cb665fa82e9f 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -170,6 +170,14 @@ added: v12.9.0 Enable experimental JSON support for the ES Module loader. +### `--experimental-loader=module` + + +Specify the `module` of a custom [experimental ECMAScript Module loader][]. +`module` may be either a path to a file, or an ECMAScript Module name. + ### `--experimental-modules` - -Specify the `module` of a custom [experimental ECMAScript Module loader][]. -`module` may be either a path to a file, or an ECMAScript Module name. - ### `--insecure-http-parser` + +Disable [runtime allocation of executable memory][jitless]. This may be +required on some platforms for security reasons. It can also reduce attack +surface on other platforms, but the performance impact may be severe. + +This flag is inherited from V8 and is subject to change upstream. It may +disappear in a non-semver-major release. + ### `--max-http-header-size=size` The TLS socket must be connected and securily established. Ensure the 'secure' -event is emitted, before you continue. +event is emitted before continuing. ### `ERR_TLS_INVALID_PROTOCOL_METHOD` diff --git a/doc/api/esm.md b/doc/api/esm.md index 7abaab87e0f6f5..60c0a6f286c0ec 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -431,6 +431,51 @@ thrown: } ``` +#### Self-referencing a package using its name + +Within a package, the values defined in the package’s +`package.json` `"exports"` field can be referenced via the package’s name. +For example, assuming the `package.json` is: + +```json +// package.json +{ + "name": "a-package", + "exports": { + ".": "./main.mjs", + "./foo": "./foo.js" + } +} +``` + +Then any module _in that package_ can reference an export in the package itself: + +```js +// ./a-module.mjs +import { something } from 'a-package'; // Imports "something" from ./main.mjs. +``` + +Self-referencing is available only if `package.json` has `exports`, and will +allow importing only what that `exports` (in the `package.json`) allows. +So the code below, given the package above, will generate a runtime error: + +```js +// ./another-module.mjs + +// Imports "another" from ./m.mjs. Fails because +// the "package.json" "exports" field +// does not provide an export named "./m.mjs". +import { another } from 'a-package/m.mjs'; +``` + +Self-referencing is also available when using `require`, both in an ES module, +and in a CommonJS one. For example, this code will also work: + +```js +// ./a-module.js +const { something } = require('a-package/foo'); // Loads from ./foo.js. +``` + ### Dual CommonJS/ES Module Packages Prior to the introduction of support for ES modules in Node.js, it was a common diff --git a/doc/api/fs.md b/doc/api/fs.md index 921decd751cba8..ae339f6da2fa41 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1720,9 +1720,9 @@ By default, the stream will not emit a `'close'` event after it has been destroyed. This is the opposite of the default for other `Readable` streams. Set the `emitClose` option to `true` to change this behavior. -By providing the `fs` option it is possible to override the corresponding `fs` -implementations for `open`, `read` and `close`. When providing the `fs` option, -you must override `open`, `close` and `read`. +By providing the `fs` option, it is possible to override the corresponding `fs` +implementations for `open`, `read`, and `close`. When providing the `fs` option, +overrides for `open`, `read`, and `close` are required. ```js const fs = require('fs'); @@ -1816,8 +1816,8 @@ Set the `emitClose` option to `true` to change this behavior. By providing the `fs` option it is possible to override the corresponding `fs` implementations for `open`, `write`, `writev` and `close`. Overriding `write()` without `writev()` can reduce performance as some optimizations (`_writev()`) -will be disabled. When providing the `fs` option, you must override `open`, -`close` and at least one of `write` and `writev`. +will be disabled. When providing the `fs` option, overrides for `open`, +`close`, and at least one of `write` and `writev` are required. Like [`ReadStream`][], if `fd` is specified, [`WriteStream`][] will ignore the `path` argument and will use the specified file descriptor. This means that no @@ -2463,8 +2463,10 @@ changes: * `callback` {Function} * `err` {Error} -Asynchronously creates a directory. No arguments other than a possible exception -are given to the completion callback. +Asynchronously creates a directory. + +The callback is given a possible exception and, if `recursive` is `true`, the +first folder path created, `(err, [path])`. The optional `options` argument can be an integer specifying mode (permission and sticky bits), or an object with a `mode` property and a `recursive` @@ -2508,8 +2510,10 @@ changes: * `options` {Object|integer} * `recursive` {boolean} **Default:** `false` * `mode` {string|integer} Not supported on Windows. **Default:** `0o777`. +* Returns: {string|undefined} -Synchronously creates a directory. Returns `undefined`. +Synchronously creates a directory. Returns `undefined`, or if `recursive` is +`true`, the first folder path created. This is the synchronous version of [`fs.mkdir()`][]. See also: mkdir(2). @@ -2771,6 +2775,29 @@ The callback is given the three arguments, `(err, bytesRead, buffer)`. If this method is invoked as its [`util.promisify()`][]ed version, it returns a `Promise` for an `Object` with `bytesRead` and `buffer` properties. +## `fs.read(fd, [options,] callback)` + +* `fd` {integer} +* `options` {Object} + * `buffer` {Buffer|TypedArray|DataView} **Default:** `Buffer.alloc(16384)` + * `offset` {integer} **Default:** `0` + * `length` {integer} **Default:** `buffer.length` + * `position` {integer} **Default:** `null` +* `callback` {Function} + * `err` {Error} + * `bytesRead` {integer} + * `buffer` {Buffer} + +Similar to the above `fs.read` function, this version takes an optional `options` object. +If no `options` object is specified, it will default with the above values. + ## `fs.readdir(path[, options], callback)` +* `options` {Object} + * `buffer` {Buffer|Uint8Array} **Default:** `Buffer.alloc(16384)` + * `offset` {integer} **Default:** `0` + * `length` {integer} **Default:** `buffer.length` + * `position` {integer} **Default:** `null` +* Returns: {Promise} + #### `filehandle.readFile(options)` + +* {number} Timeout in milliseconds. **Default:** 0 (no timeout) + +The number of milliseconds of inactivity before a socket is presumed +to have timed out. + +A value of `0` will disable the timeout behavior on incoming connections. + +The socket timeout logic is set up on connection, so changing this +value only affects new connections to the server, not any existing connections. + ### Class: `Http2SecureServer` + +* {number} Timeout in milliseconds. **Default:** 0 (no timeout) + +The number of milliseconds of inactivity before a socket is presumed +to have timed out. + +A value of `0` will disable the timeout behavior on incoming connections. + +The socket timeout logic is set up on connection, so changing this +value only affects new connections to the server, not any existing connections. + ### `http2.createServer(options[, onRequestHandler])` ```C @@ -401,6 +402,7 @@ by the previous call, it will not be called. ### napi_get_instance_data ```C @@ -1663,10 +1665,9 @@ the `napi_value` in question is of the JavaScript type expected by the API. #### napi_key_collection_mode -> Stability: 1 - Experimental - ```C typedef enum { napi_key_include_prototypes, @@ -1685,10 +1686,9 @@ of the objects's prototype chain as well. #### napi_key_filter -> Stability: 1 - Experimental - ```C typedef enum { napi_key_all_properties = 0, @@ -1705,10 +1705,9 @@ Property filter bits. They can be or'ed to build a composite filter. #### napi_key_conversion -> Stability: 1 - Experimental - ```C typedef enum { napi_key_keep_numbers, @@ -2262,10 +2261,9 @@ The JavaScript `Number` type is described in #### napi_create_bigint_int64 -> Stability: 1 - Experimental - ```C napi_status napi_create_bigint_int64(napi_env env, int64_t value, @@ -2283,10 +2281,9 @@ This API converts the C `int64_t` type to the JavaScript `BigInt` type. #### napi_create_bigint_uint64 -> Stability: 1 - Experimental - ```C napi_status napi_create_bigint_uint64(napi_env env, uint64_t value, @@ -2304,10 +2301,9 @@ This API converts the C `uint64_t` type to the JavaScript `BigInt` type. #### napi_create_bigint_words -> Stability: 1 - Experimental - ```C napi_status napi_create_bigint_words(napi_env env, int sign_bit, @@ -2653,10 +2649,9 @@ This API returns the C double primitive equivalent of the given JavaScript #### napi_get_value_bigint_int64 -> Stability: 1 - Experimental - ```C napi_status napi_get_value_bigint_int64(napi_env env, napi_value value, @@ -2680,10 +2675,9 @@ This API returns the C `int64_t` primitive equivalent of the given JavaScript #### napi_get_value_bigint_uint64 -> Stability: 1 - Experimental - ```C napi_status napi_get_value_bigint_uint64(napi_env env, napi_value value, @@ -2707,10 +2701,9 @@ This API returns the C `uint64_t` primitive equivalent of the given JavaScript #### napi_get_value_bigint_words -> Stability: 1 - Experimental - ```C napi_status napi_get_value_bigint_words(napi_env env, napi_value value, @@ -3595,10 +3588,9 @@ included. #### napi_get_all_property_names -> Stability: 1 - Experimental - ```C napi_get_all_property_names(napi_env env, napi_value object, diff --git a/doc/api/net.md b/doc/api/net.md index 84bda5e4e9bfed..ea0b9139fd33f1 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -939,7 +939,7 @@ added: v0.1.90 * Returns: {boolean} Sends data on the socket. The second parameter specifies the encoding in the -case of a string — it defaults to UTF8 encoding. +case of a string. It defaults to UTF8 encoding. Returns `true` if the entire data was flushed successfully to the kernel buffer. Returns `false` if all or part of the data was queued in user memory. diff --git a/doc/api/os.md b/doc/api/os.md index bb5bd612382ce5..a57297bc325555 100644 --- a/doc/api/os.md +++ b/doc/api/os.md @@ -389,6 +389,20 @@ operating system response. Throws a [`SystemError`][] if a user has no `username` or `homedir`. +## `os.version()` + + +* Returns {string} + +Returns a string identifying the kernel version. + +On POSIX systems, the operating system release is determined by calling +[uname(3)][]. On Windows, `RtlGetVersion()` is used, and if it is not available, +`GetVersionExW()` will be used. See +https://en.wikipedia.org/wiki/Uname#Examples for more information. + ## OS Constants The following constants are exported by `os.constants`. diff --git a/doc/api/path.md b/doc/api/path.md index 477ef2cab09e82..c05a5c29efb12f 100644 --- a/doc/api/path.md +++ b/doc/api/path.md @@ -389,7 +389,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 are purely for formatting) +(All spaces in the "" line should be ignored. They are purely for formatting.) ``` On Windows: @@ -411,7 +411,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 are 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/policy.md b/doc/api/policy.md index bf4cc214552eff..35ea48b40b410e 100644 --- a/doc/api/policy.md +++ b/doc/api/policy.md @@ -166,9 +166,9 @@ only with care after auditing a module to ensure its behavior is valid. #### Example: Patched Dependency -Since a dependency can be redirected, you can provide attenuated or modified -forms of dependencies as fits your application. For example, you could log -data about timing of function durations by wrapping the original: +Redirected dependencies can provide attenuated or modified functionality as fits +the application. For example, log data about timing of function durations by +wrapping the original: ```js const original = require('fn'); diff --git a/doc/api/process.md b/doc/api/process.md index 9850711d596e6f..34bc51d9f58111 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -190,7 +190,7 @@ rejection handler. There is no notion of a top level for a `Promise` chain at which rejections can always be handled. Being inherently asynchronous in nature, a `Promise` -rejection can be handled at a future point in time — possibly much later than +rejection can be handled at a future point in time, possibly much later than the event loop turn it takes for the `'unhandledRejection'` event to be emitted. Another way of stating this is that, unlike in synchronous code where there is @@ -502,7 +502,7 @@ process.on('SIGTERM', handle); * `'SIGTERM'` is not supported on Windows, it can be listened on. * `'SIGINT'` from the terminal is supported on all platforms, and can usually be generated with `+C` (though this may be configurable). It is not - generated when terminal raw mode is enabled. + generated when [terminal raw mode][] is enabled and `+C` is used. * `'SIGBREAK'` is delivered on Windows when `+` is pressed, on non-Windows platforms it can be listened on, but there is no way to send or generate it. @@ -518,11 +518,17 @@ process.on('SIGTERM', handle); the process hanging in an endless loop, since listeners attached using `process.on()` are called asynchronously and therefore unable to correct the underlying problem. - -Windows does not support sending signals, but Node.js offers some emulation -with [`process.kill()`][], and [`subprocess.kill()`][]. Sending signal `0` can -be used to test for the existence of a process. Sending `SIGINT`, `SIGTERM`, -and `SIGKILL` cause the unconditional termination of the target process. +* `0` can be sent to test for the existence of a process, it has no effect if + the process exists, but will throw an error if the process does not exist. + +Windows does not support signals so has no equivalent to termination by signal, +but Node.js offers some emulation with [`process.kill()`][], and +[`subprocess.kill()`][]: +* Sending `SIGINT`, `SIGTERM`, and `SIGKILL` will cause the unconditional + termination of the target process, and afterwards, subprocess will report that + the process was terminated by signal. +* Sending signal `0` can be used as a platform independent way to test for the + existence of a process. ## `process.abort()` -* `encoding` {string} The character encoding the `StringDecoder` will use. +* `encoding` {string} The character [encoding][] the `StringDecoder` will use. **Default:** `'utf8'`. Creates a new `StringDecoder` instance. @@ -88,3 +88,5 @@ Returns a decoded string, ensuring that any incomplete multibyte characters at the end of the `Buffer`, or `TypedArray`, or `DataView` are omitted from the returned string and stored in an internal buffer for the next call to `stringDecoder.write()` or `stringDecoder.end()`. + +[encoding]: buffer.html#buffer_buffers_and_character_encodings diff --git a/doc/api/url.md b/doc/api/url.md index a198b699cd31d8..49f56509fe41e9 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -47,7 +47,7 @@ WHATWG URL's `origin` property includes `protocol` and `host`, but not ├─────────────┴─────────────────────┴────────────────────────┴──────────┴────────────────┴───────┤ │ href │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ -(all spaces in the "" line should be ignored — they are purely for formatting) +(All spaces in the "" line should be ignored. They are purely for formatting.) ``` Parsing the URL string using the WHATWG API: diff --git a/doc/api/wasi.md b/doc/api/wasi.md index 3a72442d77f223..27dceaa014f7e8 100644 --- a/doc/api/wasi.md +++ b/doc/api/wasi.md @@ -58,6 +58,10 @@ added: v13.3.0 sandbox directory structure. The string keys of `preopens` are treated as directories within the sandbox. The corresponding values in `preopens` are the real paths to those directories on the host machine. + * `returnOnExit` {boolean} By default, WASI applications terminate the Node.js + process via the `__wasi_proc_exit()` function. Setting this option to `true` + causes `wasi.start()` to return the exit code rather than terminate the + process. **Default:** `false`. ### `wasi.start(instance)` + +* Returns: {Promise} A promise for a Readable Stream containing + a V8 heap snapshot + +Returns a readable stream for a V8 snapshot of the current state of the Worker. +See [`v8.getHeapSnapshot()`][] for more details. + +If the Worker thread is no longer running, which may occur before the +[`'exit'` event][] is emitted, the returned `Promise` will be rejected +immediately with an [`ERR_WORKER_NOT_RUNNING`][] error. + ### `worker.postMessage(value[, transferList])` - -* Returns: {Promise} A promise for a Readable Stream containing - a V8 heap snapshot - -Returns a readable stream for a V8 snapshot of the current state of the Worker. -See [`v8.getHeapSnapshot()`][] for more details. - -If the Worker thread is no longer running, which may occur before the -[`'exit'` event][] is emitted, the returned `Promise` will be rejected -immediately with an [`ERR_WORKER_NOT_RUNNING`][] error. - ### `worker.terminate()`

Gold Sponsors

-

Shopify Salesforce Badoo Airbnb Facebook Open Source

Silver Sponsors

+

Shopify Salesforce MagicLab Airbnb Facebook Open Source

Silver Sponsors

AMP Project

Bronze Sponsors

-

UI UX Design Agencies Top Web Design Agencies Bugsnag Stability Monitoring Crosswordsolver Codacy Mixpanel VPS Server Free Icons by Icons8 EduBirdie clay Discord ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

+

Nettikasinot.org BonusFinder Deutschland Top Web Design Agencies Bugsnag Stability Monitoring Crosswordsolver Mixpanel VPS Server Free Icons by Icons8 UI UX Design Agencies clay Discord ThemeIsle TekHattan Marfeel Fire Stick Tricks JSHeroes

## Technology Sponsors * Site search ([eslint.org](https://eslint.org)) is sponsored by [Algolia](https://www.algolia.com) - - -[npm-image]: https://img.shields.io/npm/v/eslint.svg?style=flat-square -[npm-url]: https://www.npmjs.com/package/eslint -[downloads-image]: https://img.shields.io/npm/dm/eslint.svg?style=flat-square -[downloads-url]: https://www.npmjs.com/package/eslint diff --git a/tools/node_modules/eslint/conf/category-list.json b/tools/node_modules/eslint/conf/category-list.json index 5427667b09e332..6609734950a443 100644 --- a/tools/node_modules/eslint/conf/category-list.json +++ b/tools/node_modules/eslint/conf/category-list.json @@ -10,12 +10,12 @@ ], "deprecated": { "name": "Deprecated", - "description": "These rules have been deprecated in accordance with the [deprecation policy](/docs/user-guide/rule-deprecation), and replaced by newer rules:", + "description": "These rules have been deprecated in accordance with the deprecation policy, and replaced by newer rules:", "rules": [] }, "removed": { "name": "Removed", - "description": "These rules from older versions of ESLint (before the [deprecation policy](/docs/user-guide/rule-deprecation) existed) have been replaced by newer rules:", + "description": "These rules from older versions of ESLint (before the deprecation policy existed) have been replaced by newer rules:", "rules": [ { "removed": "generator-star", "replacedBy": ["generator-star-spacing"] }, { "removed": "global-strict", "replacedBy": ["strict"] }, diff --git a/tools/node_modules/eslint/conf/default-cli-options.js b/tools/node_modules/eslint/conf/default-cli-options.js index 0f7b377fb362ec..e09a829d17cee2 100644 --- a/tools/node_modules/eslint/conf/default-cli-options.js +++ b/tools/node_modules/eslint/conf/default-cli-options.js @@ -12,7 +12,7 @@ module.exports = { useEslintrc: true, envs: [], globals: [], - extensions: [".js"], + extensions: null, ignore: true, ignorePath: void 0, cache: false, diff --git a/tools/node_modules/eslint/conf/environments.js b/tools/node_modules/eslint/conf/environments.js index 10e6fdaa70fca5..ee5ee1b4e5b2ab 100644 --- a/tools/node_modules/eslint/conf/environments.js +++ b/tools/node_modules/eslint/conf/environments.js @@ -15,7 +15,7 @@ const globals = require("globals"); //------------------------------------------------------------------------------ /** - * Get the object that has differentce. + * Get the object that has difference. * @param {Record} current The newer object. * @param {Record} prev The older object. * @returns {Record} The difference object. diff --git a/tools/node_modules/eslint/conf/eslint-recommended.js b/tools/node_modules/eslint/conf/eslint-recommended.js index e915ec449040e9..2137685fb7c63e 100644 --- a/tools/node_modules/eslint/conf/eslint-recommended.js +++ b/tools/node_modules/eslint/conf/eslint-recommended.js @@ -26,6 +26,7 @@ module.exports = { "no-delete-var": "error", "no-dupe-args": "error", "no-dupe-class-members": "error", + "no-dupe-else-if": "error", "no-dupe-keys": "error", "no-duplicate-case": "error", "no-empty": "error", @@ -37,6 +38,7 @@ module.exports = { "no-fallthrough": "error", "no-func-assign": "error", "no-global-assign": "error", + "no-import-assign": "error", "no-inner-declarations": "error", "no-invalid-regexp": "error", "no-irregular-whitespace": "error", @@ -49,6 +51,7 @@ module.exports = { "no-redeclare": "error", "no-regex-spaces": "error", "no-self-assign": "error", + "no-setter-return": "error", "no-shadow-restricted-names": "error", "no-sparse-arrays": "error", "no-this-before-super": "error", diff --git a/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js b/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js index 52703a873bb67e..f91dea4c448276 100644 --- a/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js +++ b/tools/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js @@ -26,6 +26,7 @@ const os = require("os"); const path = require("path"); const { validateConfigArray } = require("../shared/config-validator"); +const { emitDeprecationWarning } = require("../shared/deprecation-warnings"); const { ConfigArrayFactory } = require("./config-array-factory"); const { ConfigArray, ConfigDependency, IgnorePattern } = require("./config-array"); const loadRules = require("./load-rules"); @@ -105,6 +106,7 @@ function createBaseConfigArray({ */ if (rulePaths && rulePaths.length > 0) { baseConfigArray.push({ + type: "config", name: "--rulesdir", filePath: "", plugins: { @@ -290,10 +292,11 @@ class CascadingConfigArrayFactory { /** * Load and normalize config files from the ancestor directories. * @param {string} directoryPath The path to a leaf directory. + * @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories. * @returns {ConfigArray} The loaded config. * @private */ - _loadConfigInAncestors(directoryPath) { + _loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) { const { baseConfigArray, configArrayFactory, @@ -320,6 +323,16 @@ class CascadingConfigArrayFactory { // Consider this is root. if (directoryPath === homePath && cwd !== homePath) { debug("Stop traversing because of considered root."); + if (configsExistInSubdirs) { + const filePath = ConfigArrayFactory.getPathToConfigFileInDirectory(directoryPath); + + if (filePath) { + emitDeprecationWarning( + filePath, + "ESLINT_PERSONAL_CONFIG_SUPPRESS" + ); + } + } return this._cacheConfig(directoryPath, baseConfigArray); } @@ -344,7 +357,10 @@ class CascadingConfigArrayFactory { // Load from the ancestors and merge it. const parentPath = path.dirname(directoryPath); const parentConfigArray = parentPath && parentPath !== directoryPath - ? this._loadConfigInAncestors(parentPath) + ? this._loadConfigInAncestors( + parentPath, + configsExistInSubdirs || configArray.length > 0 + ) : baseConfigArray; if (configArray.length > 0) { @@ -400,12 +416,29 @@ class CascadingConfigArrayFactory { configArray.every(c => !c.filePath) && cliConfigArray.every(c => !c.filePath) // `--config` option can be a file. ) { - debug("Loading the config file of the home directory."); + const homePath = os.homedir(); + + debug("Loading the config file of the home directory:", homePath); - finalConfigArray = configArrayFactory.loadInDirectory( - os.homedir(), - { name: "PersonalConfig", parent: finalConfigArray } + const personalConfigArray = configArrayFactory.loadInDirectory( + homePath, + { name: "PersonalConfig" } ); + + if ( + personalConfigArray.length > 0 && + !directoryPath.startsWith(homePath) + ) { + const lastElement = + personalConfigArray[personalConfigArray.length - 1]; + + emitDeprecationWarning( + lastElement.filePath, + "ESLINT_PERSONAL_CONFIG_LOAD" + ); + } + + finalConfigArray = finalConfigArray.concat(personalConfigArray); } // Apply CLI options. diff --git a/tools/node_modules/eslint/lib/cli-engine/cli-engine.js b/tools/node_modules/eslint/lib/cli-engine/cli-engine.js index 22336a91de2909..9d2ef8cbcdef04 100644 --- a/tools/node_modules/eslint/lib/cli-engine/cli-engine.js +++ b/tools/node_modules/eslint/lib/cli-engine/cli-engine.js @@ -57,7 +57,7 @@ const validFixTypes = new Set(["problem", "suggestion", "layout"]); * @property {string} configFile The configuration file to use. * @property {string} cwd The value to use for the current working directory. * @property {string[]} envs An array of environments to load. - * @property {string[]} extensions An array of file extensions to check. + * @property {string[]|null} extensions An array of file extensions to check. * @property {boolean|Function} fix Execute in autofix mode. If a function, should return a boolean. * @property {string[]} fixTypes Array of rule types to apply fixes for. * @property {string[]} globals An array of global variables to declare. @@ -201,7 +201,7 @@ function calculateStatsPerRun(results) { * @param {boolean} config.fix If `true` then it does fix. * @param {boolean} config.allowInlineConfig If `true` then it uses directive comments. * @param {boolean} config.reportUnusedDisableDirectives If `true` then it reports unused `eslint-disable` comments. - * @param {RegExp} config.extensionRegExp The `RegExp` object that tests if a file path has the allowed file extensions. + * @param {FileEnumerator} config.fileEnumerator The file enumerator to check if a path is a target or not. * @param {Linter} config.linter The linter instance to verify. * @returns {LintResult} The result of linting. * @private @@ -214,7 +214,7 @@ function verifyText({ fix, allowInlineConfig, reportUnusedDisableDirectives, - extensionRegExp, + fileEnumerator, linter }) { const filePath = providedFilePath || ""; @@ -238,13 +238,11 @@ function verifyText({ /** * Check if the linter should adopt a given code block or not. - * Currently, the linter adopts code blocks if the name matches `--ext` option. - * In the future, `overrides` in the configuration would affect the adoption (https://github.com/eslint/rfcs/pull/20). * @param {string} blockFilename The virtual filename of a code block. * @returns {boolean} `true` if the linter should adopt the code block. */ filterCodeBlock(blockFilename) { - return extensionRegExp.test(blockFilename); + return fileEnumerator.isTargetPath(blockFilename); } } ); @@ -280,14 +278,11 @@ function createIgnoreResult(filePath, baseDir) { let message; const isHidden = /^\./u.test(path.basename(filePath)); const isInNodeModules = baseDir && path.relative(baseDir, filePath).startsWith("node_modules"); - const isInBowerComponents = baseDir && path.relative(baseDir, filePath).startsWith("bower_components"); if (isHidden) { message = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern '!'\") to override."; } else if (isInNodeModules) { message = "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override."; - } else if (isInBowerComponents) { - message = "File ignored by default. Use \"--ignore-pattern '!bower_components/*'\" to override."; } else { message = "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override."; } @@ -704,7 +699,7 @@ class CLIEngine { return patterns.filter(Boolean); } - const extensions = options.extensions.map(ext => ext.replace(/^\./u, "")); + const extensions = (options.extensions || [".js"]).map(ext => ext.replace(/^\./u, "")); const dirSuffix = `/**/*.{${extensions.join(",")}}`; return patterns.filter(Boolean).map(pathname => { @@ -803,7 +798,7 @@ class CLIEngine { fix, allowInlineConfig, reportUnusedDisableDirectives, - extensionRegExp: fileEnumerator.extensionRegExp, + fileEnumerator, linter }); @@ -891,7 +886,7 @@ class CLIEngine { fix, allowInlineConfig, reportUnusedDisableDirectives, - extensionRegExp: fileEnumerator.extensionRegExp, + fileEnumerator, linter })); } diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js b/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js index 76c4ccd70212cd..997a7e15318dfd 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array-factory.js @@ -436,6 +436,29 @@ class ConfigArrayFactory { ); } + /** + * Check if a config file on a given directory exists or not. + * @param {string} directoryPath The path to a directory. + * @returns {string | null} The path to the found config file. If not found then null. + */ + static getPathToConfigFileInDirectory(directoryPath) { + for (const filename of configFilenames) { + const filePath = path.join(directoryPath, filename); + + if (fs.existsSync(filePath)) { + if (filename === "package.json") { + try { + loadPackageJSONConfigFile(filePath); + return filePath; + } catch (error) { /* ignore */ } + } else { + return filePath; + } + } + } + return null; + } + /** * Load `.eslintignore` file. * @param {string} filePath The path to a `.eslintignore` file to load. @@ -542,7 +565,7 @@ class ConfigArrayFactory { */ *_normalizeESLintIgnoreData(ignorePatterns, filePath, name) { const elements = this._normalizeObjectConfigData( - { ignorePatterns }, + { type: "ignore", ignorePatterns }, filePath, name ); @@ -644,6 +667,7 @@ class ConfigArrayFactory { root, rules, settings, + type = "config", overrides: overrideList = [] }, filePath, @@ -675,6 +699,7 @@ class ConfigArrayFactory { yield { // Debug information. + type, name, filePath, @@ -1024,6 +1049,7 @@ class ConfigArrayFactory { if (processorId.startsWith(".")) { yield* this._normalizeObjectConfigData( { + type: "implicit-processor", files: [`*${processorId}`], processor: `${pluginId}/${processorId}` }, diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js b/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js index 4fae8deaca1b69..b3f7c1e7350033 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array/config-array.js @@ -5,7 +5,7 @@ * config file, base config files that were extended, loaded parsers, and loaded * plugins. * - * `ConfigArray` class provies three properties and two methods. + * `ConfigArray` class provides three properties and two methods. * * - `pluginEnvironments` * - `pluginProcessors` @@ -454,6 +454,25 @@ class ConfigArray extends Array { return cache.get(cacheKey); } + + /** + * Check if a given path is an additional lint target. + * @param {string} filePath The absolute path to the target file. + * @returns {boolean} `true` if the file is an additional lint target. + */ + isAdditionalTargetPath(filePath) { + for (const { criteria, type } of this) { + if ( + type === "config" && + criteria && + !criteria.endsWithWildcard && + criteria.test(filePath) + ) { + return true; + } + } + return false; + } } const exportObject = { diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array/ignore-pattern.js b/tools/node_modules/eslint/lib/cli-engine/config-array/ignore-pattern.js index 6140194433e861..92690b9f8ae342 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array/ignore-pattern.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array/ignore-pattern.js @@ -103,8 +103,8 @@ function dirSuffix(filePath) { return isDir ? "/" : ""; } -const DefaultPatterns = Object.freeze(["/node_modules/*", "/bower_components/*"]); -const DotPatterns = Object.freeze([".*", "!../"]); +const DefaultPatterns = Object.freeze(["/**/node_modules/*"]); +const DotPatterns = Object.freeze([".*", "!.eslintrc.*", "!../"]); //------------------------------------------------------------------------------ // Public diff --git a/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js b/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js index 67c8a6ed8a0cbb..e7ba1202f1cb08 100644 --- a/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js +++ b/tools/node_modules/eslint/lib/cli-engine/config-array/override-tester.js @@ -96,14 +96,22 @@ class OverrideTester { static create(files, excludedFiles, basePath) { const includePatterns = normalizePatterns(files); const excludePatterns = normalizePatterns(excludedFiles); - const allPatterns = includePatterns.concat(excludePatterns); + let endsWithWildcard = false; - if (allPatterns.length === 0) { + if (includePatterns.length === 0) { return null; } // Rejects absolute paths or relative paths to parents. - for (const pattern of allPatterns) { + for (const pattern of includePatterns) { + if (path.isAbsolute(pattern) || pattern.includes("..")) { + throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`); + } + if (pattern.endsWith("*")) { + endsWithWildcard = true; + } + } + for (const pattern of excludePatterns) { if (path.isAbsolute(pattern) || pattern.includes("..")) { throw new Error(`Invalid override pattern (expected relative path not containing '..'): ${pattern}`); } @@ -112,7 +120,11 @@ class OverrideTester { const includes = toMatcher(includePatterns); const excludes = toMatcher(excludePatterns); - return new OverrideTester([{ includes, excludes }], basePath); + return new OverrideTester( + [{ includes, excludes }], + basePath, + endsWithWildcard + ); } /** @@ -125,28 +137,44 @@ class OverrideTester { */ static and(a, b) { if (!b) { - return a && new OverrideTester(a.patterns, a.basePath); + return a && new OverrideTester( + a.patterns, + a.basePath, + a.endsWithWildcard + ); } if (!a) { - return new OverrideTester(b.patterns, b.basePath); + return new OverrideTester( + b.patterns, + b.basePath, + b.endsWithWildcard + ); } assert.strictEqual(a.basePath, b.basePath); - return new OverrideTester(a.patterns.concat(b.patterns), a.basePath); + return new OverrideTester( + a.patterns.concat(b.patterns), + a.basePath, + a.endsWithWildcard || b.endsWithWildcard + ); } /** * Initialize this instance. * @param {Pattern[]} patterns The matchers. * @param {string} basePath The base path. + * @param {boolean} endsWithWildcard If `true` then a pattern ends with `*`. */ - constructor(patterns, basePath) { + constructor(patterns, basePath, endsWithWildcard = false) { /** @type {Pattern[]} */ this.patterns = patterns; /** @type {string} */ this.basePath = basePath; + + /** @type {boolean} */ + this.endsWithWildcard = endsWithWildcard; } /** diff --git a/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js b/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js index c67e01aef9b1c8..7c433d32f44b1c 100644 --- a/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js +++ b/tools/node_modules/eslint/lib/cli-engine/file-enumerator.js @@ -6,7 +6,7 @@ * 1. Find target files by processing glob patterns. * 2. Tie each target file and appropriate configuration. * - * It provies a method: + * It provides a method: * * - `iterateFiles(patterns)` * Iterate files which are matched by given patterns together with the @@ -88,7 +88,7 @@ const IGNORED = 2; * @typedef {Object} FileEnumeratorInternalSlots * @property {CascadingConfigArrayFactory} configArrayFactory The factory for config arrays. * @property {string} cwd The base directory to start lookup. - * @property {RegExp} extensionRegExp The RegExp to test if a string ends with specific file extensions. + * @property {RegExp|null} extensionRegExp The RegExp to test if a string ends with specific file extensions. * @property {boolean} globInputPaths Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file. * @property {boolean} ignoreFlag The flag to check ignored files. * @property {(filePath:string, dot:boolean) => boolean} defaultIgnores The default predicate function to ignore files. @@ -127,12 +127,12 @@ function statSafeSync(filePath) { /** * Get filenames in a given path to a directory. * @param {string} directoryPath The path to target directory. - * @returns {string[]} The filenames. + * @returns {import("fs").Dirent[]} The filenames. * @private */ function readdirSafeSync(directoryPath) { try { - return fs.readdirSync(directoryPath); + return fs.readdirSync(directoryPath, { withFileTypes: true }); } catch (error) { /* istanbul ignore next */ if (error.code !== "ENOENT") { @@ -142,6 +142,27 @@ function readdirSafeSync(directoryPath) { } } +/** + * Create a `RegExp` object to detect extensions. + * @param {string[] | null} extensions The extensions to create. + * @returns {RegExp | null} The created `RegExp` object or null. + */ +function createExtensionRegExp(extensions) { + if (extensions) { + const normalizedExts = extensions.map(ext => escapeRegExp( + ext.startsWith(".") + ? ext.slice(1) + : ext + )); + + return new RegExp( + `.\\.(?:${normalizedExts.join("|")})$`, + "u" + ); + } + return null; +} + /** * The error type when no files match a glob. */ @@ -188,7 +209,7 @@ class FileEnumerator { constructor({ cwd = process.cwd(), configArrayFactory = new CascadingConfigArrayFactory({ cwd }), - extensions = [".js"], + extensions = null, globInputPaths = true, errorOnUnmatchedPattern = true, ignore = true @@ -197,17 +218,7 @@ class FileEnumerator { configArrayFactory, cwd, defaultIgnores: IgnorePattern.createDefaultIgnore(cwd), - extensionRegExp: new RegExp( - `.\\.(?:${extensions - .map(ext => escapeRegExp( - ext.startsWith(".") - ? ext.slice(1) - : ext - )) - .join("|") - })$`, - "u" - ), + extensionRegExp: createExtensionRegExp(extensions), globInputPaths, errorOnUnmatchedPattern, ignoreFlag: ignore @@ -215,11 +226,36 @@ class FileEnumerator { } /** - * The `RegExp` object that tests if a file path has the allowed file extensions. - * @type {RegExp} + * Check if a given file is target or not. + * @param {string} filePath The path to a candidate file. + * @param {ConfigArray} [providedConfig] Optional. The configuration for the file. + * @returns {boolean} `true` if the file is a target. */ - get extensionRegExp() { - return internalSlotsMap.get(this).extensionRegExp; + isTargetPath(filePath, providedConfig) { + const { + configArrayFactory, + extensionRegExp + } = internalSlotsMap.get(this); + + // If `--ext` option is present, use it. + if (extensionRegExp) { + return extensionRegExp.test(filePath); + } + + // `.js` file is target by default. + if (filePath.endsWith(".js")) { + return true; + } + + // use `overrides[].files` to check additional targets. + const config = + providedConfig || + configArrayFactory.getConfigArrayForFile( + filePath, + { ignoreNotFoundError: true } + ); + + return config.isAdditionalTargetPath(filePath); } /** @@ -247,7 +283,7 @@ class FileEnumerator { continue; } - // Iterate files of this pttern. + // Iterate files of this pattern. for (const { config, filePath, flag } of this._iterateFiles(pattern)) { foundRegardlessOfIgnored = true; if (flag === IGNORED_SILENTLY) { @@ -380,18 +416,17 @@ class FileEnumerator { */ *_iterateFilesRecursive(directoryPath, options) { debug(`Enter the directory: ${directoryPath}`); - const { configArrayFactory, extensionRegExp } = internalSlotsMap.get(this); + const { configArrayFactory } = internalSlotsMap.get(this); /** @type {ConfigArray|null} */ let config = null; // Enumerate the files of this directory. - for (const filename of readdirSafeSync(directoryPath)) { - const filePath = path.join(directoryPath, filename); - const stat = statSafeSync(filePath); // TODO: Use `withFileTypes` in the future. + for (const entry of readdirSafeSync(directoryPath)) { + const filePath = path.join(directoryPath, entry.name); // Check if the file is matched. - if (stat && stat.isFile()) { + if (entry.isFile()) { if (!config) { config = configArrayFactory.getConfigArrayForFile( filePath, @@ -404,29 +439,30 @@ class FileEnumerator { { ignoreNotFoundError: true } ); } - const ignored = this._isIgnoredFile(filePath, { ...options, config }); - const flag = ignored ? IGNORED_SILENTLY : NONE; const matched = options.selector // Started with a glob pattern; choose by the pattern. ? options.selector.match(filePath) // Started with a directory path; choose by file extensions. - : extensionRegExp.test(filePath); + : this.isTargetPath(filePath, config); if (matched) { - debug(`Yield: ${filename}${ignored ? " but ignored" : ""}`); + const ignored = this._isIgnoredFile(filePath, { ...options, config }); + const flag = ignored ? IGNORED_SILENTLY : NONE; + + debug(`Yield: ${entry.name}${ignored ? " but ignored" : ""}`); yield { config: configArrayFactory.getConfigArrayForFile(filePath), filePath, flag }; } else { - debug(`Didn't match: ${filename}`); + debug(`Didn't match: ${entry.name}`); } // Dive into the sub directory. - } else if (options.recursive && stat && stat.isDirectory()) { + } else if (options.recursive && entry.isDirectory()) { if (!config) { config = configArrayFactory.getConfigArrayForFile( filePath, diff --git a/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js b/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js index c32425883f7cac..a994b4b1980eea 100644 --- a/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js +++ b/tools/node_modules/eslint/lib/cli-engine/formatters/junit.js @@ -32,7 +32,7 @@ function getMessageType(message) { * @private */ function pathWithoutExt(filePath) { - return path.posix.join(path.posix.dirname(filePath), path.basename(filePath, path.extname(filePath))); + return path.join(path.dirname(filePath), path.basename(filePath, path.extname(filePath))); } //------------------------------------------------------------------------------ diff --git a/tools/node_modules/eslint/lib/cli.js b/tools/node_modules/eslint/lib/cli.js index 944b4b79353b3d..815ce68c22fe2e 100644 --- a/tools/node_modules/eslint/lib/cli.js +++ b/tools/node_modules/eslint/lib/cli.js @@ -17,7 +17,6 @@ const fs = require("fs"), path = require("path"), - mkdirp = require("mkdirp"), { CLIEngine } = require("./cli-engine"), options = require("./options"), log = require("./shared/logging"), @@ -115,7 +114,7 @@ function printResults(engine, results, format, outputFile) { } try { - mkdirp.sync(path.dirname(filePath)); + fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, output); } catch (ex) { log.error("There was a problem writing the output file:\n%s", ex); diff --git a/tools/node_modules/eslint/lib/init/npm-utils.js b/tools/node_modules/eslint/lib/init/npm-utils.js index 28c198fc8ada67..555ea2b2b28cb2 100644 --- a/tools/node_modules/eslint/lib/init/npm-utils.js +++ b/tools/node_modules/eslint/lib/init/npm-utils.js @@ -135,7 +135,7 @@ function check(packages, opt) { * * Convenience wrapper around check(). * @param {string[]} packages Array of node modules to check. - * @param {string} rootDir The directory contianing a package.json + * @param {string} rootDir The directory containing a package.json * @returns {Object} An object whose keys are the module names * and values are booleans indicating installation. */ diff --git a/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js b/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js index 6822ae2be0a6cd..8a623e33ea0681 100644 --- a/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js +++ b/tools/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js @@ -518,6 +518,7 @@ function processCodePathToExit(analyzer, node) { case "ImportExpression": case "MemberExpression": case "NewExpression": + case "YieldExpression": state.makeFirstThrowablePathInTryBlock(); break; diff --git a/tools/node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js b/tools/node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js index 35a4cb2dacb1ca..bde4e0a38ad24b 100644 --- a/tools/node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js +++ b/tools/node_modules/eslint/lib/linter/code-path-analysis/debug-helpers.js @@ -70,7 +70,7 @@ module.exports = { /** * Dumps a DOT code of a given code path. - * The DOT code can be visialized with Graphvis. + * The DOT code can be visualized with Graphvis. * @param {CodePath} codePath A code path to dump. * @returns {void} * @see http://www.graphviz.org @@ -135,7 +135,7 @@ module.exports = { /** * Makes a DOT code of a given code path. - * The DOT code can be visialized with Graphvis. + * The DOT code can be visualized 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. * @returns {string} A DOT code of the code path. diff --git a/tools/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js b/tools/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js index eb1d2de5a7db5b..2e872b5c0dbf5a 100644 --- a/tools/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js +++ b/tools/node_modules/eslint/lib/linter/code-path-analysis/fork-context.js @@ -211,7 +211,7 @@ class ForkContext { } /** - * Clears all secments in this context. + * Clears all segments in this context. * @returns {void} */ clear() { diff --git a/tools/node_modules/eslint/lib/linter/linter.js b/tools/node_modules/eslint/lib/linter/linter.js index 6d88cb5aa1245f..1d021d1e82e7fb 100644 --- a/tools/node_modules/eslint/lib/linter/linter.js +++ b/tools/node_modules/eslint/lib/linter/linter.js @@ -267,6 +267,15 @@ function createDisableDirectives(options) { return result; } +/** + * Remove the ignored part from a given directive comment and trim it. + * @param {string} value The comment text to strip. + * @returns {string} The stripped text. + */ +function stripDirectiveComment(value) { + return value.split(/\s-{2,}\s/u)[0].trim(); +} + /** * Parses comments in file to extract file-specific config of rules, globals * and environments and merges them with global config; also code blocks @@ -286,7 +295,7 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) { const disableDirectives = []; ast.comments.filter(token => token.type !== "Shebang").forEach(comment => { - const trimmedCommentText = comment.value.trim(); + const trimmedCommentText = stripDirectiveComment(comment.value); const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(trimmedCommentText); if (!match) { @@ -444,8 +453,11 @@ function findEslintEnv(text) { eslintEnvPattern.lastIndex = 0; - while ((match = eslintEnvPattern.exec(text))) { - retv = Object.assign(retv || {}, commentParser.parseListConfig(match[1])); + while ((match = eslintEnvPattern.exec(text)) !== null) { + retv = Object.assign( + retv || {}, + commentParser.parseListConfig(stripDirectiveComment(match[1])) + ); } return retv; @@ -1260,7 +1272,7 @@ class Linter { * @param {string|SourceCode} textOrSourceCode The source code. * @param {ConfigData|ExtractedConfig} config The config array. * @param {VerifyOptions&ProcessorOptions} options The options. - * @param {ConfigArray} [configForRecursive] The `CofnigArray` object to apply multiple processors recursively. + * @param {ConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively. * @returns {LintMessage[]} The found problems. */ _verifyWithProcessor(textOrSourceCode, config, options, configForRecursive) { diff --git a/tools/node_modules/eslint/lib/rule-tester/rule-tester.js b/tools/node_modules/eslint/lib/rule-tester/rule-tester.js index 44e01dadf09b5d..5180f87a316f85 100644 --- a/tools/node_modules/eslint/lib/rule-tester/rule-tester.js +++ b/tools/node_modules/eslint/lib/rule-tester/rule-tester.js @@ -50,6 +50,52 @@ const const ajv = require("../shared/ajv")({ strictDefaults: true }); + +//------------------------------------------------------------------------------ +// Typedefs +//------------------------------------------------------------------------------ + +/** + * A test case that is expected to pass lint. + * @typedef {Object} ValidTestCase + * @property {string} code Code for the test case. + * @property {any[]} [options] Options for the test case. + * @property {{ [name: string]: any }} [settings] Settings for the test case. + * @property {string} [filename] The fake filename for the test case. Useful for rules that make assertion about filenames. + * @property {string} [parser] The absolute path for the parser. + * @property {{ [name: string]: any }} [parserOptions] Options for the parser. + * @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables. + * @property {{ [name: string]: boolean }} [env] Environments for the test case. + */ + +/** + * A test case that is expected to fail lint. + * @typedef {Object} InvalidTestCase + * @property {string} code Code for the test case. + * @property {number | Array} errors Expected errors. + * @property {string | null} [output] The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested. + * @property {any[]} [options] Options for the test case. + * @property {{ [name: string]: any }} [settings] Settings for the test case. + * @property {string} [filename] The fake filename for the test case. Useful for rules that make assertion about filenames. + * @property {string} [parser] The absolute path for the parser. + * @property {{ [name: string]: any }} [parserOptions] Options for the parser. + * @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables. + * @property {{ [name: string]: boolean }} [env] Environments for the test case. + */ + +/** + * A description of a reported error used in a rule tester test. + * @typedef {Object} TestCaseError + * @property {string | RegExp} [message] Message. + * @property {string} [messageId] Message ID. + * @property {string} [type] The type of the reported AST node. + * @property {{ [name: string]: string }} [data] The data used to fill the message template. + * @property {number} [line] The 1-based line number of the reported start location. + * @property {number} [column] The 1-based column number of the reported start location. + * @property {number} [endLine] The 1-based line number of the reported end location. + * @property {number} [endColumn] The 1-based column number of the reported end location. + */ + //------------------------------------------------------------------------------ // Private Members //------------------------------------------------------------------------------ @@ -73,6 +119,32 @@ const RuleTesterParameters = [ "output" ]; +/* + * All allowed property names in error objects. + */ +const errorObjectParameters = new Set([ + "message", + "messageId", + "data", + "type", + "line", + "column", + "endLine", + "endColumn", + "suggestions" +]); +const friendlyErrorObjectParameterList = `[${[...errorObjectParameters].map(key => `'${key}'`).join(", ")}]`; + +/* + * All allowed property names in suggestion objects. + */ +const suggestionObjectParameters = new Set([ + "desc", + "messageId", + "output" +]); +const friendlySuggestionObjectParameterList = `[${[...suggestionObjectParameters].map(key => `'${key}'`).join(", ")}]`; + const hasOwnProperty = Function.call.bind(Object.hasOwnProperty); /** @@ -128,7 +200,7 @@ function freezeDeeply(x) { */ function sanitize(text) { return text.replace( - /[\u0000-\u0009|\u000b-\u001a]/gu, // eslint-disable-line no-control-regex + /[\u0000-\u0009\u000b-\u001a]/gu, // eslint-disable-line no-control-regex c => `\\u${c.codePointAt(0).toString(16).padStart(4, "0")}` ); } @@ -273,7 +345,10 @@ class RuleTester { * Adds a new rule test to execute. * @param {string} ruleName The name of the rule to run. * @param {Function} rule The rule to test. - * @param {Object} test The collection of tests to run. + * @param {{ + * valid: (ValidTestCase | string)[], + * invalid: InvalidTestCase[] + * }} test The collection of tests to run. * @returns {void} */ run(ruleName, rule, test) { @@ -524,13 +599,21 @@ class RuleTester { // Just an error message. assertMessageMatches(message.message, error); - } else if (typeof error === "object") { + } else if (typeof error === "object" && error !== null) { /* * Error object. * This may have a message, messageId, data, node type, line, and/or * column. */ + + Object.keys(error).forEach(propertyName => { + assert.ok( + errorObjectParameters.has(propertyName), + `Invalid error property name '${propertyName}'. Expected one of ${friendlyErrorObjectParameterList}.` + ); + }); + if (hasOwnProperty(error, "message")) { assert.ok(!hasOwnProperty(error, "messageId"), "Error should not specify both 'message' and a 'messageId'."); assert.ok(!hasOwnProperty(error, "data"), "Error should not specify both 'data' and 'message'."); @@ -605,6 +688,17 @@ class RuleTester { assert.strictEqual(message.suggestions.length, error.suggestions.length, `Error should have ${error.suggestions.length} suggestions. Instead found ${message.suggestions.length} suggestions`); error.suggestions.forEach((expectedSuggestion, index) => { + assert.ok( + typeof expectedSuggestion === "object" && expectedSuggestion !== null, + "Test suggestion in 'suggestions' array must be an object." + ); + Object.keys(expectedSuggestion).forEach(propertyName => { + assert.ok( + suggestionObjectParameters.has(propertyName), + `Invalid suggestion property name '${propertyName}'. Expected one of ${friendlySuggestionObjectParameterList}.` + ); + }); + const actualSuggestion = message.suggestions[index]; /** diff --git a/tools/node_modules/eslint/lib/rules/accessor-pairs.js b/tools/node_modules/eslint/lib/rules/accessor-pairs.js index 3a32db6eac7214..02548258ca2e28 100644 --- a/tools/node_modules/eslint/lib/rules/accessor-pairs.js +++ b/tools/node_modules/eslint/lib/rules/accessor-pairs.js @@ -171,7 +171,7 @@ module.exports = { }, enforceForClassMembers: { type: "boolean", - default: false + default: true } }, additionalProperties: false @@ -190,7 +190,7 @@ module.exports = { const config = context.options[0] || {}; const checkGetWithoutSet = config.getWithoutSet === true; const checkSetWithoutGet = config.setWithoutGet !== false; - const enforceForClassMembers = config.enforceForClassMembers === true; + const enforceForClassMembers = config.enforceForClassMembers !== false; const sourceCode = context.getSourceCode(); /** diff --git a/tools/node_modules/eslint/lib/rules/array-callback-return.js b/tools/node_modules/eslint/lib/rules/array-callback-return.js index d632a3f30c28a3..eb38965024f05d 100644 --- a/tools/node_modules/eslint/lib/rules/array-callback-return.js +++ b/tools/node_modules/eslint/lib/rules/array-callback-return.js @@ -18,7 +18,7 @@ const astUtils = require("./utils/ast-utils"); //------------------------------------------------------------------------------ const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u; -const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/u; +const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort)$/u; /** * Checks a given code path segment is reachable. @@ -61,12 +61,13 @@ function isTargetMethod(node) { /** * Checks whether or not a given node is a function expression which is the - * callback of an array method. + * callback of an array method, returning the method name. * @param {ASTNode} node A node to check. This is one of * FunctionExpression or ArrowFunctionExpression. - * @returns {boolean} `true` if the node is the callback of an array method. + * @returns {string} The method name if the node is a callback method, + * null otherwise. */ -function isCallbackOfArrayMethod(node) { +function getArrayMethodName(node) { let currentNode = node; while (currentNode) { @@ -95,7 +96,7 @@ function isCallbackOfArrayMethod(node) { const func = astUtils.getUpperFunction(parent); if (func === null || !astUtils.isCallee(func)) { - return false; + return null; } currentNode = func.parent; break; @@ -108,27 +109,31 @@ function isCallbackOfArrayMethod(node) { */ case "CallExpression": if (astUtils.isArrayFromMethod(parent.callee)) { - return ( + if ( parent.arguments.length >= 2 && parent.arguments[1] === currentNode - ); + ) { + return "from"; + } } if (isTargetMethod(parent.callee)) { - return ( + if ( parent.arguments.length >= 1 && parent.arguments[0] === currentNode - ); + ) { + return astUtils.getStaticPropertyName(parent.callee); + } } - return false; + return null; // Otherwise this node is not target. default: - return false; + return null; } } /* istanbul ignore next: unreachable */ - return false; + return null; } //------------------------------------------------------------------------------ @@ -153,6 +158,10 @@ module.exports = { allowImplicit: { type: "boolean", default: false + }, + checkForEach: { + type: "boolean", + default: false } }, additionalProperties: false @@ -162,15 +171,17 @@ module.exports = { messages: { expectedAtEnd: "Expected to return a value at the end of {{name}}.", expectedInside: "Expected to return a value in {{name}}.", - expectedReturnValue: "{{name}} expected a return value." + expectedReturnValue: "{{name}} expected a return value.", + expectedNoReturnValue: "{{name}} did not expect a return value." } }, create(context) { - const options = context.options[0] || { allowImplicit: false }; + const options = context.options[0] || { allowImplicit: false, checkForEach: false }; let funcInfo = { + arrayMethodName: null, upper: null, codePath: null, hasReturn: false, @@ -188,18 +199,32 @@ module.exports = { * @returns {void} */ function checkLastSegment(node) { - if (funcInfo.shouldCheck && - funcInfo.codePath.currentSegments.some(isReachable) - ) { + + if (!funcInfo.shouldCheck) { + return; + } + + let messageId = null; + + if (funcInfo.arrayMethodName === "forEach") { + if (options.checkForEach && node.type === "ArrowFunctionExpression" && node.expression) { + messageId = "expectedNoReturnValue"; + } + } else { + if (node.body.type === "BlockStatement" && funcInfo.codePath.currentSegments.some(isReachable)) { + messageId = funcInfo.hasReturn ? "expectedAtEnd" : "expectedInside"; + } + } + + if (messageId) { + let name = astUtils.getFunctionNameWithKind(funcInfo.node); + + name = messageId === "expectedNoReturnValue" ? lodash.upperFirst(name) : name; context.report({ node, loc: getLocation(node, context.getSourceCode()).loc.start, - messageId: funcInfo.hasReturn - ? "expectedAtEnd" - : "expectedInside", - data: { - name: astUtils.getFunctionNameWithKind(funcInfo.node) - } + messageId, + data: { name } }); } } @@ -208,14 +233,20 @@ module.exports = { // Stacks this function's information. onCodePathStart(codePath, node) { + + let methodName = null; + + if (TARGET_NODE_TYPE.test(node.type)) { + methodName = getArrayMethodName(node); + } + funcInfo = { + arrayMethodName: methodName, upper: funcInfo, codePath, hasReturn: false, shouldCheck: - TARGET_NODE_TYPE.test(node.type) && - node.body.type === "BlockStatement" && - isCallbackOfArrayMethod(node) && + methodName && !node.async && !node.generator, node @@ -229,20 +260,38 @@ module.exports = { // Checks the return statement is valid. ReturnStatement(node) { - if (funcInfo.shouldCheck) { - funcInfo.hasReturn = true; + + if (!funcInfo.shouldCheck) { + return; + } + + funcInfo.hasReturn = true; + + let messageId = null; + + if (funcInfo.arrayMethodName === "forEach") { + + // if checkForEach: true, returning a value at any path inside a forEach is not allowed + if (options.checkForEach && node.argument) { + messageId = "expectedNoReturnValue"; + } + } else { // if allowImplicit: false, should also check node.argument if (!options.allowImplicit && !node.argument) { - context.report({ - node, - messageId: "expectedReturnValue", - data: { - name: lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node)) - } - }); + messageId = "expectedReturnValue"; } } + + if (messageId) { + context.report({ + node, + messageId, + data: { + name: lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node)) + } + }); + } }, // Reports a given function if the last path is reachable. diff --git a/tools/node_modules/eslint/lib/rules/array-element-newline.js b/tools/node_modules/eslint/lib/rules/array-element-newline.js index 1da67667bee849..b7a967865b92a1 100644 --- a/tools/node_modules/eslint/lib/rules/array-element-newline.js +++ b/tools/node_modules/eslint/lib/rules/array-element-newline.js @@ -24,28 +24,52 @@ module.exports = { fixable: "whitespace", - schema: [ - { - oneOf: [ - { - enum: ["always", "never", "consistent"] - }, - { - type: "object", - properties: { - multiline: { - type: "boolean" + schema: { + definitions: { + basicConfig: { + oneOf: [ + { + enum: ["always", "never", "consistent"] + }, + { + type: "object", + properties: { + multiline: { + type: "boolean" + }, + minItems: { + type: ["integer", "null"], + minimum: 0 + } }, - minItems: { - type: ["integer", "null"], - minimum: 0 - } + additionalProperties: false + } + ] + } + }, + items: [ + { + oneOf: [ + { + $ref: "#/definitions/basicConfig" }, - additionalProperties: false - } - ] - } - ], + { + type: "object", + properties: { + ArrayExpression: { + $ref: "#/definitions/basicConfig" + }, + ArrayPattern: { + $ref: "#/definitions/basicConfig" + } + }, + additionalProperties: false, + minProperties: 1 + } + ] + } + ] + }, messages: { unexpectedLineBreak: "There should be no linebreak here.", @@ -93,6 +117,20 @@ module.exports = { * @returns {{ArrayExpression: {multiline: boolean, minItems: number}, ArrayPattern: {multiline: boolean, minItems: number}}} Normalized option object. */ function normalizeOptions(options) { + if (options && (options.ArrayExpression || options.ArrayPattern)) { + let expressionOptions, patternOptions; + + if (options.ArrayExpression) { + expressionOptions = normalizeOptionValue(options.ArrayExpression); + } + + if (options.ArrayPattern) { + patternOptions = normalizeOptionValue(options.ArrayPattern); + } + + return { ArrayExpression: expressionOptions, ArrayPattern: patternOptions }; + } + const value = normalizeOptionValue(options); return { ArrayExpression: value, ArrayPattern: value }; @@ -177,6 +215,10 @@ module.exports = { const normalizedOptions = normalizeOptions(context.options[0]); const options = normalizedOptions[node.type]; + if (!options) { + return; + } + let elementBreak = false; /* diff --git a/tools/node_modules/eslint/lib/rules/arrow-body-style.js b/tools/node_modules/eslint/lib/rules/arrow-body-style.js index 8d3b400037a6d5..9d5c77d8573d6a 100644 --- a/tools/node_modules/eslint/lib/rules/arrow-body-style.js +++ b/tools/node_modules/eslint/lib/rules/arrow-body-style.js @@ -91,7 +91,7 @@ module.exports = { * @returns {Token} The found closing parenthesis token. */ function findClosingParen(token) { - let node = sourceCode.getNodeByRangeIndex(token.range[1]); + let node = sourceCode.getNodeByRangeIndex(token.range[0]); while (!astUtils.isParenthesised(sourceCode, node)) { node = node.parent; @@ -206,24 +206,35 @@ module.exports = { fix(fixer) { const fixes = []; const arrowToken = sourceCode.getTokenBefore(arrowBody, astUtils.isArrowToken); - const firstBodyToken = sourceCode.getTokenAfter(arrowToken); - const lastBodyToken = sourceCode.getLastToken(node); + const [firstTokenAfterArrow, secondTokenAfterArrow] = sourceCode.getTokensAfter(arrowToken, { count: 2 }); + const lastToken = sourceCode.getLastToken(node); const isParenthesisedObjectLiteral = - astUtils.isOpeningParenToken(firstBodyToken) && - astUtils.isOpeningBraceToken(sourceCode.getTokenAfter(firstBodyToken)); - - // Wrap the value by a block and a return statement. - fixes.push( - fixer.insertTextBefore(firstBodyToken, "{return "), - fixer.insertTextAfter(lastBodyToken, "}") - ); + astUtils.isOpeningParenToken(firstTokenAfterArrow) && + astUtils.isOpeningBraceToken(secondTokenAfterArrow); // If the value is object literal, remove parentheses which were forced by syntax. if (isParenthesisedObjectLiteral) { - fixes.push( - fixer.remove(firstBodyToken), - fixer.remove(findClosingParen(firstBodyToken)) - ); + const openingParenToken = firstTokenAfterArrow; + const openingBraceToken = secondTokenAfterArrow; + + if (astUtils.isTokenOnSameLine(openingParenToken, openingBraceToken)) { + fixes.push(fixer.replaceText(openingParenToken, "{return ")); + } else { + + // Avoid ASI + fixes.push( + fixer.replaceText(openingParenToken, "{"), + fixer.insertTextBefore(openingBraceToken, "return ") + ); + } + + // Closing paren for the object doesn't have to be lastToken, e.g.: () => ({}).foo() + fixes.push(fixer.remove(findClosingParen(openingBraceToken))); + fixes.push(fixer.insertTextAfter(lastToken, "}")); + + } else { + fixes.push(fixer.insertTextBefore(firstTokenAfterArrow, "{return ")); + fixes.push(fixer.insertTextAfter(lastToken, "}")); } return fixes; diff --git a/tools/node_modules/eslint/lib/rules/complexity.js b/tools/node_modules/eslint/lib/rules/complexity.js index 91180e989540ce..7fc8bf9bc2ea8c 100644 --- a/tools/node_modules/eslint/lib/rules/complexity.js +++ b/tools/node_modules/eslint/lib/rules/complexity.js @@ -1,6 +1,6 @@ /** * @fileoverview Counts the cyclomatic complexity of each function of the script. See http://en.wikipedia.org/wiki/Cyclomatic_complexity. - * Counts the number of if, conditional, for, whilte, try, switch/case, + * Counts the number of if, conditional, for, while, try, switch/case, * @author Patrick Brosset */ diff --git a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js index a0bd7f48ced66b..53fdb8f4e41f95 100644 --- a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js +++ b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js @@ -32,7 +32,7 @@ module.exports = { properties: { enforceForClassMembers: { type: "boolean", - default: false + default: true } }, additionalProperties: false @@ -51,7 +51,7 @@ module.exports = { create(context) { const sourceCode = context.getSourceCode(); const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" - const enforceForClassMembers = context.options[1] && context.options[1].enforceForClassMembers; + const enforceForClassMembers = !context.options[1] || context.options[1].enforceForClassMembers; //-------------------------------------------------------------------------- // Helpers @@ -67,7 +67,7 @@ module.exports = { function reportNoBeginningSpace(node, token, tokenAfter) { context.report({ node, - loc: token.loc.start, + loc: { start: token.loc.end, end: tokenAfter.loc.start }, messageId: "unexpectedSpaceAfter", data: { tokenValue: token.value @@ -88,7 +88,7 @@ module.exports = { function reportNoEndingSpace(node, token, tokenBefore) { context.report({ node, - loc: token.loc.start, + loc: { start: tokenBefore.loc.end, end: token.loc.start }, messageId: "unexpectedSpaceBefore", data: { tokenValue: token.value @@ -108,7 +108,7 @@ module.exports = { function reportRequiredBeginningSpace(node, token) { context.report({ node, - loc: token.loc.start, + loc: token.loc, messageId: "missingSpaceAfter", data: { tokenValue: token.value @@ -128,7 +128,7 @@ module.exports = { function reportRequiredEndingSpace(node, token) { context.report({ node, - loc: token.loc.start, + loc: token.loc, messageId: "missingSpaceBefore", data: { tokenValue: token.value diff --git a/tools/node_modules/eslint/lib/rules/consistent-this.js b/tools/node_modules/eslint/lib/rules/consistent-this.js index 16f53b5374cd24..e5bc9678daef3c 100644 --- a/tools/node_modules/eslint/lib/rules/consistent-this.js +++ b/tools/node_modules/eslint/lib/rules/consistent-this.js @@ -114,7 +114,7 @@ module.exports = { } /** - * Check each alias to ensure that is was assinged to the correct value. + * Check each alias to ensure that is was assigned to the correct value. * @returns {void} */ function ensureWasAssigned() { diff --git a/tools/node_modules/eslint/lib/rules/curly.js b/tools/node_modules/eslint/lib/rules/curly.js index ee2fe4dceb82bf..29f00c0ad0b617 100644 --- a/tools/node_modules/eslint/lib/rules/curly.js +++ b/tools/node_modules/eslint/lib/rules/curly.js @@ -141,33 +141,14 @@ module.exports = { } /** - * Checks a given IfStatement node requires braces of the consequent chunk. - * This returns `true` when below: - * - * 1. The given node has the `alternate` node. - * 2. There is a `IfStatement` which doesn't have `alternate` node in the - * trailing statement chain of the `consequent` node. - * @param {ASTNode} node A IfStatement node to check. - * @returns {boolean} `true` if the node requires braces of the consequent chunk. + * Determines whether the given node has an `else` keyword token as the first token after. + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if the node is followed by an `else` keyword token. */ - function requiresBraceOfConsequent(node) { - if (node.alternate && node.consequent.type === "BlockStatement") { - if (node.consequent.body.length >= 2) { - return true; - } - - for ( - let currentNode = node.consequent.body[0]; - currentNode; - currentNode = astUtils.getTrailingStatement(currentNode) - ) { - if (currentNode.type === "IfStatement" && !currentNode.alternate) { - return true; - } - } - } + function isFollowedByElseKeyword(node) { + const nextToken = sourceCode.getTokenAfter(node); - return false; + return Boolean(nextToken) && isElseKeywordToken(nextToken); } /** @@ -224,6 +205,110 @@ module.exports = { return false; } + /** + * Determines whether the code represented by the given node contains an `if` statement + * that would become associated with an `else` keyword directly appended to that code. + * + * Examples where it returns `true`: + * + * if (a) + * foo(); + * + * if (a) { + * foo(); + * } + * + * if (a) + * foo(); + * else if (b) + * bar(); + * + * while (a) + * if (b) + * if(c) + * foo(); + * else + * bar(); + * + * Examples where it returns `false`: + * + * if (a) + * foo(); + * else + * bar(); + * + * while (a) { + * if (b) + * if(c) + * foo(); + * else + * bar(); + * } + * + * while (a) + * if (b) { + * if(c) + * foo(); + * } + * else + * bar(); + * @param {ASTNode} node Node representing the code to check. + * @returns {boolean} `true` if an `if` statement within the code would become associated with an `else` appended to that code. + */ + function hasUnsafeIf(node) { + switch (node.type) { + case "IfStatement": + if (!node.alternate) { + return true; + } + return hasUnsafeIf(node.alternate); + case "ForStatement": + case "ForInStatement": + case "ForOfStatement": + case "LabeledStatement": + case "WithStatement": + case "WhileStatement": + return hasUnsafeIf(node.body); + default: + return false; + } + } + + /** + * Determines whether the existing curly braces around the single statement are necessary to preserve the semantics of the code. + * The braces, which make the given block body, are necessary in either of the following situations: + * + * 1. The statement is a lexical declaration. + * 2. Without the braces, an `if` within the statement would become associated with an `else` after the closing brace: + * + * if (a) { + * if (b) + * foo(); + * } + * else + * bar(); + * + * if (a) + * while (b) + * while (c) { + * while (d) + * if (e) + * while(f) + * foo(); + * } + * else + * bar(); + * @param {ASTNode} node `BlockStatement` body with exactly one statement directly inside. The statement can have its own nested statements. + * @returns {boolean} `true` if the braces are necessary - removing them (replacing the given `BlockStatement` body with its single statement content) + * would change the semantics of the code or produce a syntax error. + */ + function areBracesNecessary(node) { + const statement = node.body[0]; + + return isLexicalDeclaration(statement) || + hasUnsafeIf(statement) && isFollowedByElseKeyword(node); + } + /** * Prepares to check the body of a node to see if it's a block statement. * @param {ASTNode} node The node to report if there's a problem. @@ -242,30 +327,29 @@ module.exports = { const hasBlock = (body.type === "BlockStatement"); let expected = null; - if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) { + if (hasBlock && (body.body.length !== 1 || areBracesNecessary(body))) { expected = true; } else if (multiOnly) { - if (hasBlock && body.body.length === 1 && !isLexicalDeclaration(body.body[0])) { - expected = false; - } + expected = false; } else if (multiLine) { if (!isCollapsedOneLiner(body)) { expected = true; } + + // otherwise, the body is allowed to have braces or not to have braces + } else if (multiOrNest) { - if (hasBlock && body.body.length === 1 && isOneLiner(body.body[0])) { - const leadingComments = sourceCode.getCommentsBefore(body.body[0]); - const isLexDef = isLexicalDeclaration(body.body[0]); - - if (isLexDef) { - expected = true; - } else { - expected = leadingComments.length > 0; - } - } else if (!isOneLiner(body)) { - expected = true; + if (hasBlock) { + const statement = body.body[0]; + const leadingCommentsInBlock = sourceCode.getCommentsBefore(statement); + + expected = !isOneLiner(statement) || leadingCommentsInBlock.length > 0; + } else { + expected = !isOneLiner(body); } } else { + + // default "all" expected = true; } diff --git a/tools/node_modules/eslint/lib/rules/default-case-last.js b/tools/node_modules/eslint/lib/rules/default-case-last.js new file mode 100644 index 00000000000000..80c5d6bda73958 --- /dev/null +++ b/tools/node_modules/eslint/lib/rules/default-case-last.js @@ -0,0 +1,44 @@ +/** + * @fileoverview Rule to enforce default clauses in switch statements to be last + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "suggestion", + + docs: { + description: "enforce default clauses in switch statements to be last", + category: "Best Practices", + recommended: false, + url: "https://eslint.org/docs/rules/default-case-last" + }, + + schema: [], + + messages: { + notLast: "Default clause should be the last clause." + } + }, + + create(context) { + return { + SwitchStatement(node) { + const cases = node.cases, + indexOfDefault = cases.findIndex(c => c.test === null); + + if (indexOfDefault !== -1 && indexOfDefault !== cases.length - 1) { + const defaultClause = cases[indexOfDefault]; + + context.report({ node: defaultClause, messageId: "notLast" }); + } + } + }; + } +}; diff --git a/tools/node_modules/eslint/lib/rules/func-names.js b/tools/node_modules/eslint/lib/rules/func-names.js index 1341d03630823f..ecfedb9e0e99c7 100644 --- a/tools/node_modules/eslint/lib/rules/func-names.js +++ b/tools/node_modules/eslint/lib/rules/func-names.js @@ -119,8 +119,7 @@ module.exports = { (parent.type === "VariableDeclarator" && parent.id.type === "Identifier" && parent.init === node) || (parent.type === "Property" && parent.value === node) || (parent.type === "AssignmentExpression" && parent.left.type === "Identifier" && parent.right === node) || - (parent.type === "ExportDefaultDeclaration" && parent.declaration === node) || - (parent.type === "AssignmentPattern" && parent.right === node); + (parent.type === "AssignmentPattern" && parent.left.type === "Identifier" && parent.right === node); } /** @@ -151,33 +150,41 @@ module.exports = { }); } - return { - "FunctionExpression:exit"(node) { + /** + * The listener for function nodes. + * @param {ASTNode} node function node + * @returns {void} + */ + function handleFunction(node) { - // Skip recursive functions. - const nameVar = context.getDeclaredVariables(node)[0]; + // Skip recursive functions. + const nameVar = context.getDeclaredVariables(node)[0]; - if (isFunctionName(nameVar) && nameVar.references.length > 0) { - return; - } + if (isFunctionName(nameVar) && nameVar.references.length > 0) { + return; + } - const hasName = Boolean(node.id && node.id.name); - const config = getConfigForNode(node); - - if (config === "never") { - if (hasName) { - reportUnexpectedNamedFunction(node); - } - } else if (config === "as-needed") { - if (!hasName && !hasInferredName(node)) { - reportUnexpectedUnnamedFunction(node); - } - } else { - if (!hasName && !isObjectOrClassMethod(node)) { - reportUnexpectedUnnamedFunction(node); - } + const hasName = Boolean(node.id && node.id.name); + const config = getConfigForNode(node); + + if (config === "never") { + if (hasName && node.type !== "FunctionDeclaration") { + reportUnexpectedNamedFunction(node); + } + } else if (config === "as-needed") { + if (!hasName && !hasInferredName(node)) { + reportUnexpectedUnnamedFunction(node); + } + } else { + if (!hasName && !isObjectOrClassMethod(node)) { + reportUnexpectedUnnamedFunction(node); } } + } + + return { + "FunctionExpression:exit": handleFunction, + "ExportDefaultDeclaration > FunctionDeclaration": handleFunction }; } }; diff --git a/tools/node_modules/eslint/lib/rules/id-blacklist.js b/tools/node_modules/eslint/lib/rules/id-blacklist.js index 53be62e68a3626..ddff9363aee8a8 100644 --- a/tools/node_modules/eslint/lib/rules/id-blacklist.js +++ b/tools/node_modules/eslint/lib/rules/id-blacklist.js @@ -41,6 +41,7 @@ module.exports = { //-------------------------------------------------------------------------- const blacklist = context.options; + const reportedNodes = new Set(); /** @@ -54,16 +55,69 @@ 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 + * Checks whether the given node represents an imported name that is renamed in the same import/export specifier. + * + * Examples: + * import { a as b } from 'mod'; // node `a` is renamed import + * export { a as b } from 'mod'; // node `a` is renamed import + * @param {ASTNode} node `Identifier` node to check. + * @returns {boolean} `true` if the node is a renamed import. + */ + function isRenamedImport(node) { + const parent = node.parent; + + return ( + ( + parent.type === "ImportSpecifier" && + parent.imported !== parent.local && + parent.imported === node + ) || + ( + parent.type === "ExportSpecifier" && + parent.parent.source && // re-export + parent.local !== parent.exported && + parent.local === node + ) + ); + } + + /** + * Checks whether the given node is a renamed identifier node in an ObjectPattern destructuring. + * + * Examples: + * const { a : b } = foo; // node `a` is renamed node. + * @param {ASTNode} node `Identifier` node to check. + * @returns {boolean} `true` if the node is a renamed node in an ObjectPattern destructuring. + */ + function isRenamedInDestructuring(node) { + const parent = node.parent; + + return ( + ( + !parent.computed && + parent.type === "Property" && + parent.parent.type === "ObjectPattern" && + parent.value !== node && + parent.key === node + ) + ); + } + + /** + * Verifies if we should report an error or not. + * @param {ASTNode} node The node to check * @returns {boolean} whether an error should be reported or not */ - function shouldReport(effectiveParent, name) { - return effectiveParent.type !== "CallExpression" && - effectiveParent.type !== "NewExpression" && - isInvalid(name); + function shouldReport(node) { + const parent = node.parent; + + return ( + parent.type !== "CallExpression" && + parent.type !== "NewExpression" && + !isRenamedImport(node) && + !isRenamedInDestructuring(node) && + isInvalid(node.name) + ); } /** @@ -73,50 +127,63 @@ module.exports = { * @private */ function report(node) { - context.report({ - node, - messageId: "blacklisted", - data: { - name: node.name - } - }); + if (!reportedNodes.has(node)) { + context.report({ + node, + messageId: "blacklisted", + data: { + name: node.name + } + }); + reportedNodes.add(node); + } } return { Identifier(node) { - const name = node.name, - effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; // MemberExpressions get special rules if (node.parent.type === "MemberExpression") { + const name = node.name, + effectiveParent = node.parent.parent; // Always check object names if (node.parent.object.type === "Identifier" && - node.parent.object.name === node.name) { + node.parent.object.name === name) { if (isInvalid(name)) { report(node); } - // Report AssignmentExpressions only if they are the left side of the assignment + // Report AssignmentExpressions only if they are the left side of the assignment } else if (effectiveParent.type === "AssignmentExpression" && (effectiveParent.right.type !== "MemberExpression" || - effectiveParent.left.type === "MemberExpression" && - effectiveParent.left.property.name === node.name)) { + effectiveParent.left.type === "MemberExpression" && + effectiveParent.left.property.name === name)) { if (isInvalid(name)) { report(node); } - } - // Properties have their own rules - } else if (node.parent.type === "Property") { - - if (shouldReport(effectiveParent, name)) { - report(node); + // Report the last identifier in an ObjectPattern destructuring. + } else if ( + ( + effectiveParent.type === "Property" && + effectiveParent.value === node.parent && + effectiveParent.parent.type === "ObjectPattern" + ) || + effectiveParent.type === "RestElement" || + effectiveParent.type === "ArrayPattern" || + ( + effectiveParent.type === "AssignmentPattern" && + effectiveParent.left === node.parent + ) + ) { + if (isInvalid(name)) { + report(node); + } } - // Report anything that is a match and not a CallExpression - } else if (shouldReport(effectiveParent, name)) { + } else if (shouldReport(node)) { report(node); } } diff --git a/tools/node_modules/eslint/lib/rules/id-length.js b/tools/node_modules/eslint/lib/rules/id-length.js index c8586ea3481895..a68873ac06289b 100644 --- a/tools/node_modules/eslint/lib/rules/id-length.js +++ b/tools/node_modules/eslint/lib/rules/id-length.js @@ -63,6 +63,7 @@ module.exports = { return obj; }, {}); + const reportedNode = new Set(); const SUPPORTED_EXPRESSIONS = { MemberExpression: properties && function(parent) { @@ -82,8 +83,15 @@ module.exports = { VariableDeclarator(parent, node) { return parent.id === node; }, - Property: properties && function(parent, node) { - return parent.key === node; + Property(parent, node) { + + if (parent.parent.type === "ObjectPattern") { + return ( + parent.value !== parent.key && parent.value === node || + parent.value === parent.key && parent.key === node && properties + ); + } + return properties && !parent.computed && parent.key === node; }, ImportDefaultSpecifier: true, RestElement: true, @@ -92,7 +100,8 @@ module.exports = { ClassDeclaration: true, FunctionDeclaration: true, MethodDefinition: true, - CatchClause: true + CatchClause: true, + ArrayPattern: true }; return { @@ -109,7 +118,8 @@ module.exports = { const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; - if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) { + if (isValidExpression && !reportedNode.has(node) && (isValidExpression === true || isValidExpression(parent, node))) { + reportedNode.add(node); context.report({ node, messageId: isShort ? "tooShort" : "tooLong", diff --git a/tools/node_modules/eslint/lib/rules/indent-legacy.js b/tools/node_modules/eslint/lib/rules/indent-legacy.js index f1c024c368475d..50010d3f7acb16 100644 --- a/tools/node_modules/eslint/lib/rules/indent-legacy.js +++ b/tools/node_modules/eslint/lib/rules/indent-legacy.js @@ -696,20 +696,6 @@ module.exports = { return startLine === endLine; } - /** - * Check to see if the first element inside an array is an object and on the same line as the node - * If the node is not an array then it will return false. - * @param {ASTNode} node node to check - * @returns {boolean} success/failure - */ - function isFirstArrayElementOnSameLine(node) { - if (node.type === "ArrayExpression" && node.elements[0]) { - return node.elements[0].loc.start.line === node.loc.start.line && node.elements[0].type === "ObjectExpression"; - } - return false; - - } - /** * Check indent for array block content or object block content * @param {ASTNode} node node to examine @@ -776,8 +762,6 @@ module.exports = { nodeIndent += indentSize; } } - } else if (!parentVarNode && !isFirstArrayElementOnSameLine(parent) && parent.type !== "MemberExpression" && parent.type !== "ExpressionStatement" && parent.type !== "AssignmentExpression" && parent.type !== "Property") { - nodeIndent += indentSize; } checkFirstNodeLineIndent(node, nodeIndent); diff --git a/tools/node_modules/eslint/lib/rules/indent.js b/tools/node_modules/eslint/lib/rules/indent.js index 694cf7d9e6ed4f..d576fde0382461 100644 --- a/tools/node_modules/eslint/lib/rules/indent.js +++ b/tools/node_modules/eslint/lib/rules/indent.js @@ -540,8 +540,15 @@ module.exports = { ] }, outerIIFEBody: { - type: "integer", - minimum: 0 + oneOf: [ + { + type: "integer", + minimum: 0 + }, + { + enum: ["off"] + } + ] }, MemberExpression: { oneOf: [ @@ -590,6 +597,10 @@ module.exports = { type: "boolean", default: false }, + offsetTernaryExpressions: { + type: "boolean", + default: false + }, ignoredNodes: { type: "array", items: { @@ -922,7 +933,11 @@ module.exports = { parameterParens.add(openingParen); parameterParens.add(closingParen); - offsets.setDesiredOffset(openingParen, sourceCode.getTokenBefore(openingParen), 0); + + const offsetAfterToken = node.callee.type === "TaggedTemplateExpression" ? sourceCode.getFirstToken(node.callee.quasi) : openingParen; + const offsetToken = sourceCode.getTokenBefore(offsetAfterToken); + + offsets.setDesiredOffset(openingParen, offsetToken, 0); addElementListIndent(node.arguments, openingParen, closingParen, options.CallExpression.arguments); } @@ -1088,7 +1103,6 @@ module.exports = { }, "BlockStatement, ClassBody"(node) { - let blockIndentLevel; if (node.parent && isOuterIIFE(node.parent)) { @@ -1108,6 +1122,7 @@ module.exports = { if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) { offsets.setDesiredOffset(sourceCode.getFirstToken(node), sourceCode.getFirstToken(node.parent), 0); } + addElementListIndent(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), blockIndentLevel); }, @@ -1142,7 +1157,8 @@ module.exports = { offsets.setDesiredOffset(questionMarkToken, firstToken, 1); offsets.setDesiredOffset(colonToken, firstToken, 1); - offsets.setDesiredOffset(firstConsequentToken, firstToken, 1); + offsets.setDesiredOffset(firstConsequentToken, firstToken, + options.offsetTernaryExpressions ? 2 : 1); /* * The alternate and the consequent should usually have the same indentation. @@ -1167,7 +1183,9 @@ module.exports = { * If `baz` were aligned with `bar` rather than being offset by 1 from `foo`, `baz` would end up * having no expected indentation. */ - offsets.setDesiredOffset(firstAlternateToken, firstToken, 1); + offsets.setDesiredOffset(firstAlternateToken, firstToken, + firstAlternateToken.type === "Punctuator" && + options.offsetTernaryExpressions ? 2 : 1); } } }, diff --git a/tools/node_modules/eslint/lib/rules/index.js b/tools/node_modules/eslint/lib/rules/index.js index d3fbe412080360..7f563eb2ebfb96 100644 --- a/tools/node_modules/eslint/lib/rules/index.js +++ b/tools/node_modules/eslint/lib/rules/index.js @@ -37,6 +37,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "constructor-super": () => require("./constructor-super"), curly: () => require("./curly"), "default-case": () => require("./default-case"), + "default-case-last": () => require("./default-case-last"), "default-param-last": () => require("./default-param-last"), "dot-location": () => require("./dot-location"), "dot-notation": () => require("./dot-notation"), @@ -178,6 +179,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "no-prototype-builtins": () => require("./no-prototype-builtins"), "no-redeclare": () => require("./no-redeclare"), "no-regex-spaces": () => require("./no-regex-spaces"), + "no-restricted-exports": () => require("./no-restricted-exports"), "no-restricted-globals": () => require("./no-restricted-globals"), "no-restricted-imports": () => require("./no-restricted-imports"), "no-restricted-modules": () => require("./no-restricted-modules"), @@ -215,6 +217,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({ "no-unused-labels": () => require("./no-unused-labels"), "no-unused-vars": () => require("./no-unused-vars"), "no-use-before-define": () => require("./no-use-before-define"), + "no-useless-backreference": () => require("./no-useless-backreference"), "no-useless-call": () => require("./no-useless-call"), "no-useless-catch": () => require("./no-useless-catch"), "no-useless-computed-key": () => require("./no-useless-computed-key"), diff --git a/tools/node_modules/eslint/lib/rules/key-spacing.js b/tools/node_modules/eslint/lib/rules/key-spacing.js index 6d1b9121c78c5f..c405043794c7d1 100644 --- a/tools/node_modules/eslint/lib/rules/key-spacing.js +++ b/tools/node_modules/eslint/lib/rules/key-spacing.js @@ -414,8 +414,7 @@ module.exports = { if (property.computed) { return sourceCode.getText().slice(key.range[0], key.range[1]); } - - return property.key.name || property.key.value; + return astUtils.getStaticPropertyName(property); } /** diff --git a/tools/node_modules/eslint/lib/rules/linebreak-style.js b/tools/node_modules/eslint/lib/rules/linebreak-style.js index 97d552ea07c966..078eaf2cd268d2 100644 --- a/tools/node_modules/eslint/lib/rules/linebreak-style.js +++ b/tools/node_modules/eslint/lib/rules/linebreak-style.js @@ -64,7 +64,7 @@ module.exports = { //-------------------------------------------------------------------------- return { - Program: function checkForlinebreakStyle(node) { + Program: function checkForLinebreakStyle(node) { const linebreakStyle = context.options[0] || "unix", expectedLF = linebreakStyle === "unix", expectedLFChars = expectedLF ? "\n" : "\r\n", diff --git a/tools/node_modules/eslint/lib/rules/max-len.js b/tools/node_modules/eslint/lib/rules/max-len.js index b29099ed4c4f09..995e0c52026385 100644 --- a/tools/node_modules/eslint/lib/rules/max-len.js +++ b/tools/node_modules/eslint/lib/rules/max-len.js @@ -183,12 +183,27 @@ module.exports = { (end.line > lineNumber || (end.line === lineNumber && end.column === line.length)); } + /** + * Check if a node is a JSXEmptyExpression contained in a single line JSXExpressionContainer. + * @param {ASTNode} node A node to check. + * @returns {boolean} True if the node is a JSXEmptyExpression contained in a single line JSXExpressionContainer. + */ + function isJSXEmptyExpressionInSingleLineContainer(node) { + if (!node || !node.parent || node.type !== "JSXEmptyExpression" || node.parent.type !== "JSXExpressionContainer") { + return false; + } + + const parent = node.parent; + + return parent.loc.start.line === parent.loc.end.line; + } + /** * Gets the line after the comment and any remaining trailing whitespace is * stripped. * @param {string} line The source line with a trailing comment * @param {ASTNode} comment The comment to remove - * @returns {string} Line without comment and trailing whitepace + * @returns {string} Line without comment and trailing whitespace */ function stripTrailingComment(line, comment) { @@ -252,6 +267,33 @@ module.exports = { return acc; } + /** + * Returns an array of all comments in the source code. + * If the element in the array is a JSXEmptyExpression contained with a single line JSXExpressionContainer, + * the element is changed with JSXExpressionContainer node. + * @returns {ASTNode[]} An array of comment nodes + */ + function getAllComments() { + const comments = []; + + sourceCode.getAllComments() + .forEach(commentNode => { + const containingNode = sourceCode.getNodeByRangeIndex(commentNode.range[0]); + + if (isJSXEmptyExpressionInSingleLineContainer(containingNode)) { + + // push a unique node only + if (comments[comments.length - 1] !== containingNode.parent) { + comments.push(containingNode.parent); + } + } else { + comments.push(commentNode); + } + }); + + return comments; + } + /** * Check the program for max length * @param {ASTNode} node Node to examine @@ -264,7 +306,7 @@ module.exports = { const lines = sourceCode.lines, // list of comments to ignore - comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : []; + comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? getAllComments() : []; // we iterate over comments in parallel with the lines let commentsIndex = 0; diff --git a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js index 0cfc1f8da9e65e..03539fae470078 100644 --- a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js +++ b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js @@ -54,9 +54,6 @@ const OPTIONS_OR_INTEGER_SCHEMA = { function getCommentLineNumbers(comments) { const map = new Map(); - if (!comments) { - return map; - } comments.forEach(comment => { for (let i = comment.loc.start.line; i <= comment.loc.end.line; i++) { map.set(i, comment); diff --git a/tools/node_modules/eslint/lib/rules/multiline-comment-style.js b/tools/node_modules/eslint/lib/rules/multiline-comment-style.js index fb50e1522ea11d..9524818b8bd74d 100644 --- a/tools/node_modules/eslint/lib/rules/multiline-comment-style.js +++ b/tools/node_modules/eslint/lib/rules/multiline-comment-style.js @@ -316,6 +316,10 @@ module.exports = { const [, prefix = "", initialOffset = ""] = lineTextToAlignWith.match(/^(\s*(?:\/?\*)?(\s*))/u) || []; offset = `${commentTextPrefix.slice(prefix.length)}${initialOffset}`; + + if (/^\s*\//u.test(lineText) && offset.length === 0) { + offset += " "; + } break; } diff --git a/tools/node_modules/eslint/lib/rules/new-cap.js b/tools/node_modules/eslint/lib/rules/new-cap.js index cee979310ea7cc..7cce968c5aed0e 100644 --- a/tools/node_modules/eslint/lib/rules/new-cap.js +++ b/tools/node_modules/eslint/lib/rules/new-cap.js @@ -9,6 +9,8 @@ // Requirements //------------------------------------------------------------------------------ +const astUtils = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ @@ -160,13 +162,7 @@ module.exports = { let name = ""; if (node.callee.type === "MemberExpression") { - const property = node.callee.property; - - if (property.type === "Literal" && (typeof property.value === "string")) { - name = property.value; - } else if (property.type === "Identifier" && !node.callee.computed) { - name = property.name; - } + name = astUtils.getStaticPropertyName(node.callee) || ""; } else { name = node.callee.name; } diff --git a/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js b/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js index b9a0e6ed0a70b5..9009b64fa1559a 100644 --- a/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js +++ b/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js @@ -1,6 +1,6 @@ /** * @fileoverview A rule to warn against using arrow functions when they could be - * confused with comparisions + * confused with comparisons * @author Jxck */ @@ -71,7 +71,7 @@ module.exports = { messageId: "confusing", fix(fixer) { - // if `allowParens` is not set to true dont bother wrapping in parens + // if `allowParens` is not set to true don't bother wrapping in parens return allowParens && fixer.replaceText(node.body, `(${sourceCode.getText(node.body)})`); } }); diff --git a/tools/node_modules/eslint/lib/rules/no-constant-condition.js b/tools/node_modules/eslint/lib/rules/no-constant-condition.js index d6d04174298cff..5e5838641028fe 100644 --- a/tools/node_modules/eslint/lib/rules/no-constant-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-constant-condition.js @@ -90,13 +90,27 @@ module.exports = { * @private */ function isConstant(node, inBooleanPosition) { + + // node.elements can return null values in the case of sparse arrays ex. [,] + if (!node) { + return true; + } switch (node.type) { case "Literal": case "ArrowFunctionExpression": case "FunctionExpression": case "ObjectExpression": - case "ArrayExpression": return true; + case "TemplateLiteral": + return (inBooleanPosition && node.quasis.some(quasi => quasi.value.cooked.length)) || + node.expressions.every(exp => isConstant(exp, inBooleanPosition)); + + case "ArrayExpression": { + if (node.parent.type === "BinaryExpression" && node.parent.operator === "+") { + return node.elements.every(element => isConstant(element, false)); + } + return true; + } case "UnaryExpression": if (node.operator === "void") { diff --git a/tools/node_modules/eslint/lib/rules/no-control-regex.js b/tools/node_modules/eslint/lib/rules/no-control-regex.js index 24e6b197be0b44..b39f731c3cdf29 100644 --- a/tools/node_modules/eslint/lib/rules/no-control-regex.js +++ b/tools/node_modules/eslint/lib/rules/no-control-regex.js @@ -1,5 +1,5 @@ /** - * @fileoverview Rule to forbid control charactes from regular expressions. + * @fileoverview Rule to forbid control characters from regular expressions. * @author Nicholas C. Zakas */ diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js index 6041e9e371ce5e..b12939d57bc884 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js @@ -5,6 +5,8 @@ "use strict"; +const astUtils = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -53,21 +55,6 @@ module.exports = { return stateMap[key][isStatic ? "static" : "nonStatic"]; } - /** - * Gets the name text of a given node. - * @param {ASTNode} node A node to get the name. - * @returns {string} The name text of the node. - */ - function getName(node) { - switch (node.type) { - case "Identifier": return node.name; - case "Literal": return String(node.value); - - /* istanbul ignore next: syntax error */ - default: return ""; - } - } - return { // Initializes the stack of state of member declarations. @@ -87,11 +74,12 @@ module.exports = { // Reports the node if its name has been declared already. MethodDefinition(node) { - if (node.computed) { + const name = astUtils.getStaticPropertyName(node); + + if (name === null || node.kind === "constructor") { return; } - const name = getName(node.key); const state = getState(name, node.static); let isDuplicate = false; diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-else-if.js b/tools/node_modules/eslint/lib/rules/no-dupe-else-if.js index a165e16607d2f0..cbeb437da1e7ec 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-else-if.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-else-if.js @@ -53,7 +53,7 @@ module.exports = { docs: { description: "disallow duplicate conditions in if-else-if chains", category: "Possible Errors", - recommended: false, + recommended: true, url: "https://eslint.org/docs/rules/no-dupe-else-if" }, diff --git a/tools/node_modules/eslint/lib/rules/no-eval.js b/tools/node_modules/eslint/lib/rules/no-eval.js index 9e56fb00b9fc5b..a293b04aa37de2 100644 --- a/tools/node_modules/eslint/lib/rules/no-eval.js +++ b/tools/node_modules/eslint/lib/rules/no-eval.js @@ -158,7 +158,7 @@ module.exports = { context.report({ node: reportNode, - loc: locationNode.loc.start, + loc: locationNode.loc, messageId: "unexpected" }); } diff --git a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js index 336f601d1652de..8ccd0bce9060b1 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js @@ -26,7 +26,16 @@ module.exports = { url: "https://eslint.org/docs/rules/no-extra-boolean-cast" }, - schema: [], + schema: [{ + type: "object", + properties: { + enforceForLogicalOperands: { + type: "boolean", + default: false + } + }, + additionalProperties: false + }], fixable: "code", messages: { @@ -47,23 +56,67 @@ module.exports = { "ForStatement" ]; + /** + * Check if a node is a Boolean function or constructor. + * @param {ASTNode} node the node + * @returns {boolean} If the node is Boolean function or constructor + */ + function isBooleanFunctionOrConstructorCall(node) { + + // Boolean() and new Boolean() + return (node.type === "CallExpression" || node.type === "NewExpression") && + node.callee.type === "Identifier" && + node.callee.name === "Boolean"; + } + + /** + * Checks whether the node is a logical expression and that the option is enabled + * @param {ASTNode} node the node + * @returns {boolean} if the node is a logical expression and option is enabled + */ + function isLogicalContext(node) { + return node.type === "LogicalExpression" && + (node.operator === "||" || node.operator === "&&") && + (context.options.length && context.options[0].enforceForLogicalOperands === true); + + } + + /** * Check if a node is in a context where its value would be coerced to a boolean at runtime. * @param {ASTNode} node The node - * @param {ASTNode} parent Its parent * @returns {boolean} If it is in a boolean context */ - function isInBooleanContext(node, parent) { + function isInBooleanContext(node) { return ( - (BOOLEAN_NODE_TYPES.indexOf(parent.type) !== -1 && - node === parent.test) || + (isBooleanFunctionOrConstructorCall(node.parent) && + node === node.parent.arguments[0]) || + + (BOOLEAN_NODE_TYPES.indexOf(node.parent.type) !== -1 && + node === node.parent.test) || // ! - (parent.type === "UnaryExpression" && - parent.operator === "!") + (node.parent.type === "UnaryExpression" && + node.parent.operator === "!") + ); + } + + /** + * Checks whether the node is a context that should report an error + * Acts recursively if it is in a logical context + * @param {ASTNode} node the node + * @returns {boolean} If the node is in one of the flagged contexts + */ + function isInFlaggedContext(node) { + return isInBooleanContext(node) || + (isLogicalContext(node.parent) && + + // For nested logical statements + isInFlaggedContext(node.parent) ); } + /** * Check if a node has comments inside. * @param {ASTNode} node The node to check. @@ -75,24 +128,18 @@ module.exports = { return { UnaryExpression(node) { - const ancestors = context.getAncestors(), - parent = ancestors.pop(), - grandparent = ancestors.pop(); + const parent = node.parent; + // Exit early if it's guaranteed not to match if (node.operator !== "!" || - parent.type !== "UnaryExpression" || - parent.operator !== "!") { + parent.type !== "UnaryExpression" || + parent.operator !== "!") { return; } - if (isInBooleanContext(parent, grandparent) || - // Boolean() and new Boolean() - ((grandparent.type === "CallExpression" || grandparent.type === "NewExpression") && - grandparent.callee.type === "Identifier" && - grandparent.callee.name === "Boolean") - ) { + if (isInFlaggedContext(parent)) { context.report({ node: parent, messageId: "unexpectedNegation", @@ -110,6 +157,10 @@ module.exports = { prefix = " "; } + if (astUtils.getPrecedence(node.argument) < astUtils.getPrecedence(parent.parent)) { + return fixer.replaceText(parent, `(${sourceCode.getText(node.argument)})`); + } + return fixer.replaceText(parent, prefix + sourceCode.getText(node.argument)); } }); @@ -122,7 +173,7 @@ module.exports = { return; } - if (isInBooleanContext(node, parent)) { + if (isInFlaggedContext(node)) { context.report({ node, messageId: "unexpectedCall", diff --git a/tools/node_modules/eslint/lib/rules/no-extra-parens.js b/tools/node_modules/eslint/lib/rules/no-extra-parens.js index f96e572bfeef54..a5488c3c1c6aa4 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-parens.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-parens.js @@ -169,6 +169,28 @@ module.exports = { return ruleApplies(node) && isParenthesisedTwice(node); } + /** + * Determines if a node that is expected to be parenthesised is surrounded by + * (potentially) invalid extra parentheses with considering precedence level of the node. + * If the preference level of the node is not higher or equal to precedence lower limit, it also checks + * whether the node is surrounded by parentheses twice or not. + * @param {ASTNode} node The node to be checked. + * @param {number} precedenceLowerLimit The lower limit of precedence. + * @returns {boolean} True if the node is has an unexpected extra pair of parentheses. + * @private + */ + function hasExcessParensWithPrecedence(node, precedenceLowerLimit) { + if (ruleApplies(node) && isParenthesised(node)) { + if ( + precedence(node) >= precedenceLowerLimit || + isParenthesisedTwice(node) + ) { + return true; + } + } + return false; + } + /** * Determines if a node test expression is allowed to have a parenthesised assignment * @param {ASTNode} node The node to be checked. @@ -320,6 +342,17 @@ module.exports = { return node.type === "CallExpression" && node.callee.type === "FunctionExpression"; } + /** + * Determines if the given node can be the assignment target in destructuring or the LHS of an assignment. + * This is to avoid an autofix that could change behavior because parsers mistakenly allow invalid syntax, + * such as `(a = b) = c` and `[(a = b) = c] = []`. Ideally, this function shouldn't be necessary. + * @param {ASTNode} [node] The node to check + * @returns {boolean} `true` if the given node can be a valid assignment target + */ + function canBeAssignmentTarget(node) { + return node && (node.type === "Identifier" || node.type === "MemberExpression"); + } + /** * Report the node * @param {ASTNode} node node to evaluate @@ -370,17 +403,13 @@ module.exports = { } /** - * Evaluate Unary update + * Evaluate a argument of the node. * @param {ASTNode} node node to evaluate * @returns {void} * @private */ - function checkUnaryUpdate(node) { - if (node.type === "UnaryExpression" && node.argument.type === "BinaryExpression" && node.argument.operator === "**") { - return; - } - - if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) { + function checkArgumentWithPrecedence(node) { + if (hasExcessParensWithPrecedence(node.argument, precedence(node))) { report(node.argument); } } @@ -411,25 +440,24 @@ module.exports = { function checkCallNew(node) { const callee = node.callee; - if (hasExcessParens(callee) && precedence(callee) >= precedence(node)) { + if (hasExcessParensWithPrecedence(callee, precedence(node))) { const hasNewParensException = callee.type === "NewExpression" && !isNewExpressionWithParens(callee); if ( hasDoubleExcessParens(callee) || !isIIFE(node) && !hasNewParensException && !( - /* - * Allow extra parens around a new expression if - * there are intervening parentheses. - */ - (callee.type === "MemberExpression" && doesMemberExpressionContainCallExpression(callee)) + // Allow extra parens around a new expression if they are intervening parentheses. + node.type === "NewExpression" && + callee.type === "MemberExpression" && + doesMemberExpressionContainCallExpression(callee) ) ) { report(node.callee); } } node.arguments - .filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .filter(arg => hasExcessParensWithPrecedence(arg, PRECEDENCE_OF_ASSIGNMENT_EXPR)) .forEach(report); } @@ -444,15 +472,26 @@ module.exports = { const leftPrecedence = precedence(node.left); const rightPrecedence = precedence(node.right); const isExponentiation = node.operator === "**"; - const shouldSkipLeft = (NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression")) || - node.left.type === "UnaryExpression" && isExponentiation; + const shouldSkipLeft = NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression"); const shouldSkipRight = NESTED_BINARY && (node.right.type === "BinaryExpression" || node.right.type === "LogicalExpression"); - if (!shouldSkipLeft && hasExcessParens(node.left) && (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation))) { - report(node.left); + if (!shouldSkipLeft && hasExcessParens(node.left)) { + if ( + !(node.left.type === "UnaryExpression" && isExponentiation) && + (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation)) || + isParenthesisedTwice(node.left) + ) { + report(node.left); + } } - if (!shouldSkipRight && hasExcessParens(node.right) && (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation))) { - report(node.right); + + if (!shouldSkipRight && hasExcessParens(node.right)) { + if ( + (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation)) || + isParenthesisedTwice(node.right) + ) { + report(node.right); + } } } @@ -485,11 +524,7 @@ module.exports = { * @returns {void} */ function checkSpreadOperator(node) { - const hasExtraParens = precedence(node.argument) >= PRECEDENCE_OF_ASSIGNMENT_EXPR - ? hasExcessParens(node.argument) - : hasDoubleExcessParens(node.argument); - - if (hasExtraParens) { + if (hasExcessParensWithPrecedence(node.argument, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.argument); } } @@ -651,7 +686,13 @@ module.exports = { return { ArrayExpression(node) { node.elements - .filter(e => e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .filter(e => e && hasExcessParensWithPrecedence(e, PRECEDENCE_OF_ASSIGNMENT_EXPR)) + .forEach(report); + }, + + ArrayPattern(node) { + node.elements + .filter(e => canBeAssignmentTarget(e) && hasExcessParens(e)) .forEach(report); }, @@ -661,8 +702,7 @@ module.exports = { } if (node.body.type === "ConditionalExpression" && - IGNORE_ARROW_CONDITIONALS && - !isParenthesisedTwice(node.body) + IGNORE_ARROW_CONDITIONALS ) { return; } @@ -674,18 +714,18 @@ module.exports = { if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) { tokensToIgnore.add(firstBodyToken); } - if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (hasExcessParensWithPrecedence(node.body, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.body); } } }, AssignmentExpression(node) { - if (isReturnAssignException(node)) { - return; + if (canBeAssignmentTarget(node.left) && hasExcessParens(node.left)) { + report(node.left); } - if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) { + if (!isReturnAssignException(node) && hasExcessParensWithPrecedence(node.right, precedence(node))) { report(node.right); } }, @@ -702,8 +742,8 @@ module.exports = { ClassBody(node) { node.body - .filter(member => member.type === "MethodDefinition" && member.computed && - member.key && hasExcessParens(member.key) && precedence(member.key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) + .filter(member => member.type === "MethodDefinition" && member.computed && member.key) + .filter(member => hasExcessParensWithPrecedence(member.key, PRECEDENCE_OF_ASSIGNMENT_EXPR)) .forEach(member => report(member.key)); }, @@ -711,16 +751,18 @@ module.exports = { if (isReturnAssignException(node)) { return; } - - if (hasExcessParens(node.test) && precedence(node.test) >= precedence({ type: "LogicalExpression", operator: "||" })) { + if ( + !isCondAssignException(node) && + hasExcessParensWithPrecedence(node.test, precedence({ type: "LogicalExpression", operator: "||" })) + ) { report(node.test); } - if (hasExcessParens(node.consequent) && precedence(node.consequent) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (hasExcessParensWithPrecedence(node.consequent, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.consequent); } - if (hasExcessParens(node.alternate) && precedence(node.alternate) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (hasExcessParensWithPrecedence(node.alternate, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(node.alternate); } }, @@ -757,9 +799,19 @@ module.exports = { tokensToIgnore.add(firstLeftToken); } } - if (!(node.type === "ForOfStatement" && node.right.type === "SequenceExpression") && hasExcessParens(node.right)) { + + if (node.type === "ForOfStatement") { + const hasExtraParens = node.right.type === "SequenceExpression" + ? hasDoubleExcessParens(node.right) + : hasExcessParens(node.right); + + if (hasExtraParens) { + report(node.right); + } + } else if (hasExcessParens(node.right)) { report(node.right); } + if (hasExcessParens(node.left)) { report(node.left); } @@ -910,11 +962,17 @@ module.exports = { NewExpression: checkCallNew, ObjectExpression(node) { + node.properties + .filter(property => property.value && hasExcessParensWithPrecedence(property.value, PRECEDENCE_OF_ASSIGNMENT_EXPR)) + .forEach(property => report(property.value)); + }, + + ObjectPattern(node) { node.properties .filter(property => { const value = property.value; - return value && hasExcessParens(value) && precedence(value) >= PRECEDENCE_OF_ASSIGNMENT_EXPR; + return canBeAssignmentTarget(value) && hasExcessParens(value); }).forEach(property => report(property.value)); }, @@ -922,12 +980,20 @@ module.exports = { if (node.computed) { const { key } = node; - if (key && hasExcessParens(key) && precedence(key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (key && hasExcessParensWithPrecedence(key, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(key); } } }, + RestElement(node) { + const argument = node.argument; + + if (canBeAssignmentTarget(argument) && hasExcessParens(argument)) { + report(argument); + } + }, + ReturnStatement(node) { const returnToken = sourceCode.getFirstToken(node); @@ -945,8 +1011,10 @@ module.exports = { }, SequenceExpression(node) { + const precedenceOfNode = precedence(node); + node.expressions - .filter(e => hasExcessParens(e) && precedence(e) >= precedence(node)) + .filter(e => hasExcessParensWithPrecedence(e, precedenceOfNode)) .forEach(report); }, @@ -970,16 +1038,17 @@ module.exports = { } }, - UnaryExpression: checkUnaryUpdate, - UpdateExpression: checkUnaryUpdate, - AwaitExpression: checkUnaryUpdate, + UnaryExpression: checkArgumentWithPrecedence, + UpdateExpression: checkArgumentWithPrecedence, + AwaitExpression: checkArgumentWithPrecedence, VariableDeclarator(node) { - if (node.init && hasExcessParens(node.init) && - precedence(node.init) >= PRECEDENCE_OF_ASSIGNMENT_EXPR && + if ( + node.init && hasExcessParensWithPrecedence(node.init, PRECEDENCE_OF_ASSIGNMENT_EXPR) && - // RegExp literal is allowed to have parens (#1589) - !(node.init.type === "Literal" && node.init.regex)) { + // RegExp literal is allowed to have parens (#1589) + !(node.init.type === "Literal" && node.init.regex) + ) { report(node.init); } }, @@ -1022,9 +1091,13 @@ module.exports = { }, AssignmentPattern(node) { - const { right } = node; + const { left, right } = node; + + if (canBeAssignmentTarget(left) && hasExcessParens(left)) { + report(left); + } - if (right && hasExcessParens(right) && precedence(right) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) { + if (right && hasExcessParensWithPrecedence(right, PRECEDENCE_OF_ASSIGNMENT_EXPR)) { report(right); } } diff --git a/tools/node_modules/eslint/lib/rules/no-func-assign.js b/tools/node_modules/eslint/lib/rules/no-func-assign.js index 66756e62bef5b2..33d0ad9ecd1433 100644 --- a/tools/node_modules/eslint/lib/rules/no-func-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-func-assign.js @@ -22,7 +22,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-func-assign" }, - schema: [] + schema: [], + + messages: { + isAFunction: "'{{name}}' is a function." + } }, create(context) { @@ -34,7 +38,13 @@ module.exports = { */ function checkReference(references) { astUtils.getModifyingReferences(references).forEach(reference => { - context.report({ node: reference.identifier, message: "'{{name}}' is a function.", data: { name: reference.identifier.name } }); + context.report({ + node: reference.identifier, + messageId: "isAFunction", + data: { + name: reference.identifier.name + } + }); }); } diff --git a/tools/node_modules/eslint/lib/rules/no-global-assign.js b/tools/node_modules/eslint/lib/rules/no-global-assign.js index 4ab0c706446256..ea854c4aa8cd9b 100644 --- a/tools/node_modules/eslint/lib/rules/no-global-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-global-assign.js @@ -32,7 +32,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + globalShouldNotBeModified: "Read-only global '{{name}}' should not be modified." + } }, create(context) { @@ -60,8 +64,10 @@ module.exports = { ) { context.report({ node: identifier, - message: "Read-only global '{{name}}' should not be modified.", - data: identifier + messageId: "globalShouldNotBeModified", + data: { + name: identifier.name + } }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js index c80f9813020be5..6d5ee61e96bd5b 100644 --- a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js +++ b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js @@ -187,7 +187,11 @@ module.exports = { } }, additionalProperties: false - }] + }], + + messages: { + useRecommendation: "use `{{recommendation}}` instead." + } }, create(context) { @@ -204,7 +208,7 @@ module.exports = { function report(node, recommendation, shouldFix) { context.report({ node, - message: "use `{{recommendation}}` instead.", + messageId: "useRecommendation", data: { recommendation }, diff --git a/tools/node_modules/eslint/lib/rules/no-implied-eval.js b/tools/node_modules/eslint/lib/rules/no-implied-eval.js index e0764d8223db0a..46bb5d4f76e5f7 100644 --- a/tools/node_modules/eslint/lib/rules/no-implied-eval.js +++ b/tools/node_modules/eslint/lib/rules/no-implied-eval.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-implied-eval" }, - schema: [] + schema: [], + + messages: { + impliedEval: "Implied eval. Consider passing a function instead of a string." + } }, create(context) { @@ -107,7 +111,10 @@ module.exports = { // remove the entire substack, to avoid duplicate reports const substack = impliedEvalAncestorsStack.pop(); - context.report({ node: substack[0], message: "Implied eval. Consider passing a function instead of a string." }); + context.report({ + node: substack[0], + messageId: "impliedEval" + }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-import-assign.js b/tools/node_modules/eslint/lib/rules/no-import-assign.js index 0865cf9a97704d..32e445ff68b3ef 100644 --- a/tools/node_modules/eslint/lib/rules/no-import-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-import-assign.js @@ -180,7 +180,7 @@ module.exports = { docs: { description: "disallow assigning to imported bindings", category: "Possible Errors", - recommended: false, + recommended: true, url: "https://eslint.org/docs/rules/no-import-assign" }, diff --git a/tools/node_modules/eslint/lib/rules/no-inline-comments.js b/tools/node_modules/eslint/lib/rules/no-inline-comments.js index bd226ecc35fde1..41b0f1e664c776 100644 --- a/tools/node_modules/eslint/lib/rules/no-inline-comments.js +++ b/tools/node_modules/eslint/lib/rules/no-inline-comments.js @@ -21,7 +21,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-inline-comments" }, - schema: [] + schema: [], + + messages: { + unexpectedInlineComment: "Unexpected comment inline with code." + } }, create(context) { @@ -64,7 +68,10 @@ module.exports = { return; } - context.report({ node, message: "Unexpected comment inline with code." }); + context.report({ + node, + messageId: "unexpectedInlineComment" + }); } //-------------------------------------------------------------------------- diff --git a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js index 60508d3e864eda..e1c29e0a3b4f3f 100644 --- a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js +++ b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js @@ -24,7 +24,11 @@ module.exports = { { enum: ["functions", "both"] } - ] + ], + + messages: { + moveDeclToRoot: "Move {{type}} declaration to {{body}} root." + } }, create(context) { @@ -68,7 +72,7 @@ module.exports = { if (!valid) { context.report({ node, - message: "Move {{type}} declaration to {{body}} root.", + messageId: "moveDeclToRoot", data: { type: (node.type === "FunctionDeclaration" ? "function" : "variable"), body: (body.type === "Program" ? "program" : "function body") diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js index 852efbbb935b90..c09e36fd017697 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js @@ -39,7 +39,11 @@ module.exports = { } }, additionalProperties: false - }] + }], + + messages: { + regexMessage: "{{message}}." + } }, create(context) { @@ -116,7 +120,7 @@ module.exports = { if (message) { context.report({ node, - message: "{{message}}.", + messageId: "regexMessage", data: { message } }); } diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-this.js b/tools/node_modules/eslint/lib/rules/no-invalid-this.js index 5398fc3b5f842c..a79c586d719852 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-this.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-this.js @@ -37,7 +37,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedThis: "Unexpected 'this'." + } }, create(context) { @@ -130,7 +134,10 @@ module.exports = { const current = stack.getCurrent(); if (current && !current.valid) { - context.report({ node, message: "Unexpected 'this'." }); + context.report({ + node, + messageId: "unexpectedThis" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js index f339fa6c8f34c9..21842331f21ff0 100644 --- a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js +++ b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js @@ -1,5 +1,5 @@ /** - * @fileoverview Rule to disalow whitespace that is not a tab or space, whitespace inside strings and comments are allowed + * @fileoverview Rule to disallow whitespace that is not a tab or space, whitespace inside strings and comments are allowed * @author Jonathan Kingston * @author Christophe Porteneuve */ @@ -59,7 +59,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + noIrregularWhitespace: "Irregular whitespace not allowed." + } }, create(context) { @@ -161,7 +165,11 @@ module.exports = { column: match.index }; - errors.push({ node, message: "Irregular whitespace not allowed.", loc: location }); + errors.push({ + node, + messageId: "noIrregularWhitespace", + loc: location + }); } }); } @@ -186,7 +194,11 @@ module.exports = { column: sourceLines[lineIndex].length }; - errors.push({ node, message: "Irregular whitespace not allowed.", loc: location }); + errors.push({ + node, + messageId: "noIrregularWhitespace", + loc: location + }); lastLineIndex = lineIndex; } } diff --git a/tools/node_modules/eslint/lib/rules/no-iterator.js b/tools/node_modules/eslint/lib/rules/no-iterator.js index 82319a3fb1dfb6..9ba1e7aefdbc3b 100644 --- a/tools/node_modules/eslint/lib/rules/no-iterator.js +++ b/tools/node_modules/eslint/lib/rules/no-iterator.js @@ -5,6 +5,12 @@ "use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const { getStaticPropertyName } = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -20,7 +26,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-iterator" }, - schema: [] + schema: [], + + messages: { + noIterator: "Reserved name '__iterator__'." + } }, create(context) { @@ -29,10 +39,11 @@ module.exports = { MemberExpression(node) { - if (node.property && - (node.property.type === "Identifier" && node.property.name === "__iterator__" && !node.computed) || - (node.property.type === "Literal" && node.property.value === "__iterator__")) { - context.report({ node, message: "Reserved name '__iterator__'." }); + if (getStaticPropertyName(node) === "__iterator__") { + context.report({ + node, + messageId: "noIterator" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-label-var.js b/tools/node_modules/eslint/lib/rules/no-label-var.js index a9fd042a390225..570db03285cf97 100644 --- a/tools/node_modules/eslint/lib/rules/no-label-var.js +++ b/tools/node_modules/eslint/lib/rules/no-label-var.js @@ -26,7 +26,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-label-var" }, - schema: [] + schema: [], + + messages: { + identifierClashWithLabel: "Found identifier with same name as label." + } }, create(context) { @@ -62,7 +66,10 @@ module.exports = { * with the innermost scope. */ if (findIdentifier(scope, node.label.name)) { - context.report({ node, message: "Found identifier with same name as label." }); + context.report({ + node, + messageId: "identifierClashWithLabel" + }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-labels.js b/tools/node_modules/eslint/lib/rules/no-labels.js index 52f4b0f5168b71..85760d80dbedd7 100644 --- a/tools/node_modules/eslint/lib/rules/no-labels.js +++ b/tools/node_modules/eslint/lib/rules/no-labels.js @@ -40,7 +40,13 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedLabel: "Unexpected labeled statement.", + unexpectedLabelInBreak: "Unexpected label in break statement.", + unexpectedLabelInContinue: "Unexpected label in continue statement." + } }, create(context) { @@ -113,7 +119,7 @@ module.exports = { if (!isAllowed(scopeInfo.kind)) { context.report({ node, - message: "Unexpected labeled statement." + messageId: "unexpectedLabel" }); } @@ -124,7 +130,7 @@ module.exports = { if (node.label && !isAllowed(getKind(node.label.name))) { context.report({ node, - message: "Unexpected label in break statement." + messageId: "unexpectedLabelInBreak" }); } }, @@ -133,7 +139,7 @@ module.exports = { if (node.label && !isAllowed(getKind(node.label.name))) { context.report({ node, - message: "Unexpected label in continue statement." + messageId: "unexpectedLabelInContinue" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js index 37561b0f9a3055..d7069887b8e460 100644 --- a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js +++ b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js @@ -20,7 +20,12 @@ module.exports = { url: "https://eslint.org/docs/rules/no-lone-blocks" }, - schema: [] + schema: [], + + messages: { + redundantBlock: "Block is redundant.", + redundantNestedBlock: "Nested block is redundant." + } }, create(context) { @@ -35,9 +40,12 @@ module.exports = { * @returns {void} */ function report(node) { - const message = node.parent.type === "BlockStatement" ? "Nested block is redundant." : "Block is redundant."; + const messageId = node.parent.type === "BlockStatement" ? "redundantNestedBlock" : "redundantBlock"; - context.report({ node, message }); + context.report({ + node, + messageId + }); } /** diff --git a/tools/node_modules/eslint/lib/rules/no-lonely-if.js b/tools/node_modules/eslint/lib/rules/no-lonely-if.js index b62d176a264210..6552adc5752852 100644 --- a/tools/node_modules/eslint/lib/rules/no-lonely-if.js +++ b/tools/node_modules/eslint/lib/rules/no-lonely-if.js @@ -1,5 +1,5 @@ /** - * @fileoverview Rule to disallow if as the only statmenet in an else block + * @fileoverview Rule to disallow if as the only statement in an else block * @author Brandon Mills */ "use strict"; @@ -20,7 +20,11 @@ module.exports = { }, schema: [], - fixable: "code" + fixable: "code", + + messages: { + unexpectedLonelyIf: "Unexpected if as the only statement in an else block." + } }, create(context) { @@ -38,7 +42,7 @@ module.exports = { parent === grandparent.alternate) { context.report({ node, - message: "Unexpected if as the only statement in an else block.", + messageId: "unexpectedLonelyIf", fix(fixer) { const openingElseCurly = sourceCode.getFirstToken(parent); const closingElseCurly = sourceCode.getLastToken(parent); diff --git a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js index 0909e3166d952e..5dd6feaab0dbff 100644 --- a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js +++ b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js @@ -5,10 +5,24 @@ "use strict"; +const { isNumericLiteral } = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ +/** + * Convert the value to bigint if it's a string. Otherwise return the value as-is. + * @param {bigint|number|string} x The value to normalize. + * @returns {bigint|number} The normalized value. + */ +function normalizeIgnoreValue(x) { + if (typeof x === "string") { + return BigInt(x.slice(0, -1)); + } + return x; +} + module.exports = { meta: { type: "suggestion", @@ -34,7 +48,10 @@ module.exports = { ignore: { type: "array", items: { - type: "number" + anyOf: [ + { type: "number" }, + { type: "string", pattern: "^[+-]?(?:0|[1-9][0-9]*)n$" } + ] }, uniqueItems: true }, @@ -56,18 +73,9 @@ module.exports = { const config = context.options[0] || {}, detectObjects = !!config.detectObjects, enforceConst = !!config.enforceConst, - ignore = config.ignore || [], + ignore = (config.ignore || []).map(normalizeIgnoreValue), ignoreArrayIndexes = !!config.ignoreArrayIndexes; - /** - * Returns whether the node is number literal - * @param {Node} node the node literal being evaluated - * @returns {boolean} true if the node is a number literal - */ - function isNumber(node) { - return typeof node.value === "number"; - } - /** * Returns whether the number should be ignored * @param {number} num the number @@ -102,18 +110,21 @@ module.exports = { /** * Returns whether the number should be ignored when used as an array index with enabled 'ignoreArrayIndexes' option. - * @param {ASTNode} parent the non-"UnaryExpression" parent. + * @param {ASTNode} node Node to check * @returns {boolean} true if the number should be ignored */ - function shouldIgnoreArrayIndexes(parent) { - return parent.type === "MemberExpression" && ignoreArrayIndexes; + function shouldIgnoreArrayIndexes(node) { + const parent = node.parent; + + return ignoreArrayIndexes && + parent.type === "MemberExpression" && parent.property === node; } return { Literal(node) { const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"]; - if (!isNumber(node)) { + if (!isNumericLiteral(node)) { return; } @@ -137,7 +148,7 @@ module.exports = { if (shouldIgnoreNumber(value) || shouldIgnoreParseInt(parent, fullNumberNode) || - shouldIgnoreArrayIndexes(parent) || + shouldIgnoreArrayIndexes(fullNumberNode) || shouldIgnoreJSXNumbers(parent)) { return; } diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js index 80fac79affdb0e..37e8906e827a4c 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js @@ -112,7 +112,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedMixedOperator: "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'." + } }, create(context) { @@ -188,8 +192,6 @@ module.exports = { const parent = node.parent; const left = (getChildNode(parent) === node) ? node : parent; const right = (getChildNode(parent) !== node) ? node : parent; - const message = - "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'."; const data = { leftOperator: left.operator || "?:", rightOperator: right.operator || "?:" @@ -198,13 +200,13 @@ module.exports = { context.report({ node: left, loc: getOperatorToken(left).loc, - message, + messageId: "unexpectedMixedOperator", data }); context.report({ node: right, loc: getOperatorToken(right).loc, - message, + messageId: "unexpectedMixedOperator", data }); } diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js index fda8a11d9e2e74..8e988e32c24f84 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js @@ -40,7 +40,12 @@ module.exports = { } ] } - ] + ], + + messages: { + noMixRequire: "Do not mix 'require' and other declarations.", + noMixCoreModuleFileComputed: "Do not mix core, module, file and computed requires." + } }, create(context) { @@ -211,9 +216,15 @@ module.exports = { VariableDeclaration(node) { if (isMixed(node.declarations)) { - context.report({ node, message: "Do not mix 'require' and other declarations." }); + context.report({ + node, + messageId: "noMixRequire" + }); } else if (grouping && !isGrouped(node.declarations)) { - context.report({ node, message: "Do not mix core, module, file and computed requires." }); + context.report({ + node, + messageId: "noMixCoreModuleFileComputed" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js index 7b1e2c4a2a760c..16c2bd4122e851 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js @@ -23,14 +23,17 @@ module.exports = { { enum: ["smart-tabs", true, false] } - ] + ], + + messages: { + mixedSpacesAndTabs: "Mixed spaces and tabs." + } }, create(context) { const sourceCode = context.getSourceCode(); let smartTabs; - const ignoredLocs = []; switch (context.options[0]) { case true: // Support old syntax, maybe add deprecation warning here @@ -41,47 +44,23 @@ module.exports = { smartTabs = false; } - /** - * Determines if a given line and column are before a location. - * @param {Location} loc The location object from an AST node. - * @param {int} line The line to check. - * @param {int} column The column to check. - * @returns {boolean} True if the line and column are before the location, false if not. - * @private - */ - function beforeLoc(loc, line, column) { - if (line < loc.start.line) { - return true; - } - return line === loc.start.line && column < loc.start.column; - } - - /** - * Determines if a given line and column are after a location. - * @param {Location} loc The location object from an AST node. - * @param {int} line The line to check. - * @param {int} column The column to check. - * @returns {boolean} True if the line and column are after the location, false if not. - * @private - */ - function afterLoc(loc, line, column) { - if (line > loc.end.line) { - return true; - } - return line === loc.end.line && column > loc.end.column; - } - //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - TemplateElement(node) { - ignoredLocs.push(node.loc); - }, - "Program:exit"(node) { + const lines = sourceCode.lines, + comments = sourceCode.getAllComments(), + ignoredCommentLines = new Set(); + + // Add all lines except the first ones. + comments.forEach(comment => { + for (let i = comment.loc.start.line + 1; i <= comment.loc.end.line; i++) { + ignoredCommentLines.add(i); + } + }); /* * At least one space followed by a tab @@ -89,24 +68,6 @@ module.exports = { * characters begin. */ let regex = /^(?=[\t ]*(\t | \t))/u; - const lines = sourceCode.lines, - comments = sourceCode.getAllComments(); - - comments.forEach(comment => { - ignoredLocs.push(comment.loc); - }); - - ignoredLocs.sort((first, second) => { - if (beforeLoc(first, second.start.line, second.start.column)) { - return 1; - } - - if (beforeLoc(second, first.start.line, second.start.column)) { - return -1; - } - - return 0; - }); if (smartTabs) { @@ -122,25 +83,23 @@ module.exports = { if (match) { const lineNumber = i + 1, - column = match.index + 1; - - for (let j = 0; j < ignoredLocs.length; j++) { - if (beforeLoc(ignoredLocs[j], lineNumber, column)) { - continue; + column = match.index + 1, + loc = { line: lineNumber, column }; + + if (!ignoredCommentLines.has(lineNumber)) { + const containingNode = sourceCode.getNodeByRangeIndex(sourceCode.getIndexFromLoc(loc)); + + if (!(containingNode && ["Literal", "TemplateElement"].includes(containingNode.type))) { + context.report({ + node, + loc, + messageId: "mixedSpacesAndTabs" + }); } - if (afterLoc(ignoredLocs[j], lineNumber, column)) { - continue; - } - - return; } - - context.report({ node, loc: { line: lineNumber, column }, message: "Mixed spaces and tabs." }); } }); } - }; - } }; diff --git a/tools/node_modules/eslint/lib/rules/no-multi-assign.js b/tools/node_modules/eslint/lib/rules/no-multi-assign.js index 8524a1a571ef9e..ab6430c19ef070 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-assign.js @@ -21,7 +21,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-multi-assign" }, - schema: [] + schema: [], + + messages: { + unexpectedChain: "Unexpected chained assignment." + } }, create(context) { @@ -35,7 +39,7 @@ module.exports = { if (["AssignmentExpression", "VariableDeclarator"].indexOf(node.parent.type) !== -1) { context.report({ node, - message: "Unexpected chained assignment." + messageId: "unexpectedChain" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js index 403d04da9dd9ec..d43ed736337945 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js @@ -44,7 +44,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + multipleSpaces: "Multiple spaces found before '{{displayValue}}'." + } }, create(context) { @@ -122,7 +126,7 @@ module.exports = { context.report({ node: rightToken, loc: { start: leftToken.loc.end, end: rightToken.loc.start }, - message: "Multiple spaces found before '{{displayValue}}'.", + messageId: "multipleSpaces", data: { displayValue }, fix: fixer => fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " ") }); diff --git a/tools/node_modules/eslint/lib/rules/no-multi-str.js b/tools/node_modules/eslint/lib/rules/no-multi-str.js index f6832f3341777f..7cf1ae367942fe 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-str.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-str.js @@ -26,7 +26,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-multi-str" }, - schema: [] + schema: [], + + messages: { + multilineString: "Multiline support is limited to browsers supporting ES5 only." + } }, create(context) { @@ -49,7 +53,10 @@ module.exports = { Literal(node) { if (astUtils.LINEBREAK_MATCHER.test(node.raw) && !isJSXElement(node.parent)) { - context.report({ node, message: "Multiline support is limited to browsers supporting ES5 only." }); + context.report({ + node, + messageId: "multilineString" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js index 41e6be3a289584..9cccef3088a56e 100644 --- a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js +++ b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js @@ -42,7 +42,13 @@ module.exports = { required: ["max"], additionalProperties: false } - ] + ], + + messages: { + blankBeginningOfFile: "Too many blank lines at the beginning of file. Max of {{max}} allowed.", + blankEndOfFile: "Too many blank lines at the end of file. Max of {{max}} allowed.", + consecutiveBlank: "More than {{max}} blank {{pluralizedLines}} not allowed." + } }, create(context) { @@ -94,25 +100,31 @@ module.exports = { // Given two line numbers of non-empty lines, report the lines between if the difference is too large. .reduce((lastLineNumber, lineNumber) => { - let message, maxAllowed; + let messageId, maxAllowed; if (lastLineNumber === 0) { - message = "Too many blank lines at the beginning of file. Max of {{max}} allowed."; + messageId = "blankBeginningOfFile"; maxAllowed = maxBOF; } else if (lineNumber === allLines.length + 1) { - message = "Too many blank lines at the end of file. Max of {{max}} allowed."; + messageId = "blankEndOfFile"; maxAllowed = maxEOF; } else { - message = "More than {{max}} blank {{pluralizedLines}} not allowed."; + messageId = "consecutiveBlank"; maxAllowed = max; } if (lineNumber - lastLineNumber - 1 > maxAllowed) { context.report({ node, - loc: { start: { line: lastLineNumber + maxAllowed + 1, column: 0 }, end: { line: lineNumber, column: 0 } }, - message, - data: { max: maxAllowed, pluralizedLines: maxAllowed === 1 ? "line" : "lines" }, + loc: { + start: { line: lastLineNumber + maxAllowed + 1, column: 0 }, + end: { line: lineNumber, column: 0 } + }, + messageId, + data: { + max: maxAllowed, + pluralizedLines: maxAllowed === 1 ? "line" : "lines" + }, fix(fixer) { const rangeStart = sourceCode.getIndexFromLoc({ line: lastLineNumber + 1, column: 0 }); diff --git a/tools/node_modules/eslint/lib/rules/no-native-reassign.js b/tools/node_modules/eslint/lib/rules/no-native-reassign.js index eb233c80b1cca0..833e3b7ce409b3 100644 --- a/tools/node_modules/eslint/lib/rules/no-native-reassign.js +++ b/tools/node_modules/eslint/lib/rules/no-native-reassign.js @@ -37,7 +37,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + nativeReassign: "Read-only global '{{name}}' should not be modified." + } }, create(context) { @@ -65,7 +69,7 @@ module.exports = { ) { context.report({ node: identifier, - message: "Read-only global '{{name}}' should not be modified.", + messageId: "nativeReassign", data: identifier }); } diff --git a/tools/node_modules/eslint/lib/rules/no-negated-condition.js b/tools/node_modules/eslint/lib/rules/no-negated-condition.js index e55a8287487de3..8a9eba881df04c 100644 --- a/tools/node_modules/eslint/lib/rules/no-negated-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-negated-condition.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-negated-condition" }, - schema: [] + schema: [], + + messages: { + unexpectedNegated: "Unexpected negated condition." + } }, create(context) { @@ -72,12 +76,18 @@ module.exports = { } if (isNegatedIf(node)) { - context.report({ node, message: "Unexpected negated condition." }); + context.report({ + node, + messageId: "unexpectedNegated" + }); } }, ConditionalExpression(node) { if (isNegatedIf(node)) { - context.report({ node, message: "Unexpected negated condition." }); + context.report({ + node, + messageId: "unexpectedNegated" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js b/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js index 0084ad1570bb00..1229cedd1190dc 100644 --- a/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js +++ b/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js @@ -24,7 +24,11 @@ module.exports = { replacedBy: ["no-unsafe-negation"], deprecated: true, - schema: [] + schema: [], + + messages: { + negatedLHS: "The 'in' expression's left operand is negated." + } }, create(context) { @@ -33,7 +37,7 @@ module.exports = { BinaryExpression(node) { if (node.operator === "in" && node.left.type === "UnaryExpression" && node.left.operator === "!") { - context.report({ node, message: "The 'in' expression's left operand is negated." }); + context.report({ node, messageId: "negatedLHS" }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js index 87a11e87962a8f..383bb238887d2a 100644 --- a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-nested-ternary" }, - schema: [] + schema: [], + + messages: { + noNestedTernary: "Do not nest ternary expressions." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { ConditionalExpression(node) { if (node.alternate.type === "ConditionalExpression" || node.consequent.type === "ConditionalExpression") { - context.report({ node, message: "Do not nest ternary expressions." }); + context.report({ + node, + messageId: "noNestedTernary" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new-func.js b/tools/node_modules/eslint/lib/rules/no-new-func.js index 23e92f7bf3030c..d1360e9dee036d 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-func.js +++ b/tools/node_modules/eslint/lib/rules/no-new-func.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-func" }, - schema: [] + schema: [], + + messages: { + noFunctionConstructor: "The Function constructor is eval." + } }, create(context) { @@ -36,7 +40,10 @@ module.exports = { * @private */ function report(node) { - context.report({ node, message: "The Function constructor is eval." }); + context.report({ + node, + messageId: "noFunctionConstructor" + }); } return { diff --git a/tools/node_modules/eslint/lib/rules/no-new-object.js b/tools/node_modules/eslint/lib/rules/no-new-object.js index f5cc28664f4e1c..f3e99c9bd13502 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-object.js +++ b/tools/node_modules/eslint/lib/rules/no-new-object.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-object" }, - schema: [] + schema: [], + + messages: { + preferLiteral: "The object literal notation {} is preferrable." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { NewExpression(node) { if (node.callee.name === "Object") { - context.report({ node, message: "The object literal notation {} is preferrable." }); + context.report({ + node, + messageId: "preferLiteral" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new-require.js b/tools/node_modules/eslint/lib/rules/no-new-require.js index 1eae0659430fbd..df12a424e3527e 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-require.js +++ b/tools/node_modules/eslint/lib/rules/no-new-require.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-require" }, - schema: [] + schema: [], + + messages: { + noNewRequire: "Unexpected use of new with require." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { NewExpression(node) { if (node.callee.type === "Identifier" && node.callee.name === "require") { - context.report({ node, message: "Unexpected use of new with require." }); + context.report({ + node, + messageId: "noNewRequire" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new-symbol.js b/tools/node_modules/eslint/lib/rules/no-new-symbol.js index ccf757ed6a0cee..cb7e4f0fc88d69 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-symbol.js +++ b/tools/node_modules/eslint/lib/rules/no-new-symbol.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-symbol" }, - schema: [] + schema: [], + + messages: { + noNewSymbol: "`Symbol` cannot be called as a constructor." + } }, create(context) { @@ -35,7 +39,10 @@ module.exports = { const node = ref.identifier; if (node.parent && node.parent.type === "NewExpression") { - context.report({ node, message: "`Symbol` cannot be called as a constructor." }); + context.report({ + node, + messageId: "noNewSymbol" + }); } }); } diff --git a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js index ae2aeec0341243..0a2861fa5f7799 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js +++ b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new-wrappers" }, - schema: [] + schema: [], + + messages: { + noConstructor: "Do not use {{fn}} as a constructor." + } }, create(context) { @@ -31,7 +35,11 @@ module.exports = { const wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"]; if (wrapperObjects.indexOf(node.callee.name) > -1) { - context.report({ node, message: "Do not use {{fn}} as a constructor.", data: { fn: node.callee.name } }); + context.report({ + node, + messageId: "noConstructor", + data: { fn: node.callee.name } + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-new.js b/tools/node_modules/eslint/lib/rules/no-new.js index 2e0702597eade3..aa8a4e26876609 100644 --- a/tools/node_modules/eslint/lib/rules/no-new.js +++ b/tools/node_modules/eslint/lib/rules/no-new.js @@ -21,14 +21,21 @@ module.exports = { url: "https://eslint.org/docs/rules/no-new" }, - schema: [] + schema: [], + + messages: { + noNewStatement: "Do not use 'new' for side effects." + } }, create(context) { return { "ExpressionStatement > NewExpression"(node) { - context.report({ node: node.parent, message: "Do not use 'new' for side effects." }); + context.report({ + node: node.parent, + messageId: "noNewStatement" + }); } }; diff --git a/tools/node_modules/eslint/lib/rules/no-obj-calls.js b/tools/node_modules/eslint/lib/rules/no-obj-calls.js index 5102d5594949ba..9ff666b03281ca 100644 --- a/tools/node_modules/eslint/lib/rules/no-obj-calls.js +++ b/tools/node_modules/eslint/lib/rules/no-obj-calls.js @@ -47,8 +47,8 @@ module.exports = { const tracker = new ReferenceTracker(scope); const traceMap = {}; - for (const global of nonCallableGlobals) { - traceMap[global] = { + for (const g of nonCallableGlobals) { + traceMap[g] = { [CALL]: true }; } diff --git a/tools/node_modules/eslint/lib/rules/no-octal.js b/tools/node_modules/eslint/lib/rules/no-octal.js index 5ee69f0309ee03..e9940befafa889 100644 --- a/tools/node_modules/eslint/lib/rules/no-octal.js +++ b/tools/node_modules/eslint/lib/rules/no-octal.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-octal" }, - schema: [] + schema: [], + + messages: { + noOcatal: "Octal literals should not be used." + } }, create(context) { @@ -29,7 +33,10 @@ module.exports = { Literal(node) { if (typeof node.value === "number" && /^0[0-9]/u.test(node.raw)) { - context.report({ node, message: "Octal literals should not be used." }); + context.report({ + node, + messageId: "noOcatal" + }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-param-reassign.js b/tools/node_modules/eslint/lib/rules/no-param-reassign.js index d65eb34762aaf2..6874af44f389b7 100644 --- a/tools/node_modules/eslint/lib/rules/no-param-reassign.js +++ b/tools/node_modules/eslint/lib/rules/no-param-reassign.js @@ -58,7 +58,12 @@ module.exports = { } ] } - ] + ], + + messages: { + assignmentToFunctionParam: "Assignment to function parameter '{{name}}'.", + assignmentToFunctionParamProp: "Assignment to property of function parameter '{{name}}'." + } }, create(context) { @@ -177,9 +182,17 @@ module.exports = { (index === 0 || references[index - 1].identifier !== identifier) ) { if (reference.isWrite()) { - context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } }); + context.report({ + node: identifier, + messageId: "assignmentToFunctionParam", + data: { name: identifier.name } + }); } else if (props && isModifyingProp(reference) && !isIgnoredPropertyAssignment(identifier.name)) { - context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } }); + context.report({ + node: identifier, + messageId: "assignmentToFunctionParamProp", + data: { name: identifier.name } + }); } } } diff --git a/tools/node_modules/eslint/lib/rules/no-path-concat.js b/tools/node_modules/eslint/lib/rules/no-path-concat.js index abe0d5247db719..9fa8b852fe8358 100644 --- a/tools/node_modules/eslint/lib/rules/no-path-concat.js +++ b/tools/node_modules/eslint/lib/rules/no-path-concat.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-path-concat" }, - schema: [] + schema: [], + + messages: { + usePathFunctions: "Use path.join() or path.resolve() instead of + to create paths." + } }, create(context) { @@ -42,7 +46,10 @@ module.exports = { (right.type === "Identifier" && MATCHER.test(right.name))) ) { - context.report({ node, message: "Use path.join() or path.resolve() instead of + to create paths." }); + context.report({ + node, + messageId: "usePathFunctions" + }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-plusplus.js b/tools/node_modules/eslint/lib/rules/no-plusplus.js index 1d122dcd31f086..f55303863d25ca 100644 --- a/tools/node_modules/eslint/lib/rules/no-plusplus.js +++ b/tools/node_modules/eslint/lib/rules/no-plusplus.js @@ -32,7 +32,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedUnaryOp: "Unary operator '{{operator}}' used." + } }, create(context) { @@ -52,7 +56,7 @@ module.exports = { } context.report({ node, - message: "Unary operator '{{operator}}' used.", + messageId: "unexpectedUnaryOp", data: { operator: node.operator } diff --git a/tools/node_modules/eslint/lib/rules/no-process-env.js b/tools/node_modules/eslint/lib/rules/no-process-env.js index a66d9709b09b4f..0f8d7f8a339d0e 100644 --- a/tools/node_modules/eslint/lib/rules/no-process-env.js +++ b/tools/node_modules/eslint/lib/rules/no-process-env.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-process-env" }, - schema: [] + schema: [], + + messages: { + unexpectedProcessEnv: "Unexpected use of process.env." + } }, create(context) { @@ -31,7 +35,7 @@ module.exports = { propertyName = node.property.name; if (objectName === "process" && !node.computed && propertyName && propertyName === "env") { - context.report({ node, message: "Unexpected use of process.env." }); + context.report({ node, messageId: "unexpectedProcessEnv" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-process-exit.js b/tools/node_modules/eslint/lib/rules/no-process-exit.js index fcfc6b2af59d0e..29871660cc6ee1 100644 --- a/tools/node_modules/eslint/lib/rules/no-process-exit.js +++ b/tools/node_modules/eslint/lib/rules/no-process-exit.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-process-exit" }, - schema: [] + schema: [], + + messages: { + noProcessExit: "Don't use process.exit(); throw an error instead." + } }, create(context) { @@ -30,7 +34,7 @@ module.exports = { return { "CallExpression > MemberExpression.callee[object.name = 'process'][property.name = 'exit']"(node) { - context.report({ node: node.parent, message: "Don't use process.exit(); throw an error instead." }); + context.report({ node: node.parent, messageId: "noProcessExit" }); } }; diff --git a/tools/node_modules/eslint/lib/rules/no-proto.js b/tools/node_modules/eslint/lib/rules/no-proto.js index 80b9650941696d..82ce02fa4e3b9e 100644 --- a/tools/node_modules/eslint/lib/rules/no-proto.js +++ b/tools/node_modules/eslint/lib/rules/no-proto.js @@ -5,6 +5,12 @@ "use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const { getStaticPropertyName } = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -20,7 +26,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-proto" }, - schema: [] + schema: [], + + messages: { + unexpectedProto: "The '__proto__' property is deprecated." + } }, create(context) { @@ -28,11 +38,8 @@ module.exports = { return { MemberExpression(node) { - - if (node.property && - (node.property.type === "Identifier" && node.property.name === "__proto__" && !node.computed) || - (node.property.type === "Literal" && node.property.value === "__proto__")) { - context.report({ node, message: "The '__proto__' property is deprecated." }); + if (getStaticPropertyName(node) === "__proto__") { + context.report({ node, messageId: "unexpectedProto" }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js b/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js index 87a760156e3693..5bed2539a6486b 100644 --- a/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js +++ b/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-prototype-builtins" }, - schema: [] + schema: [], + + messages: { + prototypeBuildIn: "Do not access Object.prototype method '{{prop}}' from target object." + } }, create(context) { @@ -42,7 +46,7 @@ module.exports = { if (DISALLOWED_PROPS.indexOf(propName) > -1) { context.report({ - message: "Do not access Object.prototype method '{{prop}}' from target object.", + messageId: "prototypeBuildIn", loc: node.callee.property.loc.start, data: { prop: propName }, node diff --git a/tools/node_modules/eslint/lib/rules/no-regex-spaces.js b/tools/node_modules/eslint/lib/rules/no-regex-spaces.js index 7581e9271fdf14..afb26d70259f1b 100644 --- a/tools/node_modules/eslint/lib/rules/no-regex-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-regex-spaces.js @@ -45,7 +45,11 @@ module.exports = { }, schema: [], - fixable: "code" + fixable: "code", + + messages: { + multipleSpaces: "Spaces are hard to count. Use {{{length}}}." + } }, create(context) { @@ -96,7 +100,7 @@ module.exports = { ) { context.report({ node: nodeToReport, - message: "Spaces are hard to count. Use {{{length}}}.", + messageId: "multipleSpaces", data: { length }, fix(fixer) { if (pattern !== rawPattern) { @@ -109,7 +113,7 @@ module.exports = { } }); - // Report only the first occurence of consecutive spaces + // Report only the first occurrence of consecutive spaces return; } } diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-exports.js b/tools/node_modules/eslint/lib/rules/no-restricted-exports.js new file mode 100644 index 00000000000000..5b5c7d9bffb99c --- /dev/null +++ b/tools/node_modules/eslint/lib/rules/no-restricted-exports.js @@ -0,0 +1,84 @@ +/** + * @fileoverview Rule to disallow specified names in exports + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "suggestion", + + docs: { + description: "disallow specified names in exports", + category: "ECMAScript 6", + recommended: false, + url: "https://eslint.org/docs/rules/no-restricted-exports" + }, + + schema: [{ + type: "object", + properties: { + restrictedNamedExports: { + type: "array", + items: { + type: "string" + }, + uniqueItems: true + } + }, + additionalProperties: false + }], + + messages: { + restrictedNamed: "'{{name}}' is restricted from being used as an exported name." + } + }, + + create(context) { + + const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports); + + /** + * Checks and reports given exported identifier. + * @param {ASTNode} node exported `Identifer` node to check. + * @returns {void} + */ + function checkExportedName(node) { + const name = node.name; + + if (restrictedNames.has(name)) { + context.report({ + node, + messageId: "restrictedNamed", + data: { name } + }); + } + } + + return { + ExportNamedDeclaration(node) { + const declaration = node.declaration; + + if (declaration) { + if (declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") { + checkExportedName(declaration.id); + } else if (declaration.type === "VariableDeclaration") { + context.getDeclaredVariables(declaration) + .map(v => v.defs.find(d => d.parent === declaration)) + .map(d => d.name) // Identifier nodes + .forEach(checkExportedName); + } + } else { + node.specifiers + .map(s => s.exported) + .forEach(checkExportedName); + } + } + }; + } +}; diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js index 1a2629a8ec95e8..2c932a7307c0b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js @@ -4,13 +4,6 @@ */ "use strict"; -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -const DEFAULT_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'.", - CUSTOM_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'. {{customMessage}}"; - //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -46,6 +39,12 @@ module.exports = { }, uniqueItems: true, minItems: 0 + }, + + messages: { + defaultMessage: "Unexpected use of '{{name}}'.", + // eslint-disable-next-line eslint-plugin/report-message-format + customMessage: "Unexpected use of '{{name}}'. {{customMessage}}" } }, @@ -75,13 +74,13 @@ module.exports = { function reportReference(reference) { const name = reference.identifier.name, customMessage = restrictedGlobalMessages[name], - message = customMessage - ? CUSTOM_MESSAGE_TEMPLATE - : DEFAULT_MESSAGE_TEMPLATE; + messageId = customMessage + ? "customMessage" + : "defaultMessage"; context.report({ node: reference.identifier, - message, + messageId, data: { name, customMessage diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js index ec0696f99a2de0..c205dad8bdb79d 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js @@ -64,7 +64,11 @@ module.exports = { everything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.", // eslint-disable-next-line eslint-plugin/report-message-format - everythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted. {{customMessage}}" + everythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted. {{customMessage}}", + + importName: "'{{importName}}' import from '{{importSource}}' is restricted.", + // eslint-disable-next-line eslint-plugin/report-message-format + importNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}" }, schema: { @@ -87,6 +91,7 @@ module.exports = { }, create(context) { + const sourceCode = context.getSourceCode(); const options = Array.isArray(context.options) ? context.options : []; const isPathAndPatternsObject = typeof options[0] === "object" && @@ -95,6 +100,11 @@ module.exports = { const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || []; const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || []; + // if no imports are restricted we don"t need to check + if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) { + return {}; + } + const restrictedPathMessages = restrictedPaths.reduce((memo, importSource) => { if (typeof importSource === "string") { memo[importSource] = { message: null }; @@ -107,40 +117,68 @@ module.exports = { return memo; }, {}); - // if no imports are restricted we don"t need to check - if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) { - return {}; - } - const restrictedPatternsMatcher = ignore().add(restrictedPatterns); - /** - * Checks to see if "*" is being used to import everything. - * @param {Set.} importNames Set of import names that are being imported - * @returns {boolean} whether everything is imported or not - */ - function isEverythingImported(importNames) { - return importNames.has("*"); - } - /** * Report a restricted path. + * @param {string} importSource path of the import + * @param {Map} importNames Map of import names that are being imported * @param {node} node representing the restricted path reference * @returns {void} * @private */ - function reportPath(node) { - const importSource = node.source.value.trim(); - const customMessage = restrictedPathMessages[importSource] && restrictedPathMessages[importSource].message; + function checkRestrictedPathAndReport(importSource, importNames, node) { + if (!Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) { + return; + } - context.report({ - node, - messageId: customMessage ? "pathWithCustomMessage" : "path", - data: { - importSource, - customMessage + const customMessage = restrictedPathMessages[importSource].message; + const restrictedImportNames = restrictedPathMessages[importSource].importNames; + + if (restrictedImportNames) { + if (importNames.has("*")) { + const specifierData = importNames.get("*")[0]; + + context.report({ + node, + messageId: customMessage ? "everythingWithCustomMessage" : "everything", + loc: specifierData.loc, + data: { + importSource, + importNames: restrictedImportNames, + customMessage + } + }); } - }); + + restrictedImportNames.forEach(importName => { + if (importNames.has(importName)) { + const specifiers = importNames.get(importName); + + specifiers.forEach(specifier => { + context.report({ + node, + messageId: customMessage ? "importNameWithCustomMessage" : "importName", + loc: specifier.loc, + data: { + importSource, + customMessage, + importName + } + }); + }); + } + }); + } else { + context.report({ + node, + messageId: customMessage ? "pathWithCustomMessage" : "path", + data: { + importSource, + customMessage + } + }); + } } /** @@ -161,75 +199,6 @@ module.exports = { }); } - /** - * Report a restricted path specifically when using the '*' import. - * @param {string} importSource path of the import - * @param {node} node representing the restricted path reference - * @returns {void} - * @private - */ - function reportPathForEverythingImported(importSource, node) { - const importNames = restrictedPathMessages[importSource].importNames; - const customMessage = restrictedPathMessages[importSource] && restrictedPathMessages[importSource].message; - - context.report({ - node, - messageId: customMessage ? "everythingWithCustomMessage" : "everything", - data: { - importSource, - importNames, - customMessage - } - }); - } - - /** - * Check if the given importSource is restricted because '*' is being imported. - * @param {string} importSource path of the import - * @param {Set.} importNames Set of import names that are being imported - * @returns {boolean} whether the path is restricted - * @private - */ - function isRestrictedForEverythingImported(importSource, importNames) { - return Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource) && - restrictedPathMessages[importSource].importNames && - isEverythingImported(importNames); - } - - /** - * Check if the given importNames are restricted given a list of restrictedImportNames. - * @param {Set.} importNames Set of import names that are being imported - * @param {string[]} restrictedImportNames array of import names that are restricted for this import - * @returns {boolean} whether the objectName is restricted - * @private - */ - function isRestrictedObject(importNames, restrictedImportNames) { - return restrictedImportNames.some(restrictedObjectName => ( - importNames.has(restrictedObjectName) - )); - } - - /** - * Check if the given importSource is a restricted path. - * @param {string} importSource path of the import - * @param {Set.} importNames Set of import names that are being imported - * @returns {boolean} whether the variable is a restricted path or not - * @private - */ - function isRestrictedPath(importSource, importNames) { - let isRestricted = false; - - if (Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) { - if (restrictedPathMessages[importSource].importNames) { - isRestricted = isRestrictedObject(importNames, restrictedPathMessages[importSource].importNames); - } else { - isRestricted = true; - } - } - - return isRestricted; - } - /** * Check if the given importSource is restricted by a pattern. * @param {string} importSource path of the import @@ -248,26 +217,39 @@ module.exports = { */ function checkNode(node) { const importSource = node.source.value.trim(); - const importNames = node.specifiers ? node.specifiers.reduce((set, specifier) => { - if (specifier.type === "ImportDefaultSpecifier") { - set.add("default"); - } else if (specifier.type === "ImportNamespaceSpecifier") { - set.add("*"); - } else if (specifier.imported) { - set.add(specifier.imported.name); - } else if (specifier.local) { - set.add(specifier.local.name); - } - return set; - }, new Set()) : new Set(); + const importNames = new Map(); + + if (node.type === "ExportAllDeclaration") { + const starToken = sourceCode.getFirstToken(node, 1); + + importNames.set("*", [{ loc: starToken.loc }]); + } else if (node.specifiers) { + for (const specifier of node.specifiers) { + let name; + const specifierData = { loc: specifier.loc }; + + if (specifier.type === "ImportDefaultSpecifier") { + name = "default"; + } else if (specifier.type === "ImportNamespaceSpecifier") { + name = "*"; + } else if (specifier.imported) { + name = specifier.imported.name; + } else if (specifier.local) { + name = specifier.local.name; + } - if (isRestrictedForEverythingImported(importSource, importNames)) { - reportPathForEverythingImported(importSource, node); + if (name) { + if (importNames.has(name)) { + importNames.get(name).push(specifierData); + } else { + importNames.set(name, [specifierData]); + } + } + } } - if (isRestrictedPath(importSource, importNames)) { - reportPath(node); - } + checkRestrictedPathAndReport(importSource, importNames, node); + if (isRestrictedPattern(importSource)) { reportPathForPatterns(node); } diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-modules.js b/tools/node_modules/eslint/lib/rules/no-restricted-modules.js index ef8748a7d04baf..abd8d5cbe29381 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-modules.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-modules.js @@ -4,13 +4,6 @@ */ "use strict"; -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -const DEFAULT_MESSAGE_TEMPLATE = "'{{moduleName}}' module is restricted from being used."; -const CUSTOM_MESSAGE_TEMPLATE = "'{{moduleName}}' module is restricted from being used. {{customMessage}}"; - //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -72,6 +65,13 @@ module.exports = { additionalItems: false } ] + }, + + messages: { + defaultMessage: "'{{name}}' module is restricted from being used.", + // eslint-disable-next-line eslint-plugin/report-message-format + customMessage: "'{{name}}' module is restricted from being used. {{customMessage}}", + patternMessage: "'{{name}}' module is restricted from being used by a pattern." } }, @@ -106,10 +106,19 @@ module.exports = { * @param {ASTNode} node The node to check. * @returns {boolean} If the node is a string literal. */ - function isString(node) { + function isStringLiteral(node) { return node && node.type === "Literal" && typeof node.value === "string"; } + /** + * Function to check if a node is a static string template literal. + * @param {ASTNode} node The node to check. + * @returns {boolean} If the node is a string template literal. + */ + function isStaticTemplateLiteral(node) { + return node && node.type === "TemplateLiteral" && node.expressions.length === 0; + } + /** * Function to check if a node is a require call. * @param {ASTNode} node The node to check. @@ -119,24 +128,41 @@ module.exports = { return node.callee.type === "Identifier" && node.callee.name === "require"; } + /** + * Extract string from Literal or TemplateLiteral node + * @param {ASTNode} node The node to extract from + * @returns {string|null} Extracted string or null if node doesn't represent a string + */ + function getFirstArgumentString(node) { + if (isStringLiteral(node)) { + return node.value.trim(); + } + + if (isStaticTemplateLiteral(node)) { + return node.quasis[0].value.cooked.trim(); + } + + return null; + } + /** * Report a restricted path. * @param {node} node representing the restricted path reference + * @param {string} name restricted path * @returns {void} * @private */ - function reportPath(node) { - const moduleName = node.arguments[0].value.trim(); - const customMessage = restrictedPathMessages[moduleName]; - const message = customMessage - ? CUSTOM_MESSAGE_TEMPLATE - : DEFAULT_MESSAGE_TEMPLATE; + function reportPath(node, name) { + const customMessage = restrictedPathMessages[name]; + const messageId = customMessage + ? "customMessage" + : "defaultMessage"; context.report({ node, - message, + messageId, data: { - moduleName, + name, customMessage } }); @@ -156,21 +182,25 @@ module.exports = { CallExpression(node) { if (isRequireCall(node)) { - // node has arguments and first argument is string - if (node.arguments.length && isString(node.arguments[0])) { - const moduleName = node.arguments[0].value.trim(); - - // check if argument value is in restricted modules array - if (isRestrictedPath(moduleName)) { - reportPath(node); - } - - if (restrictedPatterns.length > 0 && ig.ignores(moduleName)) { - context.report({ - node, - message: "'{{moduleName}}' module is restricted from being used by a pattern.", - data: { moduleName } - }); + // node has arguments + if (node.arguments.length) { + const name = getFirstArgumentString(node.arguments[0]); + + // if first argument is a string literal or a static string template literal + if (name) { + + // check if argument value is in restricted modules array + if (isRestrictedPath(name)) { + reportPath(node, name); + } + + if (restrictedPatterns.length > 0 && ig.ignores(name)) { + context.report({ + node, + messageId: "patternMessage", + data: { name } + }); + } } } } diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-properties.js b/tools/node_modules/eslint/lib/rules/no-restricted-properties.js index bdab22b19c4edc..7ab83995a3ebbf 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-properties.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-properties.js @@ -61,6 +61,13 @@ module.exports = { ] }, uniqueItems: true + }, + + messages: { + // eslint-disable-next-line eslint-plugin/report-message-format + restrictedObjectProperty: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", + // eslint-disable-next-line eslint-plugin/report-message-format + restrictedProperty: "'{{propertyName}}' is restricted from being used.{{message}}" } }, @@ -114,8 +121,7 @@ module.exports = { context.report({ node, - // eslint-disable-next-line eslint-plugin/report-message-format - message: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", + messageId: "restrictedObjectProperty", data: { objectName, propertyName, @@ -127,8 +133,7 @@ module.exports = { context.report({ node, - // eslint-disable-next-line eslint-plugin/report-message-format - message: "'{{propertyName}}' is restricted from being used.{{message}}", + messageId: "restrictedProperty", data: { propertyName, message diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js index 41aa9fa390a88d..9572603a82485a 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js @@ -39,6 +39,11 @@ module.exports = { }, uniqueItems: true, minItems: 0 + }, + + messages: { + // eslint-disable-next-line eslint-plugin/report-message-format + restrictedSyntax: "{{message}}" } }, @@ -48,14 +53,14 @@ module.exports = { const hasCustomMessage = !isStringFormat && Boolean(selectorOrObject.message); const selector = isStringFormat ? selectorOrObject : selectorOrObject.selector; - const message = hasCustomMessage ? selectorOrObject.message : "Using '{{selector}}' is not allowed."; + const message = hasCustomMessage ? selectorOrObject.message : `Using '${selector}' is not allowed.`; return Object.assign(result, { [selector](node) { context.report({ node, - message, - data: hasCustomMessage ? {} : { selector } + messageId: "restrictedSyntax", + data: { message } }); } }); diff --git a/tools/node_modules/eslint/lib/rules/no-return-assign.js b/tools/node_modules/eslint/lib/rules/no-return-assign.js index ea6a6bb49fcf6d..4b57d42eb9952b 100644 --- a/tools/node_modules/eslint/lib/rules/no-return-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-return-assign.js @@ -35,7 +35,12 @@ module.exports = { { enum: ["except-parens", "always"] } - ] + ], + + messages: { + returnAssignment: "Return statement should not contain assignment.", + arrowAssignment: "Arrow function should not return assignment." + } }, create(context) { @@ -61,12 +66,12 @@ module.exports = { if (parent && parent.type === "ReturnStatement") { context.report({ node: parent, - message: "Return statement should not contain assignment." + messageId: "returnAssignment" }); } else if (parent && parent.type === "ArrowFunctionExpression" && parent.body === currentChild) { context.report({ node: parent, - message: "Arrow function should not return assignment." + messageId: "arrowAssignment" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-return-await.js b/tools/node_modules/eslint/lib/rules/no-return-await.js index 6652b5932dc1b8..d1d89826856dc4 100644 --- a/tools/node_modules/eslint/lib/rules/no-return-await.js +++ b/tools/node_modules/eslint/lib/rules/no-return-await.js @@ -10,8 +10,6 @@ const astUtils = require("./utils/ast-utils"); // Rule Definition //------------------------------------------------------------------------------ -const message = "Redundant use of `await` on a return value."; - module.exports = { meta: { type: "suggestion", @@ -28,7 +26,11 @@ module.exports = { fixable: null, schema: [ - ] + ], + + messages: { + redundantUseOfAwait: "Redundant use of `await` on a return value." + } }, create(context) { @@ -42,7 +44,7 @@ module.exports = { context.report({ node: context.getSourceCode().getFirstToken(node), loc: node.loc, - message + messageId: "redundantUseOfAwait" }); } diff --git a/tools/node_modules/eslint/lib/rules/no-script-url.js b/tools/node_modules/eslint/lib/rules/no-script-url.js index 40e9bfe8b27544..2078fc1dcea122 100644 --- a/tools/node_modules/eslint/lib/rules/no-script-url.js +++ b/tools/node_modules/eslint/lib/rules/no-script-url.js @@ -22,7 +22,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-script-url" }, - schema: [] + schema: [], + + messages: { + unexpectedScriptURL: "Script URL is a form of eval." + } }, create(context) { @@ -34,7 +38,7 @@ module.exports = { const value = node.value.toLowerCase(); if (value.indexOf("javascript:") === 0) { - context.report({ node, message: "Script URL is a form of eval." }); + context.report({ node, messageId: "unexpectedScriptURL" }); } } } diff --git a/tools/node_modules/eslint/lib/rules/no-self-assign.js b/tools/node_modules/eslint/lib/rules/no-self-assign.js index 705d0f409c4128..170e46b05930d1 100644 --- a/tools/node_modules/eslint/lib/rules/no-self-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-self-assign.js @@ -196,7 +196,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + selfAssignment: "'{{name}}' is assigned to itself." + } }, create(context) { @@ -211,7 +215,7 @@ module.exports = { function report(node) { context.report({ node, - message: "'{{name}}' is assigned to itself.", + messageId: "selfAssignment", data: { name: sourceCode.getText(node).replace(SPACES, "") } diff --git a/tools/node_modules/eslint/lib/rules/no-self-compare.js b/tools/node_modules/eslint/lib/rules/no-self-compare.js index 8986240ec5c842..79b6ac7ea0f28d 100644 --- a/tools/node_modules/eslint/lib/rules/no-self-compare.js +++ b/tools/node_modules/eslint/lib/rules/no-self-compare.js @@ -21,7 +21,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-self-compare" }, - schema: [] + schema: [], + + messages: { + comparingToSelf: "Comparing to itself is potentially pointless." + } }, create(context) { @@ -47,7 +51,7 @@ module.exports = { const operators = new Set(["===", "==", "!==", "!=", ">", "<", ">=", "<="]); if (operators.has(node.operator) && hasSameTokens(node.left, node.right)) { - context.report({ node, message: "Comparing to itself is potentially pointless." }); + context.report({ node, messageId: "comparingToSelf" }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-sequences.js b/tools/node_modules/eslint/lib/rules/no-sequences.js index 8046a8711a3e9a..d67635d117549e 100644 --- a/tools/node_modules/eslint/lib/rules/no-sequences.js +++ b/tools/node_modules/eslint/lib/rules/no-sequences.js @@ -26,7 +26,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-sequences" }, - schema: [] + schema: [], + + messages: { + unexpectedCommaExpression: "Unexpected use of comma operator." + } }, create(context) { @@ -107,7 +111,7 @@ module.exports = { const firstCommaToken = sourceCode.getTokenAfter(node.expressions[0], astUtils.isCommaToken); - context.report({ node, loc: firstCommaToken.loc, message: "Unexpected use of comma operator." }); + context.report({ node, loc: firstCommaToken.loc, messageId: "unexpectedCommaExpression" }); } }; diff --git a/tools/node_modules/eslint/lib/rules/no-setter-return.js b/tools/node_modules/eslint/lib/rules/no-setter-return.js index e0948696c347f5..a558640c357d92 100644 --- a/tools/node_modules/eslint/lib/rules/no-setter-return.js +++ b/tools/node_modules/eslint/lib/rules/no-setter-return.js @@ -145,7 +145,7 @@ module.exports = { docs: { description: "disallow returning values from setters", category: "Possible Errors", - recommended: false, + recommended: true, url: "https://eslint.org/docs/rules/no-setter-return" }, diff --git a/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js b/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js index 9030d523b705d2..9647e9a1bcdd9e 100644 --- a/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js +++ b/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js @@ -32,7 +32,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-shadow-restricted-names" }, - schema: [] + schema: [], + + messages: { + shadowingRestrictedName: "Shadowing of global property '{{name}}'." + } }, create(context) { @@ -46,9 +50,9 @@ module.exports = { if (variable.defs.length > 0 && RESTRICTED.has(variable.name) && !safelyShadowsUndefined(variable)) { context.report({ node: variable.defs[0].name, - message: "Shadowing of global property '{{idName}}'.", + messageId: "shadowingRestrictedName", data: { - idName: variable.name + name: variable.name } }); } diff --git a/tools/node_modules/eslint/lib/rules/no-shadow.js b/tools/node_modules/eslint/lib/rules/no-shadow.js index bad6cb5f3094cc..1be8590e47abcb 100644 --- a/tools/node_modules/eslint/lib/rules/no-shadow.js +++ b/tools/node_modules/eslint/lib/rules/no-shadow.js @@ -41,7 +41,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + noShadow: "'{{name}}' is already declared in the upper scope." + } }, create(context) { @@ -163,7 +167,7 @@ module.exports = { ) { context.report({ node: variable.identifiers[0], - message: "'{{name}}' is already declared in the upper scope.", + messageId: "noShadow", data: variable }); } diff --git a/tools/node_modules/eslint/lib/rules/no-spaced-func.js b/tools/node_modules/eslint/lib/rules/no-spaced-func.js index 8535881f435e48..961bc681f7eac5 100644 --- a/tools/node_modules/eslint/lib/rules/no-spaced-func.js +++ b/tools/node_modules/eslint/lib/rules/no-spaced-func.js @@ -26,7 +26,11 @@ module.exports = { replacedBy: ["func-call-spacing"], fixable: "whitespace", - schema: [] + schema: [], + + messages: { + noSpacedFunction: "Unexpected space between function name and paren." + } }, create(context) { @@ -62,7 +66,7 @@ module.exports = { context.report({ node, loc: lastCalleeToken.loc.start, - message: "Unexpected space between function name and paren.", + messageId: "noSpacedFunction", fix(fixer) { return fixer.removeRange([prevToken.range[1], parenToken.range[0]]); } diff --git a/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js b/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js index 985109c36b267d..e8407c3faede2d 100644 --- a/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js +++ b/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-sparse-arrays" }, - schema: [] + schema: [], + + messages: { + unexpectedSparseArray: "Unexpected comma in middle of array." + } }, create(context) { @@ -36,7 +40,7 @@ module.exports = { const emptySpot = node.elements.indexOf(null) > -1; if (emptySpot) { - context.report({ node, message: "Unexpected comma in middle of array." }); + context.report({ node, messageId: "unexpectedSparseArray" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-sync.js b/tools/node_modules/eslint/lib/rules/no-sync.js index 578bac96d3d061..d8111059631734 100644 --- a/tools/node_modules/eslint/lib/rules/no-sync.js +++ b/tools/node_modules/eslint/lib/rules/no-sync.js @@ -33,7 +33,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + noSync: "Unexpected sync method: '{{propertyName}}'." + } }, create(context) { @@ -45,7 +49,7 @@ module.exports = { [selector](node) { context.report({ node, - message: "Unexpected sync method: '{{propertyName}}'.", + messageId: "noSync", data: { propertyName: node.property.name } diff --git a/tools/node_modules/eslint/lib/rules/no-tabs.js b/tools/node_modules/eslint/lib/rules/no-tabs.js index 3fc0b78b6e741c..ca7be261653c02 100644 --- a/tools/node_modules/eslint/lib/rules/no-tabs.js +++ b/tools/node_modules/eslint/lib/rules/no-tabs.js @@ -35,7 +35,11 @@ module.exports = { } }, additionalProperties: false - }] + }], + + messages: { + unexpectedTab: "Unexpected tab character." + } }, create(context) { @@ -64,7 +68,7 @@ module.exports = { column: match.index + match[0].length } }, - message: "Unexpected tab character." + messageId: "unexpectedTab" }); } }); diff --git a/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js b/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js index f7822e961cc1e7..539cd5be5ff9c5 100644 --- a/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js +++ b/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-template-curly-in-string" }, - schema: [] + schema: [], + + messages: { + unexpectedTemplateExpression: "Unexpected template string expression." + } }, create(context) { @@ -30,7 +34,7 @@ module.exports = { if (typeof node.value === "string" && regex.test(node.value)) { context.report({ node, - message: "Unexpected template string expression." + messageId: "unexpectedTemplateExpression" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-ternary.js b/tools/node_modules/eslint/lib/rules/no-ternary.js index 890f2abfa0c59a..b3ced86056614c 100644 --- a/tools/node_modules/eslint/lib/rules/no-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-ternary.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-ternary" }, - schema: [] + schema: [], + + messages: { + noTernaryOperator: "Ternary operator used." + } }, create(context) { @@ -28,7 +32,7 @@ module.exports = { return { ConditionalExpression(node) { - context.report({ node, message: "Ternary operator used." }); + context.report({ node, messageId: "noTernaryOperator" }); } }; diff --git a/tools/node_modules/eslint/lib/rules/no-this-before-super.js b/tools/node_modules/eslint/lib/rules/no-this-before-super.js index 6975ea060bf00d..44288c0c97136e 100644 --- a/tools/node_modules/eslint/lib/rules/no-this-before-super.js +++ b/tools/node_modules/eslint/lib/rules/no-this-before-super.js @@ -45,7 +45,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-this-before-super" }, - schema: [] + schema: [], + + messages: { + noBeforeSuper: "'{{kind}}' is not allowed before 'super()'." + } }, create(context) { @@ -187,7 +191,7 @@ module.exports = { const invalidNode = info.invalidNodes[i]; context.report({ - message: "'{{kind}}' is not allowed before 'super()'.", + messageId: "noBeforeSuper", node: invalidNode, data: { kind: invalidNode.type === "Super" ? "super" : "this" diff --git a/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js b/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js index 3a4124f4c0f7a4..98ae62c896359c 100644 --- a/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js @@ -42,7 +42,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + trailingSpace: "Trailing spaces not allowed." + } }, create(context) { @@ -74,7 +78,7 @@ module.exports = { context.report({ node, loc: location, - message: "Trailing spaces not allowed.", + messageId: "trailingSpace", fix(fixer) { return fixer.removeRange(fixRange); } diff --git a/tools/node_modules/eslint/lib/rules/no-undef-init.js b/tools/node_modules/eslint/lib/rules/no-undef-init.js index 1fdccb867b3c24..5c240fef742b83 100644 --- a/tools/node_modules/eslint/lib/rules/no-undef-init.js +++ b/tools/node_modules/eslint/lib/rules/no-undef-init.js @@ -23,7 +23,11 @@ module.exports = { }, schema: [], - fixable: "code" + fixable: "code", + + messages: { + unnecessaryUndefinedInit: "It's not necessary to initialize '{{name}}' to undefined." + } }, create(context) { @@ -43,7 +47,7 @@ module.exports = { if (init === "undefined" && node.parent.kind !== "const" && !shadowed) { context.report({ node, - message: "It's not necessary to initialize '{{name}}' to undefined.", + messageId: "unnecessaryUndefinedInit", data: { name }, fix(fixer) { if (node.parent.kind === "var") { diff --git a/tools/node_modules/eslint/lib/rules/no-undefined.js b/tools/node_modules/eslint/lib/rules/no-undefined.js index b92f6700637c30..a075d903e21e98 100644 --- a/tools/node_modules/eslint/lib/rules/no-undefined.js +++ b/tools/node_modules/eslint/lib/rules/no-undefined.js @@ -19,7 +19,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-undefined" }, - schema: [] + schema: [], + + messages: { + unexpectedUndefined: "Unexpected use of undefined." + } }, create(context) { @@ -32,7 +36,7 @@ module.exports = { function report(node) { context.report({ node, - message: "Unexpected use of undefined." + messageId: "unexpectedUndefined" }); } diff --git a/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js b/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js index e910e2739a740a..cac594e10047e8 100644 --- a/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js +++ b/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js @@ -49,7 +49,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedUnderscore: "Unexpected dangling '_' in '{{identifier}}'." + } }, create(context) { @@ -134,7 +138,7 @@ module.exports = { if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) { context.report({ node, - message: "Unexpected dangling '_' in '{{identifier}}'.", + messageId: "unexpectedUnderscore", data: { identifier } @@ -156,7 +160,7 @@ module.exports = { !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) { context.report({ node, - message: "Unexpected dangling '_' in '{{identifier}}'.", + messageId: "unexpectedUnderscore", data: { identifier } @@ -183,7 +187,7 @@ module.exports = { !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) { context.report({ node, - message: "Unexpected dangling '_' in '{{identifier}}'.", + messageId: "unexpectedUnderscore", data: { identifier } @@ -201,10 +205,10 @@ module.exports = { const identifier = node.key.name; const isMethod = node.type === "MethodDefinition" || node.type === "Property" && node.method; - if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasTrailingUnderscore(identifier)) { + if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) { context.report({ node, - message: "Unexpected dangling '_' in '{{identifier}}'.", + messageId: "unexpectedUnderscore", data: { identifier } diff --git a/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js b/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js index 3b8e7417d5b586..7031a4dd8b83fc 100644 --- a/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js @@ -167,7 +167,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-unmodified-loop-condition" }, - schema: [] + schema: [], + + messages: { + loopConditionNotModified: "'{{name}}' is not modified in this loop." + } }, create(context) { @@ -184,7 +188,7 @@ module.exports = { context.report({ node, - message: "'{{name}}' is not modified in this loop.", + messageId: "loopConditionNotModified", data: node }); } diff --git a/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js b/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js index 893baa34f74917..d4438e2fe08fbe 100644 --- a/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js @@ -47,7 +47,12 @@ module.exports = { } ], - fixable: "code" + fixable: "code", + + messages: { + unnecessaryConditionalExpression: "Unnecessary use of boolean literals in conditional expression.", + unnecessaryConditionalAssignment: "Unnecessary use of conditional expression for default assignment." + } }, create(context) { @@ -118,7 +123,7 @@ module.exports = { context.report({ node, loc: node.consequent.loc.start, - message: "Unnecessary use of boolean literals in conditional expression.", + messageId: "unnecessaryConditionalExpression", fix(fixer) { if (node.consequent.value === node.alternate.value) { @@ -140,7 +145,7 @@ module.exports = { context.report({ node, loc: node.consequent.loc.start, - message: "Unnecessary use of conditional expression for default assignment.", + messageId: "unnecessaryConditionalAssignment", fix: fixer => { const shouldParenthesizeAlternate = ( astUtils.getPrecedence(node.alternate) < OR_PRECEDENCE && diff --git a/tools/node_modules/eslint/lib/rules/no-unreachable.js b/tools/node_modules/eslint/lib/rules/no-unreachable.js index 91c4ca7150903f..415631a6f7d726 100644 --- a/tools/node_modules/eslint/lib/rules/no-unreachable.js +++ b/tools/node_modules/eslint/lib/rules/no-unreachable.js @@ -110,7 +110,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-unreachable" }, - schema: [] + schema: [], + + messages: { + unreachableCode: "Unreachable code." + } }, create(context) { @@ -154,7 +158,7 @@ module.exports = { */ if (!range.isEmpty) { context.report({ - message: "Unreachable code.", + messageId: "unreachableCode", loc: range.location, node: range.startNode }); diff --git a/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js b/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js index a41dff9c80372f..11bf06e872a813 100644 --- a/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js +++ b/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js @@ -29,7 +29,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-unsafe-finally" }, - schema: [] + schema: [], + + messages: { + unsafeUsage: "Unsafe usage of {{nodeType}}." + } }, create(context) { @@ -86,7 +90,7 @@ module.exports = { function check(node) { if (isInFinallyBlock(node, node.label)) { context.report({ - message: "Unsafe usage of {{nodeType}}.", + messageId: "unsafeUsage", data: { nodeType: node.type }, diff --git a/tools/node_modules/eslint/lib/rules/no-unused-expressions.js b/tools/node_modules/eslint/lib/rules/no-unused-expressions.js index fd0440256be016..26a25b7584bc80 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-expressions.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-expressions.js @@ -38,7 +38,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unusedExpression: "Expected an assignment or function call and instead saw an expression." + } }, create(context) { @@ -127,7 +131,7 @@ module.exports = { return { ExpressionStatement(node) { if (!isValidExpression(node.expression) && !isDirective(node, context.getAncestors())) { - context.report({ node, message: "Expected an assignment or function call and instead saw an expression." }); + context.report({ node, messageId: "unusedExpression" }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-unused-vars.js b/tools/node_modules/eslint/lib/rules/no-unused-vars.js index 63e6e048ef1e46..18c48bf0d7810c 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-vars.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-vars.js @@ -11,6 +11,18 @@ const astUtils = require("./utils/ast-utils"); +//------------------------------------------------------------------------------ +// Typedefs +//------------------------------------------------------------------------------ + +/** + * Bag of data used for formatting the `unusedVar` lint message. + * @typedef {Object} UnusedVarMessageData + * @property {string} varName The name of the unused var. + * @property {'defined'|'assigned a value'} action Description of the vars state. + * @property {string} additional Any additional info to be appended at the end. + */ + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -60,7 +72,11 @@ module.exports = { } ] } - ] + ], + + messages: { + unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}." + } }, create(context) { @@ -101,12 +117,12 @@ module.exports = { } /** - * Generate the warning message about the variable being - * defined and unused, including the ignore pattern if configured. + * Generates the message data about the variable being defined and unused, + * including the ignore pattern if configured. * @param {Variable} unusedVar eslint-scope variable object. - * @returns {string} The warning message to be used with this unused variable. + * @returns {UnusedVarMessageData} The message data to be used with this unused variable. */ - function getDefinedMessage(unusedVar) { + function getDefinedMessageData(unusedVar) { const defType = unusedVar.defs && unusedVar.defs[0] && unusedVar.defs[0].type; let type; let pattern; @@ -122,20 +138,29 @@ module.exports = { pattern = config.varsIgnorePattern.toString(); } - const additional = type ? ` Allowed unused ${type} must match ${pattern}.` : ""; + const additional = type ? `. Allowed unused ${type} must match ${pattern}` : ""; - return `'{{name}}' is defined but never used.${additional}`; + return { + varName: unusedVar.name, + action: "defined", + additional + }; } /** * Generate the warning message about the variable being * assigned and unused, including the ignore pattern if configured. - * @returns {string} The warning message to be used with this unused variable. + * @param {Variable} unusedVar eslint-scope variable object. + * @returns {UnusedVarMessageData} The message data to be used with this unused variable. */ - function getAssignedMessage() { - const additional = config.varsIgnorePattern ? ` Allowed unused vars must match ${config.varsIgnorePattern.toString()}.` : ""; - - return `'{{name}}' is assigned a value but never used.${additional}`; + function getAssignedMessageData(unusedVar) { + const additional = config.varsIgnorePattern ? `. Allowed unused vars must match ${config.varsIgnorePattern.toString()}` : ""; + + return { + varName: unusedVar.name, + action: "assigned a value", + additional + }; } //-------------------------------------------------------------------------- @@ -282,7 +307,7 @@ module.exports = { function getRhsNode(ref, prevRhsNode) { const id = ref.identifier; const parent = id.parent; - const granpa = parent.parent; + const grandparent = parent.parent; const refScope = ref.from.variableScope; const varScope = ref.resolved.scope.variableScope; const canBeUsedLater = refScope !== varScope || astUtils.isInLoop(id); @@ -296,7 +321,7 @@ module.exports = { } if (parent.type === "AssignmentExpression" && - granpa.type === "ExpressionStatement" && + grandparent.type === "ExpressionStatement" && id === parent.left && !canBeUsedLater ) { @@ -342,7 +367,7 @@ module.exports = { /* * If it encountered statements, this is a complex pattern. - * Since analyzeing complex patterns is hard, this returns `true` to avoid false positive. + * Since analyzing complex patterns is hard, this returns `true` to avoid false positive. */ return true; } @@ -389,7 +414,7 @@ module.exports = { function isReadForItself(ref, rhsNode) { const id = ref.identifier; const parent = id.parent; - const granpa = parent.parent; + const grandparent = parent.parent; return ref.isRead() && ( @@ -397,12 +422,12 @@ module.exports = { (// in RHS of an assignment for itself. e.g. `a = a + 1` (( parent.type === "AssignmentExpression" && - granpa.type === "ExpressionStatement" && + grandparent.type === "ExpressionStatement" && parent.left === id ) || ( parent.type === "UpdateExpression" && - granpa.type === "ExpressionStatement" + grandparent.type === "ExpressionStatement" ) || rhsNode && isInside(id, rhsNode) && !isInsideOfStorableFunction(id, rhsNode))) @@ -595,10 +620,10 @@ module.exports = { if (unusedVar.defs.length > 0) { context.report({ node: unusedVar.identifiers[0], - message: unusedVar.references.some(ref => ref.isWrite()) - ? getAssignedMessage() - : getDefinedMessage(unusedVar), - data: unusedVar + messageId: "unusedVar", + data: unusedVar.references.some(ref => ref.isWrite()) + ? getAssignedMessageData(unusedVar) + : getDefinedMessageData(unusedVar) }); // If there are no regular declaration, report the first `/*globals*/` comment directive. @@ -608,8 +633,8 @@ module.exports = { context.report({ node: programNode, loc: astUtils.getNameLocationInGlobalDirectiveComment(sourceCode, directiveComment, unusedVar.name), - message: getDefinedMessage(unusedVar), - data: unusedVar + messageId: "unusedVar", + data: getDefinedMessageData(unusedVar) }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-use-before-define.js b/tools/node_modules/eslint/lib/rules/no-use-before-define.js index ed3540532f9095..c7300567ede0b7 100644 --- a/tools/node_modules/eslint/lib/rules/no-use-before-define.js +++ b/tools/node_modules/eslint/lib/rules/no-use-before-define.js @@ -157,7 +157,11 @@ module.exports = { } ] } - ] + ], + + messages: { + usedBeforeDefined: "'{{name}}' was used before it was defined." + } }, create(context) { @@ -212,7 +216,7 @@ module.exports = { // Reports. context.report({ node: reference.identifier, - message: "'{{name}}' was used before it was defined.", + messageId: "usedBeforeDefined", data: reference.identifier }); }); diff --git a/tools/node_modules/eslint/lib/rules/no-useless-backreference.js b/tools/node_modules/eslint/lib/rules/no-useless-backreference.js new file mode 100644 index 00000000000000..8a6fbe14daafe6 --- /dev/null +++ b/tools/node_modules/eslint/lib/rules/no-useless-backreference.js @@ -0,0 +1,193 @@ +/** + * @fileoverview Rule to disallow useless backreferences in regular expressions + * @author Milos Djermanovic + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("eslint-utils"); +const { RegExpParser, visitRegExpAST } = require("regexpp"); +const lodash = require("lodash"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +const parser = new RegExpParser(); + +/** + * Finds the path from the given `regexpp` AST node to the root node. + * @param {regexpp.Node} node Node. + * @returns {regexpp.Node[]} Array that starts with the given node and ends with the root node. + */ +function getPathToRoot(node) { + const path = []; + let current = node; + + do { + path.push(current); + current = current.parent; + } while (current); + + return path; +} + +/** + * Determines whether the given `regexpp` AST node is a lookaround node. + * @param {regexpp.Node} node Node. + * @returns {boolean} `true` if it is a lookaround node. + */ +function isLookaround(node) { + return node.type === "Assertion" && + (node.kind === "lookahead" || node.kind === "lookbehind"); +} + +/** + * Determines whether the given `regexpp` AST node is a negative lookaround node. + * @param {regexpp.Node} node Node. + * @returns {boolean} `true` if it is a negative lookaround node. + */ +function isNegativeLookaround(node) { + return isLookaround(node) && node.negate; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: "problem", + + docs: { + description: "disallow useless backreferences in regular expressions", + category: "Possible Errors", + recommended: false, + url: "https://eslint.org/docs/rules/no-useless-backreference" + }, + + schema: [], + + messages: { + nested: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' from within that group.", + forward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which appears later in the pattern.", + backward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which appears before in the same lookbehind.", + disjunctive: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which is in another alternative.", + intoNegativeLookaround: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which is in a negative lookaround." + } + }, + + create(context) { + + /** + * Checks and reports useless backreferences in the given regular expression. + * @param {ASTNode} node Node that represents regular expression. A regex literal or RegExp constructor call. + * @param {string} pattern Regular expression pattern. + * @param {string} flags Regular expression flags. + * @returns {void} + */ + function checkRegex(node, pattern, flags) { + let regExpAST; + + try { + regExpAST = parser.parsePattern(pattern, 0, pattern.length, flags.includes("u")); + } catch (e) { + + // Ignore regular expressions with syntax errors + return; + } + + visitRegExpAST(regExpAST, { + onBackreferenceEnter(bref) { + const group = bref.resolved, + brefPath = getPathToRoot(bref), + groupPath = getPathToRoot(group); + let messageId = null; + + if (brefPath.includes(group)) { + + // group is bref's ancestor => bref is nested ('nested reference') => group hasn't matched yet when bref starts to match. + messageId = "nested"; + } else { + + // Start from the root to find the lowest common ancestor. + let i = brefPath.length - 1, + j = groupPath.length - 1; + + do { + i--; + j--; + } while (brefPath[i] === groupPath[j]); + + const indexOfLowestCommonAncestor = j + 1, + groupCut = groupPath.slice(0, indexOfLowestCommonAncestor), + commonPath = groupPath.slice(indexOfLowestCommonAncestor), + lowestCommonLookaround = commonPath.find(isLookaround), + isMatchingBackward = lowestCommonLookaround && lowestCommonLookaround.kind === "lookbehind"; + + if (!isMatchingBackward && bref.end <= group.start) { + + // bref is left, group is right ('forward reference') => group hasn't matched yet when bref starts to match. + messageId = "forward"; + } else if (isMatchingBackward && group.end <= bref.start) { + + // the opposite of the previous when the regex is matching backward in a lookbehind context. + messageId = "backward"; + } else if (lodash.last(groupCut).type === "Alternative") { + + // group's and bref's ancestor nodes below the lowest common ancestor are sibling alternatives => they're disjunctive. + messageId = "disjunctive"; + } else if (groupCut.some(isNegativeLookaround)) { + + // group is in a negative lookaround which isn't bref's ancestor => group has already failed when bref starts to match. + messageId = "intoNegativeLookaround"; + } + } + + if (messageId) { + context.report({ + node, + messageId, + data: { + bref: bref.raw, + group: group.raw + } + }); + } + } + }); + } + + return { + "Literal[regex]"(node) { + const { pattern, flags } = node.regex; + + checkRegex(node, pattern, flags); + }, + Program() { + const scope = context.getScope(), + tracker = new ReferenceTracker(scope), + traceMap = { + RegExp: { + [CALL]: true, + [CONSTRUCT]: true + } + }; + + for (const { node } of tracker.iterateGlobalReferences(traceMap)) { + const [patternNode, flagsNode] = node.arguments, + pattern = getStringIfConstant(patternNode, scope), + flags = getStringIfConstant(flagsNode, scope); + + if (typeof pattern === "string") { + checkRegex(node, pattern, flags || ""); + } + } + } + }; + } +}; diff --git a/tools/node_modules/eslint/lib/rules/no-useless-call.js b/tools/node_modules/eslint/lib/rules/no-useless-call.js index 11cf524d124211..afc729d5de0d9b 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-call.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-call.js @@ -58,7 +58,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-useless-call" }, - schema: [] + schema: [], + + messages: { + unnecessaryCall: "Unnecessary '.{{name}}()'." + } }, create(context) { @@ -75,7 +79,7 @@ module.exports = { const thisArg = node.arguments[0]; if (isValidThisArg(expectedThis, thisArg, sourceCode)) { - context.report({ node, message: "unnecessary '.{{name}}()'.", data: { name: node.callee.property.name } }); + context.report({ node, messageId: "unnecessaryCall", data: { name: node.callee.property.name } }); } } }; diff --git a/tools/node_modules/eslint/lib/rules/no-useless-catch.js b/tools/node_modules/eslint/lib/rules/no-useless-catch.js index 37bf453aecd932..f303c272948489 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-catch.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-catch.js @@ -20,7 +20,12 @@ module.exports = { url: "https://eslint.org/docs/rules/no-useless-catch" }, - schema: [] + schema: [], + + messages: { + unnecessaryCatchClause: "Unnecessary catch clause.", + unnecessaryCatch: "Unnecessary try/catch wrapper." + } }, create(context) { @@ -37,12 +42,12 @@ module.exports = { if (node.parent.finalizer) { context.report({ node, - message: "Unnecessary catch clause." + messageId: "unnecessaryCatchClause" }); } else { context.report({ node: node.parent, - message: "Unnecessary try/catch wrapper." + messageId: "unnecessaryCatch" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js index b5e53174e42be7..e0505a318efaae 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js @@ -15,8 +15,6 @@ const astUtils = require("./utils/ast-utils"); // Rule Definition //------------------------------------------------------------------------------ -const MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{property}}] found."; - module.exports = { meta: { type: "suggestion", @@ -38,7 +36,11 @@ module.exports = { }, additionalProperties: false }], - fixable: "code" + fixable: "code", + + messages: { + unnecessarilyComputedProperty: "Unnecessarily computed property [{{property}}] found." + } }, create(context) { const sourceCode = context.getSourceCode(); @@ -68,17 +70,14 @@ module.exports = { if (key.type === "Literal" && (nodeType === "string" || nodeType === "number") && key.value !== allowedKey) { context.report({ node, - message: MESSAGE_UNNECESSARY_COMPUTED, + messageId: "unnecessarilyComputedProperty", data: { property: sourceCode.getText(key) }, fix(fixer) { - const leftSquareBracket = sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken); - const rightSquareBracket = sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken); - const tokensBetween = sourceCode.getTokensBetween(leftSquareBracket, rightSquareBracket, 1); - - if (tokensBetween.slice(0, -1).some((token, index) => - sourceCode.getText().slice(token.range[1], tokensBetween[index + 1].range[0]).trim())) { + const leftSquareBracket = sourceCode.getTokenBefore(key, astUtils.isOpeningBracketToken); + const rightSquareBracket = sourceCode.getTokenAfter(key, astUtils.isClosingBracketToken); - // If there are comments between the brackets and the property name, don't do a fix. + // If there are comments between the brackets and the property name, don't do a fix. + if (sourceCode.commentsExistBetween(leftSquareBracket, rightSquareBracket)) { return null; } diff --git a/tools/node_modules/eslint/lib/rules/no-useless-concat.js b/tools/node_modules/eslint/lib/rules/no-useless-concat.js index cdaca273eb003f..aa46742abdd5ca 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-concat.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-concat.js @@ -1,5 +1,5 @@ /** - * @fileoverview disallow unncessary concatenation of template strings + * @fileoverview disallow unnecessary concatenation of template strings * @author Henry Zhu */ "use strict"; @@ -75,7 +75,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-useless-concat" }, - schema: [] + schema: [], + + messages: { + unexpectedConcat: "Unexpected string concatenation of literals." + } }, create(context) { @@ -102,7 +106,7 @@ module.exports = { context.report({ node, loc: operatorToken.loc.start, - message: "Unexpected string concatenation of literals." + messageId: "unexpectedConcat" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js index 7cf033805f99d9..4c34aeda715937 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js @@ -115,7 +115,7 @@ function isPassingThrough(ctorParams, superArgs) { * Checks whether the constructor body is a redundant super call. * @param {Array} body constructor body content. * @param {Array} ctorParams The params to check against super call. - * @returns {boolean} true if the construtor body is redundant + * @returns {boolean} true if the constructor body is redundant */ function isRedundantSuperCall(body, ctorParams) { return ( @@ -143,7 +143,11 @@ module.exports = { url: "https://eslint.org/docs/rules/no-useless-constructor" }, - schema: [] + schema: [], + + messages: { + noUselessConstructor: "Useless constructor." + } }, create(context) { @@ -165,7 +169,7 @@ module.exports = { if (superClass ? isRedundantSuperCall(body, ctorParams) : (body.length === 0)) { context.report({ node, - message: "Useless constructor." + messageId: "noUselessConstructor" }); } } diff --git a/tools/node_modules/eslint/lib/rules/no-useless-rename.js b/tools/node_modules/eslint/lib/rules/no-useless-rename.js index eb570a3ef5c1d3..fa88f37f50b79c 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-rename.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-rename.js @@ -32,7 +32,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unnecessarilyRenamed: "{{type}} {{name}} unnecessarily renamed." + } }, create(context) { @@ -59,7 +63,7 @@ module.exports = { return context.report({ node, - message: "{{type}} {{name}} unnecessarily renamed.", + messageId: "unnecessarilyRenamed", data: { name, type diff --git a/tools/node_modules/eslint/lib/rules/no-useless-return.js b/tools/node_modules/eslint/lib/rules/no-useless-return.js index 942d4eede9964e..111cb21015fb81 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-return.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-return.js @@ -32,7 +32,7 @@ function remove(array, element) { /** * Checks whether it can remove the given return statement or not. * @param {ASTNode} node The return statement node to check. - * @returns {boolean} `true` if the node is removeable. + * @returns {boolean} `true` if the node is removable. */ function isRemovable(node) { return astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type); @@ -73,7 +73,11 @@ module.exports = { }, fixable: "code", - schema: [] + schema: [], + + messages: { + unnecessaryReturn: "Unnecessary return statement." + } }, create(context) { @@ -208,7 +212,7 @@ module.exports = { context.report({ node, loc: node.loc, - message: "Unnecessary return statement.", + messageId: "unnecessaryReturn", fix(fixer) { if (isRemovable(node) && !sourceCode.getCommentsInside(node).length) { diff --git a/tools/node_modules/eslint/lib/rules/no-var.js b/tools/node_modules/eslint/lib/rules/no-var.js index 74203f8bf3bebf..f2cb96b1f708e9 100644 --- a/tools/node_modules/eslint/lib/rules/no-var.js +++ b/tools/node_modules/eslint/lib/rules/no-var.js @@ -191,7 +191,11 @@ module.exports = { }, schema: [], - fixable: "code" + fixable: "code", + + messages: { + unexpectedVar: "Unexpected var, use let or const instead." + } }, create(context) { @@ -307,7 +311,7 @@ module.exports = { function report(node) { context.report({ node, - message: "Unexpected var, use let or const instead.", + messageId: "unexpectedVar", fix(fixer) { const varToken = sourceCode.getFirstToken(node, { filter: t => t.value === "var" }); diff --git a/tools/node_modules/eslint/lib/rules/no-void.js b/tools/node_modules/eslint/lib/rules/no-void.js index d2b5d2f9631dff..99c83785552ab8 100644 --- a/tools/node_modules/eslint/lib/rules/no-void.js +++ b/tools/node_modules/eslint/lib/rules/no-void.js @@ -19,22 +19,46 @@ module.exports = { url: "https://eslint.org/docs/rules/no-void" }, - schema: [] + messages: { + noVoid: "Expected 'undefined' and instead saw 'void'." + }, + + schema: [ + { + type: "object", + properties: { + allowAsStatement: { + type: "boolean", + default: false + } + }, + additionalProperties: false + } + ] }, create(context) { + const allowAsStatement = + context.options[0] && context.options[0].allowAsStatement; //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - UnaryExpression(node) { - if (node.operator === "void") { - context.report({ node, message: "Expected 'undefined' and instead saw 'void'." }); + 'UnaryExpression[operator="void"]'(node) { + if ( + allowAsStatement && + node.parent && + node.parent.type === "ExpressionStatement" + ) { + return; } + context.report({ + node, + messageId: "noVoid" + }); } }; - } }; diff --git a/tools/node_modules/eslint/lib/rules/no-warning-comments.js b/tools/node_modules/eslint/lib/rules/no-warning-comments.js index a400c446767ff7..d70bd5dd5c4002 100644 --- a/tools/node_modules/eslint/lib/rules/no-warning-comments.js +++ b/tools/node_modules/eslint/lib/rules/no-warning-comments.js @@ -39,7 +39,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedComment: "Unexpected '{{matchedTerm}}' comment." + } }, create(context) { @@ -140,7 +144,7 @@ module.exports = { matches.forEach(matchedTerm => { context.report({ node, - message: "Unexpected '{{matchedTerm}}' comment.", + messageId: "unexpectedComment", data: { matchedTerm } diff --git a/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js b/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js index 9541401a3176b7..ccd0b091b744e3 100644 --- a/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js +++ b/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js @@ -26,7 +26,11 @@ module.exports = { }, fixable: "whitespace", - schema: [] + schema: [], + + messages: { + unexpectedWhitespace: "Unexpected whitespace before property {{propName}}." + } }, create(context) { @@ -49,7 +53,7 @@ module.exports = { context.report({ node, - message: "Unexpected whitespace before property {{propName}}.", + messageId: "unexpectedWhitespace", data: { propName: sourceCode.getText(node.property) }, diff --git a/tools/node_modules/eslint/lib/rules/no-with.js b/tools/node_modules/eslint/lib/rules/no-with.js index 5763661584c061..d3e52e02f3d15a 100644 --- a/tools/node_modules/eslint/lib/rules/no-with.js +++ b/tools/node_modules/eslint/lib/rules/no-with.js @@ -20,14 +20,18 @@ module.exports = { url: "https://eslint.org/docs/rules/no-with" }, - schema: [] + schema: [], + + messages: { + unexpectedWith: "Unexpected use of 'with' statement." + } }, create(context) { return { WithStatement(node) { - context.report({ node, message: "Unexpected use of 'with' statement." }); + context.report({ node, messageId: "unexpectedWith" }); } }; diff --git a/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js b/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js index 01763cea92f381..34e6eeac39de50 100644 --- a/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js +++ b/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js @@ -40,7 +40,12 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + expectNoLinebreak: "Expected no linebreak before this statement.", + expectLinebreak: "Expected a linebreak before this statement." + } }, create(context) { @@ -79,13 +84,13 @@ module.exports = { if (tokenBefore.loc.end.line === node.loc.start.line && option === "below") { context.report({ node, - message: "Expected a linebreak before this statement.", + messageId: "expectLinebreak", fix: fixer => fixer.insertTextBefore(node, "\n") }); } else if (tokenBefore.loc.end.line !== node.loc.start.line && option === "beside") { context.report({ node, - message: "Expected no linebreak before this statement.", + messageId: "expectNoLinebreak", fix(fixer) { if (sourceCode.getText().slice(tokenBefore.range[1], node.range[0]).trim()) { return null; diff --git a/tools/node_modules/eslint/lib/rules/object-curly-newline.js b/tools/node_modules/eslint/lib/rules/object-curly-newline.js index e870a69a954180..b48b2526a0b2bd 100644 --- a/tools/node_modules/eslint/lib/rules/object-curly-newline.js +++ b/tools/node_modules/eslint/lib/rules/object-curly-newline.js @@ -159,7 +159,14 @@ module.exports = { } ] } - ] + ], + + messages: { + unexpectedLinebreakBeforeClosingBrace: "Unexpected line break before this closing brace.", + unexpectedLinebreakAfterOpeningBrace: "Unexpected line break after this opening brace.", + expectedLinebreakBeforeClosingBrace: "Expected a line break before this closing brace.", + expectedLinebreakAfterOpeningBrace: "Expected a line break after this opening brace." + } }, create(context) { @@ -215,7 +222,7 @@ module.exports = { if (needsLineBreaks) { if (astUtils.isTokenOnSameLine(openBrace, first)) { context.report({ - message: "Expected a line break after this opening brace.", + messageId: "expectedLinebreakAfterOpeningBrace", node, loc: openBrace.loc.start, fix(fixer) { @@ -229,7 +236,7 @@ module.exports = { } if (astUtils.isTokenOnSameLine(last, closeBrace)) { context.report({ - message: "Expected a line break before this closing brace.", + messageId: "expectedLinebreakBeforeClosingBrace", node, loc: closeBrace.loc.start, fix(fixer) { @@ -251,7 +258,7 @@ module.exports = { (consistent && hasLineBreakBetweenOpenBraceAndFirst && !hasLineBreakBetweenCloseBraceAndLast) ) { context.report({ - message: "Unexpected line break after this opening brace.", + messageId: "unexpectedLinebreakAfterOpeningBrace", node, loc: openBrace.loc.start, fix(fixer) { @@ -271,7 +278,7 @@ module.exports = { (consistent && !hasLineBreakBetweenOpenBraceAndFirst && hasLineBreakBetweenCloseBraceAndLast) ) { context.report({ - message: "Unexpected line break before this closing brace.", + messageId: "unexpectedLinebreakBeforeClosingBrace", node, loc: closeBrace.loc.start, fix(fixer) { diff --git a/tools/node_modules/eslint/lib/rules/object-curly-spacing.js b/tools/node_modules/eslint/lib/rules/object-curly-spacing.js index 117a7a35426103..c0044f5033c005 100644 --- a/tools/node_modules/eslint/lib/rules/object-curly-spacing.js +++ b/tools/node_modules/eslint/lib/rules/object-curly-spacing.js @@ -39,7 +39,14 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + requireSpaceBefore: "A space is required before '{{token}}'.", + requireSpaceAfter: "A space is required after '{{token}}'.", + unexpectedSpaceBefore: "There should be no space before '{{token}}'.", + unexpectedSpaceAfter: "There should be no space after '{{token}}'." + } }, create(context) { @@ -79,7 +86,7 @@ module.exports = { context.report({ node, loc: { start: token.loc.end, end: nextToken.loc.start }, - message: "There should be no space after '{{token}}'.", + messageId: "unexpectedSpaceAfter", data: { token: token.value }, @@ -101,7 +108,7 @@ module.exports = { context.report({ node, loc: { start: previousToken.loc.end, end: token.loc.start }, - message: "There should be no space before '{{token}}'.", + messageId: "unexpectedSpaceBefore", data: { token: token.value }, @@ -121,7 +128,7 @@ module.exports = { context.report({ node, loc: token.loc, - message: "A space is required after '{{token}}'.", + messageId: "requireSpaceAfter", data: { token: token.value }, @@ -141,7 +148,7 @@ module.exports = { context.report({ node, loc: token.loc, - message: "A space is required before '{{token}}'.", + messageId: "requireSpaceBefore", data: { token: token.value }, diff --git a/tools/node_modules/eslint/lib/rules/object-property-newline.js b/tools/node_modules/eslint/lib/rules/object-property-newline.js index bf777b5ff65ba2..074bc775ae35a3 100644 --- a/tools/node_modules/eslint/lib/rules/object-property-newline.js +++ b/tools/node_modules/eslint/lib/rules/object-property-newline.js @@ -37,16 +37,21 @@ module.exports = { } ], - fixable: "whitespace" + fixable: "whitespace", + + messages: { + propertiesOnNewlineAll: "Object properties must go on a new line if they aren't all on the same line.", + propertiesOnNewline: "Object properties must go on a new line." + } }, create(context) { const allowSameLine = context.options[0] && ( (context.options[0].allowAllPropertiesOnSameLine || context.options[0].allowMultiplePropertiesPerLine /* Deprecated */) ); - const 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."; + const messageId = allowSameLine + ? "propertiesOnNewlineAll" + : "propertiesOnNewline"; const sourceCode = context.getSourceCode(); @@ -73,7 +78,7 @@ module.exports = { context.report({ node, loc: firstTokenOfCurrentProperty.loc.start, - message: errorMessage, + messageId, fix(fixer) { const comma = sourceCode.getTokenBefore(firstTokenOfCurrentProperty); const rangeAfterComma = [comma.range[1], firstTokenOfCurrentProperty.range[0]]; diff --git a/tools/node_modules/eslint/lib/rules/object-shorthand.js b/tools/node_modules/eslint/lib/rules/object-shorthand.js index d4afd09c5a52c4..3999ff8b99fb29 100644 --- a/tools/node_modules/eslint/lib/rules/object-shorthand.js +++ b/tools/node_modules/eslint/lib/rules/object-shorthand.js @@ -92,6 +92,16 @@ module.exports = { maxItems: 2 } ] + }, + + messages: { + expectedAllPropertiesShorthanded: "Expected shorthand for all properties.", + expectedLiteralMethodLongform: "Expected longform method syntax for string literal keys.", + expectedPropertyShorthand: "Expected property shorthand.", + expectedPropertyLongform: "Expected longform property syntax.", + expectedMethodShorthand: "Expected method shorthand.", + expectedMethodLongform: "Expected longform method syntax.", + unexpectedMix: "Unexpected mix of shorthand and non-shorthand properties." } }, @@ -211,7 +221,7 @@ module.exports = { // We have at least 1 shorthand property if (shorthandProperties.length > 0) { - context.report({ node, message: "Unexpected mix of shorthand and non-shorthand properties." }); + context.report({ node, messageId: "unexpectedMix" }); } else if (checkRedundancy) { /* @@ -221,7 +231,7 @@ module.exports = { const canAlwaysUseShorthand = properties.every(isRedundant); if (canAlwaysUseShorthand) { - context.report({ node, message: "Expected shorthand for all properties." }); + context.report({ node, messageId: "expectedAllPropertiesShorthanded" }); } } } @@ -430,12 +440,12 @@ module.exports = { // Checks for property/method shorthand. if (isConciseProperty) { if (node.method && (APPLY_NEVER || AVOID_QUOTES && isStringLiteral(node.key))) { - const message = APPLY_NEVER ? "Expected longform method syntax." : "Expected longform method syntax for string literal keys."; + const messageId = APPLY_NEVER ? "expectedMethodLongform" : "expectedLiteralMethodLongform"; // { x() {} } should be written as { x: function() {} } context.report({ node, - message, + messageId, fix: fixer => makeFunctionLongform(fixer, node) }); } else if (APPLY_NEVER) { @@ -443,7 +453,7 @@ module.exports = { // { x } should be written as { x: x } context.report({ node, - message: "Expected longform property syntax.", + messageId: "expectedPropertyLongform", fix: fixer => fixer.insertTextAfter(node.key, `: ${node.key.name}`) }); } @@ -464,7 +474,7 @@ module.exports = { ) { context.report({ node, - message: "Expected method shorthand.", + messageId: "expectedMethodShorthand", fix: fixer => makeFunctionShorthand(fixer, node) }); } @@ -473,7 +483,7 @@ module.exports = { // {x: x} should be written as {x} context.report({ node, - message: "Expected property shorthand.", + messageId: "expectedPropertyShorthand", fix(fixer) { return fixer.replaceText(node, node.value.name); } @@ -486,7 +496,7 @@ module.exports = { // {"x": x} should be written as {x} context.report({ node, - message: "Expected property shorthand.", + messageId: "expectedPropertyShorthand", fix(fixer) { return fixer.replaceText(node, node.value.name); } diff --git a/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js b/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js index b64656eefed0a9..30ca2cf49834fe 100644 --- a/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js +++ b/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js @@ -25,12 +25,15 @@ module.exports = { } ], - fixable: "whitespace" + fixable: "whitespace", + + messages: { + expectVarOnNewline: "Expected variable declaration to be on a new line." + } }, create(context) { - const ERROR_MESSAGE = "Expected variable declaration to be on a new line."; const always = context.options[0] === "always"; //-------------------------------------------------------------------------- @@ -67,7 +70,7 @@ module.exports = { if (always || prev.init || current.init) { context.report({ node, - message: ERROR_MESSAGE, + messageId: "expectVarOnNewline", loc: current.loc.start, fix: fixer => fixer.insertTextBefore(current, "\n") }); diff --git a/tools/node_modules/eslint/lib/rules/one-var.js b/tools/node_modules/eslint/lib/rules/one-var.js index e79461ce46c5be..c31a0d2b13c187 100644 --- a/tools/node_modules/eslint/lib/rules/one-var.js +++ b/tools/node_modules/eslint/lib/rules/one-var.js @@ -60,7 +60,17 @@ module.exports = { } ] } - ] + ], + + messages: { + combineUninitialized: "Combine this with the previous '{{type}}' statement with uninitialized variables.", + combineInitialized: "Combine this with the previous '{{type}}' statement with initialized variables.", + splitUninitialized: "Split uninitialized '{{type}}' declarations into multiple statements.", + splitInitialized: "Split initialized '{{type}}' declarations into multiple statements.", + splitRequires: "Split requires to be separated into a single block.", + combine: "Combine this with the previous '{{type}}' statement.", + split: "Split '{{type}}' declarations into multiple statements." + } }, create(context) { @@ -361,7 +371,7 @@ module.exports = { if (options.separateRequires && mixedRequires) { context.report({ node, - message: "Split requires to be separated into a single block." + messageId: "splitRequires" }); } } @@ -384,7 +394,7 @@ module.exports = { if (options[type].initialized === MODE_CONSECUTIVE && options[type].uninitialized === MODE_CONSECUTIVE) { context.report({ node, - message: "Combine this with the previous '{{type}}' statement.", + messageId: "combine", data: { type }, @@ -393,7 +403,7 @@ module.exports = { } else if (options[type].initialized === MODE_CONSECUTIVE && declarationCounts.initialized > 0 && previousDeclCounts.initialized > 0) { context.report({ node, - message: "Combine this with the previous '{{type}}' statement with initialized variables.", + messageId: "combineInitialized", data: { type }, @@ -404,7 +414,7 @@ module.exports = { previousDeclCounts.uninitialized > 0) { context.report({ node, - message: "Combine this with the previous '{{type}}' statement with uninitialized variables.", + messageId: "combineUninitialized", data: { type }, @@ -419,7 +429,7 @@ module.exports = { if (options[type].initialized === MODE_ALWAYS && options[type].uninitialized === MODE_ALWAYS) { context.report({ node, - message: "Combine this with the previous '{{type}}' statement.", + messageId: "combine", data: { type }, @@ -429,7 +439,7 @@ module.exports = { if (options[type].initialized === MODE_ALWAYS && declarationCounts.initialized > 0) { context.report({ node, - message: "Combine this with the previous '{{type}}' statement with initialized variables.", + messageId: "combineInitialized", data: { type }, @@ -442,7 +452,7 @@ module.exports = { } context.report({ node, - message: "Combine this with the previous '{{type}}' statement with uninitialized variables.", + messageId: "combineUninitialized", data: { type }, @@ -462,7 +472,7 @@ module.exports = { // both initialized and uninitialized context.report({ node, - message: "Split '{{type}}' declarations into multiple statements.", + messageId: "split", data: { type }, @@ -473,7 +483,7 @@ module.exports = { // initialized context.report({ node, - message: "Split initialized '{{type}}' declarations into multiple statements.", + messageId: "splitInitialized", data: { type }, @@ -484,7 +494,7 @@ module.exports = { // uninitialized context.report({ node, - message: "Split uninitialized '{{type}}' declarations into multiple statements.", + messageId: "splitUninitialized", data: { type }, diff --git a/tools/node_modules/eslint/lib/rules/operator-assignment.js b/tools/node_modules/eslint/lib/rules/operator-assignment.js index b19ba0d02e1a1b..c4c8671f327a93 100644 --- a/tools/node_modules/eslint/lib/rules/operator-assignment.js +++ b/tools/node_modules/eslint/lib/rules/operator-assignment.js @@ -26,10 +26,10 @@ function isCommutativeOperatorWithShorthand(operator) { } /** - * Checks whether an operator is not commuatative and has an operator assignment + * Checks whether an operator is not commutative and has an operator assignment * shorthand form. * @param {string} operator Operator to check. - * @returns {boolean} True if the operator is not commuatative and has + * @returns {boolean} True if the operator is not commutative and has * a shorthand form. */ function isNonCommutativeOperatorWithShorthand(operator) { @@ -219,7 +219,7 @@ module.exports = { if ( operatorToken.range[1] === firstRightToken.range[0] && - !astUtils.canTokensBeAdjacent(newOperator, firstRightToken) + !astUtils.canTokensBeAdjacent({ type: "Punctuator", value: newOperator }, firstRightToken) ) { rightTextPrefix = " "; // foo+=+bar -> foo= foo+ +bar } diff --git a/tools/node_modules/eslint/lib/rules/operator-linebreak.js b/tools/node_modules/eslint/lib/rules/operator-linebreak.js index bce0ef56a0cc6c..c2fddcffd25c7f 100644 --- a/tools/node_modules/eslint/lib/rules/operator-linebreak.js +++ b/tools/node_modules/eslint/lib/rules/operator-linebreak.js @@ -47,7 +47,14 @@ module.exports = { } ], - fixable: "code" + fixable: "code", + + messages: { + operatorAtBeginning: "'{{operator}}' should be placed at the beginning of the line.", + operatorAtEnd: "'{{operator}}' should be placed at the end of the line.", + badLinebreak: "Bad line breaking before and after '{{operator}}'.", + noLinebreak: "There should be no line break before or after '{{operator}}'." + } }, create(context) { @@ -169,7 +176,7 @@ module.exports = { line: operatorToken.loc.end.line, column: operatorToken.loc.end.column }, - message: "Bad line breaking before and after '{{operator}}'.", + messageId: "badLinebreak", data: { operator }, @@ -184,7 +191,7 @@ module.exports = { line: operatorToken.loc.end.line, column: operatorToken.loc.end.column }, - message: "'{{operator}}' should be placed at the beginning of the line.", + messageId: "operatorAtBeginning", data: { operator }, @@ -199,7 +206,7 @@ module.exports = { line: operatorToken.loc.end.line, column: operatorToken.loc.end.column }, - message: "'{{operator}}' should be placed at the end of the line.", + messageId: "operatorAtEnd", data: { operator }, @@ -214,7 +221,7 @@ module.exports = { line: operatorToken.loc.end.line, column: operatorToken.loc.end.column }, - message: "There should be no line break before or after '{{operator}}'.", + messageId: "noLinebreak", data: { operator }, diff --git a/tools/node_modules/eslint/lib/rules/padded-blocks.js b/tools/node_modules/eslint/lib/rules/padded-blocks.js index dafa88115edd78..f58a7535ba86c2 100644 --- a/tools/node_modules/eslint/lib/rules/padded-blocks.js +++ b/tools/node_modules/eslint/lib/rules/padded-blocks.js @@ -60,7 +60,12 @@ module.exports = { } } } - ] + ], + + messages: { + alwaysPadBlock: "Block must be padded by blank lines.", + neverPadBlock: "Block must not be padded by blank lines." + } }, create(context) { @@ -90,9 +95,6 @@ module.exports = { options.allowSingleLineBlocks = exceptOptions.allowSingleLineBlocks === true; } - const ALWAYS_MESSAGE = "Block must be padded by blank lines.", - NEVER_MESSAGE = "Block must not be padded by blank lines."; - const sourceCode = context.getSourceCode(); /** @@ -145,9 +147,9 @@ module.exports = { } /** - * Checks if the given token is preceeded by a blank line. + * Checks if the given token is preceded by a blank line. * @param {Token} token The token to check - * @returns {boolean} Whether or not the token is preceeded by a blank line + * @returns {boolean} Whether or not the token is preceded by a blank line */ function getLastBlockToken(token) { let last = token, @@ -208,7 +210,7 @@ module.exports = { fix(fixer) { return fixer.insertTextAfter(tokenBeforeFirst, "\n"); }, - message: ALWAYS_MESSAGE + messageId: "alwaysPadBlock" }); } if (!blockHasBottomPadding) { @@ -218,7 +220,7 @@ module.exports = { fix(fixer) { return fixer.insertTextBefore(tokenAfterLast, "\n"); }, - message: ALWAYS_MESSAGE + messageId: "alwaysPadBlock" }); } } else { @@ -230,7 +232,7 @@ module.exports = { fix(fixer) { return fixer.replaceTextRange([tokenBeforeFirst.range[1], firstBlockToken.range[0] - firstBlockToken.loc.start.column], "\n"); }, - message: NEVER_MESSAGE + messageId: "neverPadBlock" }); } @@ -239,7 +241,7 @@ module.exports = { context.report({ node, loc: { line: tokenAfterLast.loc.end.line, column: tokenAfterLast.loc.end.column - 1 }, - message: NEVER_MESSAGE, + messageId: "neverPadBlock", fix(fixer) { return fixer.replaceTextRange([lastBlockToken.range[1], tokenAfterLast.range[0] - tokenAfterLast.loc.start.column], "\n"); } diff --git a/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js b/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js index 350a9dbf2aba15..eea19f5ce5811b 100644 --- a/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js +++ b/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js @@ -243,7 +243,7 @@ function verifyForNever(context, _, nextNode, paddingLines) { context.report({ node: nextNode, - message: "Unexpected blank line before this statement.", + messageId: "unexpectedBlankLine", fix(fixer) { if (paddingLines.length >= 2) { return null; @@ -282,7 +282,7 @@ function verifyForAlways(context, prevNode, nextNode, paddingLines) { context.report({ node: nextNode, - message: "Expected blank line before this statement.", + messageId: "expectedBlankLine", fix(fixer) { const sourceCode = context.getSourceCode(); let prevToken = getActualLastToken(sourceCode, prevNode); @@ -468,6 +468,11 @@ module.exports = { required: ["blankLine", "prev", "next"] }, additionalItems: false + }, + + messages: { + unexpectedBlankLine: "Unexpected blank line before this statement.", + expectedBlankLine: "Expected blank line before this statement." } }, diff --git a/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js b/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js index 08126e5b1a5459..d4e0251940c503 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js +++ b/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js @@ -56,7 +56,7 @@ function getVariableOfArguments(scope) { } /** - * Checkes whether or not a given node is a callback. + * Checks whether or not a given node is a callback. * @param {ASTNode} node A node to check. * @returns {Object} * {boolean} retv.isCallback - `true` if the node is a callback. @@ -158,7 +158,11 @@ module.exports = { } ], - fixable: "code" + fixable: "code", + + messages: { + preferArrowCallback: "Unexpected function expression." + } }, create(context) { @@ -267,7 +271,7 @@ module.exports = { ) { context.report({ node, - message: "Unexpected function expression.", + messageId: "preferArrowCallback", fix(fixer) { if ((!callbackInfo.isLexicalThis && scopeInfo.this) || hasDuplicateParams(node.params)) { diff --git a/tools/node_modules/eslint/lib/rules/prefer-destructuring.js b/tools/node_modules/eslint/lib/rules/prefer-destructuring.js index eff37294a9b6ef..1a51956dde53ff 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-destructuring.js +++ b/tools/node_modules/eslint/lib/rules/prefer-destructuring.js @@ -82,7 +82,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + preferDestructuring: "Use {{type}} destructuring." + } }, create(context) { @@ -137,7 +141,7 @@ module.exports = { function report(reportNode, type, fix) { context.report({ node: reportNode, - message: "Use {{type}} destructuring.", + messageId: "preferDestructuring", data: { type }, fix }); diff --git a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js index bbcd88bee3d071..1344433f52fa93 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js +++ b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js @@ -25,6 +25,36 @@ function hasArraySpread(node) { return node.arguments.some(arg => arg.type === "SpreadElement"); } +/** + * Determines whether the given node is an accessor property (getter/setter). + * @param {ASTNode} node Node to check. + * @returns {boolean} `true` if the node is a getter or a setter. + */ +function isAccessorProperty(node) { + return node.type === "Property" && + (node.kind === "get" || node.kind === "set"); +} + +/** + * Determines whether the given object expression node has accessor properties (getters/setters). + * @param {ASTNode} node `ObjectExpression` node to check. + * @returns {boolean} `true` if the node has at least one getter/setter. + */ +function hasAccessors(node) { + return node.properties.some(isAccessorProperty); +} + +/** + * Determines whether the given call expression node has object expression arguments with accessor properties (getters/setters). + * @param {ASTNode} node `CallExpression` node to check. + * @returns {boolean} `true` if the node has at least one argument that is an object expression with at least one getter/setter. + */ +function hasArgumentsWithAccessors(node) { + return node.arguments + .filter(arg => arg.type === "ObjectExpression") + .some(hasAccessors); +} + /** * Helper that checks if the node needs parentheses to be valid JS. * The default is to wrap the node in parentheses to avoid parsing errors. @@ -68,7 +98,7 @@ function argNeedsParens(node, sourceCode) { /** * Get the parenthesis tokens of a given ObjectExpression node. - * This incldues the braces of the object literal and enclosing parentheses. + * This includes the braces of the object literal and enclosing parentheses. * @param {ASTNode} node The node to get. * @param {Token} leftArgumentListParen The opening paren token of the argument list. * @param {SourceCode} sourceCode The source code object to get tokens. @@ -249,7 +279,11 @@ module.exports = { if ( node.arguments.length >= 1 && node.arguments[0].type === "ObjectExpression" && - !hasArraySpread(node) + !hasArraySpread(node) && + !( + node.arguments.length > 1 && + hasArgumentsWithAccessors(node) + ) ) { const messageId = node.arguments.length === 1 ? "useLiteralMessage" diff --git a/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js b/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js index e142a96b55c78f..56911b67adcc99 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js +++ b/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js @@ -31,7 +31,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + rejectAnError: "Expected the Promise rejection reason to be an Error." + } }, create(context) { @@ -58,7 +62,7 @@ module.exports = { ) { context.report({ node: callExpression, - message: "Expected the Promise rejection reason to be an Error." + messageId: "rejectAnError" }); } } diff --git a/tools/node_modules/eslint/lib/rules/prefer-reflect.js b/tools/node_modules/eslint/lib/rules/prefer-reflect.js index 796bbdf05fd446..fb2de923bea379 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-reflect.js +++ b/tools/node_modules/eslint/lib/rules/prefer-reflect.js @@ -49,7 +49,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + preferReflect: "Avoid using {{existing}}, instead use {{substitute}}." + } }, create(context) { @@ -65,7 +69,7 @@ module.exports = { preventExtensions: "Object.preventExtensions" }; - const reflectSubsitutes = { + const reflectSubstitutes = { apply: "Reflect.apply", call: "Reflect.apply", defineProperty: "Reflect.defineProperty", @@ -89,7 +93,7 @@ module.exports = { function report(node, existing, substitute) { context.report({ node, - message: "Avoid using {{existing}}, instead use {{substitute}}.", + messageId: "preferReflect", data: { existing, substitute @@ -101,11 +105,11 @@ module.exports = { CallExpression(node) { const methodName = (node.callee.property || {}).name; const isReflectCall = (node.callee.object || {}).name === "Reflect"; - const hasReflectSubsitute = Object.prototype.hasOwnProperty.call(reflectSubsitutes, methodName); + const hasReflectSubsitute = Object.prototype.hasOwnProperty.call(reflectSubstitutes, methodName); const userConfiguredException = exceptions.indexOf(methodName) !== -1; if (hasReflectSubsitute && !isReflectCall && !userConfiguredException) { - report(node, existingNames[methodName], reflectSubsitutes[methodName]); + report(node, existingNames[methodName], reflectSubstitutes[methodName]); } }, UnaryExpression(node) { diff --git a/tools/node_modules/eslint/lib/rules/prefer-rest-params.js b/tools/node_modules/eslint/lib/rules/prefer-rest-params.js index 3a28584f6bc126..3ecea732af8b94 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-rest-params.js +++ b/tools/node_modules/eslint/lib/rules/prefer-rest-params.js @@ -70,7 +70,11 @@ module.exports = { url: "https://eslint.org/docs/rules/prefer-rest-params" }, - schema: [] + schema: [], + + messages: { + preferRestParams: "Use the rest parameters instead of 'arguments'." + } }, create(context) { @@ -84,7 +88,7 @@ module.exports = { context.report({ node: reference.identifier, loc: reference.identifier.loc, - message: "Use the rest parameters instead of 'arguments'." + messageId: "preferRestParams" }); } diff --git a/tools/node_modules/eslint/lib/rules/prefer-spread.js b/tools/node_modules/eslint/lib/rules/prefer-spread.js index 14c05bd97103de..bcb0dc0dd4c1a9 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-spread.js +++ b/tools/node_modules/eslint/lib/rules/prefer-spread.js @@ -59,7 +59,11 @@ module.exports = { }, schema: [], - fixable: null + fixable: null, + + messages: { + preferSpread: "Use the spread operator instead of '.apply()'." + } }, create(context) { @@ -78,7 +82,7 @@ module.exports = { if (isValidThisArg(expectedThis, thisArg, sourceCode)) { context.report({ node, - message: "Use the spread operator instead of '.apply()'." + messageId: "preferSpread" }); } } diff --git a/tools/node_modules/eslint/lib/rules/prefer-template.js b/tools/node_modules/eslint/lib/rules/prefer-template.js index fa6e58d9721e12..e8f980ebd38c6f 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-template.js +++ b/tools/node_modules/eslint/lib/rules/prefer-template.js @@ -142,7 +142,11 @@ module.exports = { }, schema: [], - fixable: "code" + fixable: "code", + + messages: { + unexpectedStringConcatenation: "Unexpected string concatenation." + } }, create(context) { @@ -261,7 +265,7 @@ module.exports = { if (hasNonStringLiteral(topBinaryExpr)) { context.report({ node: topBinaryExpr, - message: "Unexpected string concatenation.", + messageId: "unexpectedStringConcatenation", fix: fixer => fixNonStringBinaryExpression(fixer, node) }); } diff --git a/tools/node_modules/eslint/lib/rules/quote-props.js b/tools/node_modules/eslint/lib/rules/quote-props.js index ab09b8fa938e63..a2a4e1d47923ff 100644 --- a/tools/node_modules/eslint/lib/rules/quote-props.js +++ b/tools/node_modules/eslint/lib/rules/quote-props.js @@ -8,8 +8,9 @@ // Requirements //------------------------------------------------------------------------------ -const espree = require("espree"), - keywords = require("./utils/keywords"); +const espree = require("espree"); +const astUtils = require("./utils/ast-utils"); +const keywords = require("./utils/keywords"); //------------------------------------------------------------------------------ // Rule Definition @@ -66,7 +67,16 @@ module.exports = { ] }, - fixable: "code" + fixable: "code", + messages: { + requireQuotesDueToReservedWord: "Properties should be quoted as '{{property}}' is a reserved word.", + inconsistentlyQuotedProperty: "Inconsistently quoted property '{{key}}' found.", + unnecessarilyQuotedProperty: "Unnecessarily quoted property '{{property}}' found.", + unquotedReservedProperty: "Unquoted reserved word '{{property}}' used as key.", + unquotedNumericProperty: "Unquoted number literal '{{property}}' used as key.", + unquotedPropertyFound: "Unquoted property '{{property}}' found.", + redundantQuoting: "Properties shouldn't be quoted as all quotes are redundant." + } }, create(context) { @@ -76,10 +86,6 @@ module.exports = { CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false, NUMBERS = context.options[1] && context.options[1].numbers, - MESSAGE_UNNECESSARY = "Unnecessarily quoted property '{{property}}' found.", - MESSAGE_UNQUOTED = "Unquoted property '{{property}}' found.", - MESSAGE_NUMERIC = "Unquoted number literal '{{property}}' used as key.", - MESSAGE_RESERVED = "Unquoted reserved word '{{property}}' used as key.", sourceCode = context.getSourceCode(); @@ -165,7 +171,7 @@ module.exports = { if (CHECK_UNNECESSARY && areQuotesRedundant(key.value, tokens, NUMBERS)) { context.report({ node, - message: MESSAGE_UNNECESSARY, + messageId: "unnecessarilyQuotedProperty", data: { property: key.value }, fix: fixer => fixer.replaceText(key, getUnquotedKey(key)) }); @@ -173,14 +179,14 @@ module.exports = { } else if (KEYWORDS && key.type === "Identifier" && isKeyword(key.name)) { context.report({ node, - message: MESSAGE_RESERVED, + messageId: "unquotedReservedProperty", data: { property: key.name }, fix: fixer => fixer.replaceText(key, getQuotedKey(key)) }); - } else if (NUMBERS && key.type === "Literal" && typeof key.value === "number") { + } else if (NUMBERS && key.type === "Literal" && astUtils.isNumericLiteral(key)) { context.report({ node, - message: MESSAGE_NUMERIC, + messageId: "unquotedNumericProperty", data: { property: key.value }, fix: fixer => fixer.replaceText(key, getQuotedKey(key)) }); @@ -198,7 +204,7 @@ module.exports = { if (!node.method && !node.computed && !node.shorthand && !(key.type === "Literal" && typeof key.value === "string")) { context.report({ node, - message: MESSAGE_UNQUOTED, + messageId: "unquotedPropertyFound", data: { property: key.name || key.value }, fix: fixer => fixer.replaceText(key, getQuotedKey(key)) }); @@ -253,7 +259,7 @@ module.exports = { quotedProps.forEach(property => { context.report({ node: property, - message: "Properties shouldn't be quoted as all quotes are redundant.", + messageId: "redundantQuoting", fix: fixer => fixer.replaceText(property.key, getUnquotedKey(property.key)) }); }); @@ -261,7 +267,7 @@ module.exports = { unquotedProps.forEach(property => { context.report({ node: property, - message: "Properties should be quoted as '{{property}}' is a reserved word.", + messageId: "requireQuotesDueToReservedWord", data: { property: keywordKeyName }, fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key)) }); @@ -270,7 +276,7 @@ module.exports = { unquotedProps.forEach(property => { context.report({ node: property, - message: "Inconsistently quoted property '{{key}}' found.", + messageId: "inconsistentlyQuotedProperty", data: { key: property.key.name || property.key.value }, fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key)) }); diff --git a/tools/node_modules/eslint/lib/rules/quotes.js b/tools/node_modules/eslint/lib/rules/quotes.js index f78d1129425633..d1f4443b9033c9 100644 --- a/tools/node_modules/eslint/lib/rules/quotes.js +++ b/tools/node_modules/eslint/lib/rules/quotes.js @@ -110,7 +110,11 @@ module.exports = { } ] } - ] + ], + + messages: { + wrongQuotes: "Strings must use {{description}}." + } }, create(context) { @@ -273,7 +277,7 @@ module.exports = { if (!isValid) { context.report({ node, - message: "Strings must use {{description}}.", + messageId: "wrongQuotes", data: { description: settings.description }, @@ -304,7 +308,7 @@ module.exports = { context.report({ node, - message: "Strings must use {{description}}.", + messageId: "wrongQuotes", data: { description: settings.description }, diff --git a/tools/node_modules/eslint/lib/rules/radix.js b/tools/node_modules/eslint/lib/rules/radix.js index ed3c5cb66b8cdc..3903cb2a6a2b01 100644 --- a/tools/node_modules/eslint/lib/rules/radix.js +++ b/tools/node_modules/eslint/lib/rules/radix.js @@ -18,6 +18,8 @@ const astUtils = require("./utils/ast-utils"); const MODE_ALWAYS = "always", MODE_AS_NEEDED = "as-needed"; +const validRadixValues = new Set(Array.from({ length: 37 - 2 }, (_, index) => index + 2)); + /** * Checks whether a given variable is shadowed or not. * @param {eslint-scope.Variable} variable A variable to check. @@ -47,14 +49,14 @@ function isParseIntMethod(node) { * * The following values are invalid. * - * - A literal except numbers. + * - A literal except integers between 2 and 36. * - undefined. * @param {ASTNode} radix A node of radix to check. * @returns {boolean} `true` if the node is valid. */ function isValidRadix(radix) { return !( - (radix.type === "Literal" && typeof radix.value !== "number") || + (radix.type === "Literal" && !validRadixValues.has(radix.value)) || (radix.type === "Identifier" && radix.name === "undefined") ); } @@ -87,7 +89,14 @@ module.exports = { { enum: ["always", "as-needed"] } - ] + ], + + messages: { + missingParameters: "Missing parameters.", + redundantRadix: "Redundant radix parameter.", + missingRadix: "Missing radix parameter.", + invalidRadix: "Invalid radix parameter, must be an integer between 2 and 36." + } }, create(context) { @@ -106,7 +115,7 @@ module.exports = { case 0: context.report({ node, - message: "Missing parameters." + messageId: "missingParameters" }); break; @@ -114,7 +123,7 @@ module.exports = { if (mode === MODE_ALWAYS) { context.report({ node, - message: "Missing radix parameter." + messageId: "missingRadix" }); } break; @@ -123,12 +132,12 @@ module.exports = { if (mode === MODE_AS_NEEDED && isDefaultRadix(args[1])) { context.report({ node, - message: "Redundant radix parameter." + messageId: "redundantRadix" }); } else if (!isValidRadix(args[1])) { context.report({ node, - message: "Invalid radix parameter." + messageId: "invalidRadix" }); } break; @@ -142,7 +151,7 @@ module.exports = { // Check `parseInt()` variable = astUtils.getVariableByName(scope, "parseInt"); - if (!isShadowed(variable)) { + if (variable && !isShadowed(variable)) { variable.references.forEach(reference => { const node = reference.identifier; @@ -154,7 +163,7 @@ module.exports = { // Check `Number.parseInt()` variable = astUtils.getVariableByName(scope, "Number"); - if (!isShadowed(variable)) { + if (variable && !isShadowed(variable)) { variable.references.forEach(reference => { const node = reference.identifier.parent; diff --git a/tools/node_modules/eslint/lib/rules/require-atomic-updates.js b/tools/node_modules/eslint/lib/rules/require-atomic-updates.js index bdd6d81ebc4758..4f6acceab804d1 100644 --- a/tools/node_modules/eslint/lib/rules/require-atomic-updates.js +++ b/tools/node_modules/eslint/lib/rules/require-atomic-updates.js @@ -223,7 +223,7 @@ module.exports = { /* * Register the variable to verify after ESLint traversed the `writeExpr` node - * if this reference is an assignment to a variable which is referred from other clausure. + * if this reference is an assignment to a variable which is referred from other closure. */ if (writeExpr && writeExpr.parent.right === writeExpr && // ← exclude variable declarations. diff --git a/tools/node_modules/eslint/lib/rules/require-await.js b/tools/node_modules/eslint/lib/rules/require-await.js index 22c111b6dc852e..274e241cfc7d5b 100644 --- a/tools/node_modules/eslint/lib/rules/require-await.js +++ b/tools/node_modules/eslint/lib/rules/require-await.js @@ -39,7 +39,11 @@ module.exports = { url: "https://eslint.org/docs/rules/require-await" }, - schema: [] + schema: [], + + messages: { + missingAwait: "{{name}} has no 'await' expression." + } }, create(context) { @@ -68,7 +72,7 @@ module.exports = { context.report({ node, loc: astUtils.getFunctionHeadLoc(node, sourceCode), - message: "{{name}} has no 'await' expression.", + messageId: "missingAwait", data: { name: capitalizeFirstLetter( astUtils.getFunctionNameWithKind(node) diff --git a/tools/node_modules/eslint/lib/rules/require-jsdoc.js b/tools/node_modules/eslint/lib/rules/require-jsdoc.js index 416a22ce6c4375..e581b2bee4646a 100644 --- a/tools/node_modules/eslint/lib/rules/require-jsdoc.js +++ b/tools/node_modules/eslint/lib/rules/require-jsdoc.js @@ -52,7 +52,11 @@ module.exports = { ], deprecated: true, - replacedBy: [] + replacedBy: [], + + messages: { + missingJSDocComment: "Missing JSDoc comment." + } }, create(context) { @@ -72,7 +76,7 @@ module.exports = { * @returns {void} */ function report(node) { - context.report({ node, message: "Missing JSDoc comment." }); + context.report({ node, messageId: "missingJSDocComment" }); } /** diff --git a/tools/node_modules/eslint/lib/rules/require-yield.js b/tools/node_modules/eslint/lib/rules/require-yield.js index dbfd759948af78..af2344dfa6b8ff 100644 --- a/tools/node_modules/eslint/lib/rules/require-yield.js +++ b/tools/node_modules/eslint/lib/rules/require-yield.js @@ -20,7 +20,11 @@ module.exports = { url: "https://eslint.org/docs/rules/require-yield" }, - schema: [] + schema: [], + + messages: { + missingYield: "This generator function does not have 'yield'." + } }, create(context) { @@ -51,7 +55,7 @@ module.exports = { const countYield = stack.pop(); if (countYield === 0 && node.body.body.length > 0) { - context.report({ node, message: "This generator function does not have 'yield'." }); + context.report({ node, messageId: "missingYield" }); } } diff --git a/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js b/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js index cd740fd3a99057..4bb5f787c6c568 100644 --- a/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js +++ b/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js @@ -26,7 +26,12 @@ module.exports = { { enum: ["always", "never"] } - ] + ], + + messages: { + unexpectedWhitespace: "Unexpected whitespace after {{type}} operator.", + expectedWhitespace: "Expected whitespace after {{type}} operator." + } }, create(context) { @@ -78,7 +83,7 @@ module.exports = { line: operator.loc.end.line, column: operator.loc.end.column }, - message: "Expected whitespace after {{type}} operator.", + messageId: "expectedWhitespace", data: { type }, @@ -93,7 +98,7 @@ module.exports = { line: operator.loc.end.line, column: operator.loc.end.column }, - message: "Unexpected whitespace after {{type}} operator.", + messageId: "unexpectedWhitespace", data: { type }, diff --git a/tools/node_modules/eslint/lib/rules/semi-spacing.js b/tools/node_modules/eslint/lib/rules/semi-spacing.js index 083dc26199f7bd..92948533d2789e 100644 --- a/tools/node_modules/eslint/lib/rules/semi-spacing.js +++ b/tools/node_modules/eslint/lib/rules/semi-spacing.js @@ -39,7 +39,14 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedWhitespaceBefore: "Unexpected whitespace before semicolon.", + unexpectedWhitespaceAfter: "Unexpected whitespace after semicolon.", + missingWhitespaceBefore: "Missing whitespace before semicolon.", + missingWhitespaceAfter: "Missing whitespace after semicolon." + } }, create(context) { @@ -124,7 +131,7 @@ module.exports = { context.report({ node, loc: location, - message: "Unexpected whitespace before semicolon.", + messageId: "unexpectedWhitespaceBefore", fix(fixer) { const tokenBefore = sourceCode.getTokenBefore(token); @@ -137,7 +144,7 @@ module.exports = { context.report({ node, loc: location, - message: "Missing whitespace before semicolon.", + messageId: "missingWhitespaceBefore", fix(fixer) { return fixer.insertTextBefore(token, " "); } @@ -151,7 +158,7 @@ module.exports = { context.report({ node, loc: location, - message: "Unexpected whitespace after semicolon.", + messageId: "unexpectedWhitespaceAfter", fix(fixer) { const tokenAfter = sourceCode.getTokenAfter(token); @@ -164,7 +171,7 @@ module.exports = { context.report({ node, loc: location, - message: "Missing whitespace after semicolon.", + messageId: "missingWhitespaceAfter", fix(fixer) { return fixer.insertTextAfter(token, " "); } diff --git a/tools/node_modules/eslint/lib/rules/semi-style.js b/tools/node_modules/eslint/lib/rules/semi-style.js index da3c4a38742b88..0c9bec4c85ede8 100644 --- a/tools/node_modules/eslint/lib/rules/semi-style.js +++ b/tools/node_modules/eslint/lib/rules/semi-style.js @@ -75,7 +75,11 @@ module.exports = { }, schema: [{ enum: ["last", "first"] }], - fixable: "whitespace" + fixable: "whitespace", + + messages: { + expectedSemiColon: "Expected this semicolon to be at {{pos}}." + } }, create(context) { @@ -97,7 +101,7 @@ module.exports = { if ((expected === "last" && !prevIsSameLine) || (expected === "first" && !nextIsSameLine)) { context.report({ loc: semiToken.loc, - message: "Expected this semicolon to be at {{pos}}.", + messageId: "expectedSemiColon", data: { pos: (expected === "last") ? "the end of the previous line" diff --git a/tools/node_modules/eslint/lib/rules/semi.js b/tools/node_modules/eslint/lib/rules/semi.js index 22e299efe72e49..d2f0670427b3ab 100644 --- a/tools/node_modules/eslint/lib/rules/semi.js +++ b/tools/node_modules/eslint/lib/rules/semi.js @@ -67,6 +67,11 @@ module.exports = { maxItems: 2 } ] + }, + + messages: { + missingSemi: "Missing semicolon.", + extraSemi: "Extra semicolon." } }, @@ -91,12 +96,12 @@ module.exports = { */ function report(node, missing) { const lastToken = sourceCode.getLastToken(node); - let message, + let messageId, fix, loc; if (!missing) { - message = "Missing semicolon."; + messageId = "missingSemi"; loc = { start: lastToken.loc.end, end: astUtils.getNextLocation(sourceCode, lastToken.loc.end) @@ -105,7 +110,7 @@ module.exports = { return fixer.insertTextAfter(lastToken, ";"); }; } else { - message = "Extra semicolon."; + messageId = "extraSemi"; loc = lastToken.loc; fix = function(fixer) { @@ -123,14 +128,14 @@ module.exports = { context.report({ node, loc, - message, + messageId, fix }); } /** - * Check whether a given semicolon token is redandant. + * Check whether a given semicolon token is redundant. * @param {Token} semiToken A semicolon token to check. * @returns {boolean} `true` if the next token is `;` or `}`. */ diff --git a/tools/node_modules/eslint/lib/rules/sort-imports.js b/tools/node_modules/eslint/lib/rules/sort-imports.js index 3b7f1d010348ad..65ad9a18a93112 100644 --- a/tools/node_modules/eslint/lib/rules/sort-imports.js +++ b/tools/node_modules/eslint/lib/rules/sort-imports.js @@ -50,7 +50,13 @@ module.exports = { } ], - fixable: "code" + fixable: "code", + + messages: { + sortImportsAlphabetically: "Imports should be sorted alphabetically.", + sortMembersAlphabetically: "Member '{{memberName}}' of the import declaration should be sorted alphabetically.", + unexpectedSyntaxOrder: "Expected '{{syntaxA}}' syntax before '{{syntaxB}}' syntax." + } }, create(context) { @@ -132,7 +138,7 @@ module.exports = { if (currentMemberSyntaxGroupIndex < previousMemberSyntaxGroupIndex) { context.report({ node, - message: "Expected '{{syntaxA}}' syntax before '{{syntaxB}}' syntax.", + messageId: "unexpectedSyntaxOrder", data: { syntaxA: memberSyntaxSortOrder[currentMemberSyntaxGroupIndex], syntaxB: memberSyntaxSortOrder[previousMemberSyntaxGroupIndex] @@ -146,7 +152,7 @@ module.exports = { ) { context.report({ node, - message: "Imports should be sorted alphabetically." + messageId: "sortImportsAlphabetically" }); } } @@ -163,7 +169,7 @@ module.exports = { if (firstUnsortedIndex !== -1) { context.report({ node: importSpecifiers[firstUnsortedIndex], - message: "Member '{{memberName}}' of the import declaration should be sorted alphabetically.", + messageId: "sortMembersAlphabetically", data: { memberName: importSpecifiers[firstUnsortedIndex].local.name }, fix(fixer) { if (importSpecifiers.some(specifier => diff --git a/tools/node_modules/eslint/lib/rules/sort-keys.js b/tools/node_modules/eslint/lib/rules/sort-keys.js index a5ce445f71ae93..8a95ee25d61948 100644 --- a/tools/node_modules/eslint/lib/rules/sort-keys.js +++ b/tools/node_modules/eslint/lib/rules/sort-keys.js @@ -41,7 +41,7 @@ function getPropertyName(node) { * Functions which check that the given 2 names are in specific order. * * Postfix `I` is meant insensitive. - * Postfix `N` is meant natual. + * Postfix `N` is meant natural. * @private */ const isValidOrders = { @@ -109,7 +109,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + sortKeys: "Expected object keys to be in {{natural}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'." + } }, create(context) { @@ -118,10 +122,10 @@ module.exports = { const order = context.options[0] || "asc"; const options = context.options[1]; const insensitive = options && options.caseSensitive === false; - const natual = options && options.natural; + const natural = options && options.natural; const minKeys = options && options.minKeys; const isValidOrder = isValidOrders[ - order + (insensitive ? "I" : "") + (natual ? "N" : "") + order + (insensitive ? "I" : "") + (natural ? "N" : "") ]; // The stack to save the previous property's name for each object literals. @@ -167,13 +171,13 @@ module.exports = { context.report({ node, loc: node.key.loc, - message: "Expected object keys to be in {{natual}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'.", + messageId: "sortKeys", data: { thisName, prevName, order, insensitive: insensitive ? "insensitive " : "", - natual: natual ? "natural " : "" + natural: natural ? "natural " : "" } }); } diff --git a/tools/node_modules/eslint/lib/rules/sort-vars.js b/tools/node_modules/eslint/lib/rules/sort-vars.js index e85c6534e3a189..7add2cf74b2940 100644 --- a/tools/node_modules/eslint/lib/rules/sort-vars.js +++ b/tools/node_modules/eslint/lib/rules/sort-vars.js @@ -33,7 +33,11 @@ module.exports = { } ], - fixable: "code" + fixable: "code", + + messages: { + sortVars: "Variables within the same declaration block should be sorted alphabetically." + } }, create(context) { @@ -56,7 +60,7 @@ module.exports = { if (currentVariableName < lastVariableName) { context.report({ node: decl, - message: "Variables within the same declaration block should be sorted alphabetically.", + messageId: "sortVars", fix(fixer) { if (unfixable || fixed) { return null; diff --git a/tools/node_modules/eslint/lib/rules/space-before-blocks.js b/tools/node_modules/eslint/lib/rules/space-before-blocks.js index 038e88db5215f5..9b56481bf355fb 100644 --- a/tools/node_modules/eslint/lib/rules/space-before-blocks.js +++ b/tools/node_modules/eslint/lib/rules/space-before-blocks.js @@ -47,7 +47,12 @@ module.exports = { } ] } - ] + ], + + messages: { + unexpectedSpace: "Unexpected space before opening brace.", + missingSpace: "Missing space before opening brace." + } }, create(context) { @@ -114,7 +119,7 @@ module.exports = { if (requireSpace && !hasSpace) { context.report({ node, - message: "Missing space before opening brace.", + messageId: "missingSpace", fix(fixer) { return fixer.insertTextBefore(node, " "); } @@ -122,7 +127,7 @@ module.exports = { } else if (requireNoSpace && hasSpace) { context.report({ node, - message: "Unexpected space before opening brace.", + messageId: "unexpectedSpace", fix(fixer) { return fixer.removeRange([precedingToken.range[1], node.range[0]]); } diff --git a/tools/node_modules/eslint/lib/rules/space-before-function-paren.js b/tools/node_modules/eslint/lib/rules/space-before-function-paren.js index 3a6d430f362051..af609c2e7c72fa 100644 --- a/tools/node_modules/eslint/lib/rules/space-before-function-paren.js +++ b/tools/node_modules/eslint/lib/rules/space-before-function-paren.js @@ -50,7 +50,12 @@ module.exports = { } ] } - ] + ], + + messages: { + unexpectedSpace: "Unexpected space before function parentheses.", + missingSpace: "Missing space before function parentheses." + } }, create(context) { @@ -123,7 +128,7 @@ module.exports = { context.report({ node, loc: leftToken.loc.end, - message: "Unexpected space before function parentheses.", + messageId: "unexpectedSpace", fix(fixer) { const comments = sourceCode.getCommentsBefore(rightToken); @@ -141,7 +146,7 @@ module.exports = { context.report({ node, loc: leftToken.loc.end, - message: "Missing space before function parentheses.", + messageId: "missingSpace", fix: fixer => fixer.insertTextAfter(leftToken, " ") }); } diff --git a/tools/node_modules/eslint/lib/rules/space-in-parens.js b/tools/node_modules/eslint/lib/rules/space-in-parens.js index 85ee74210d6007..b0a604d955d788 100644 --- a/tools/node_modules/eslint/lib/rules/space-in-parens.js +++ b/tools/node_modules/eslint/lib/rules/space-in-parens.js @@ -169,7 +169,7 @@ module.exports = { } /** - * Determines if a closing paren is immediately preceeded by a required space + * Determines if a closing paren is immediately preceded by a required space * @param {Object} tokenBeforeClosingParen The token before the paren * @param {Object} closingParenToken The paren token * @returns {boolean} True if the closing paren is missing a required space @@ -190,7 +190,7 @@ module.exports = { } /** - * Determines if a closer paren is immediately preceeded by a disallowed space + * Determines if a closer paren is immediately preceded by a disallowed space * @param {Object} tokenBeforeClosingParen The token before the paren * @param {Object} closingParenToken The paren token * @returns {boolean} True if the closing paren has a disallowed space diff --git a/tools/node_modules/eslint/lib/rules/space-infix-ops.js b/tools/node_modules/eslint/lib/rules/space-infix-ops.js index bd2c0ae0e1d3b7..471c22210eb613 100644 --- a/tools/node_modules/eslint/lib/rules/space-infix-ops.js +++ b/tools/node_modules/eslint/lib/rules/space-infix-ops.js @@ -32,7 +32,11 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + missingSpace: "Operator '{{operator}}' must be spaced." + } }, create(context) { @@ -70,7 +74,7 @@ module.exports = { context.report({ node: mainNode, loc: culpritToken.loc, - message: "Operator '{{operator}}' must be spaced.", + messageId: "missingSpace", data: { operator: culpritToken.value }, @@ -123,11 +127,11 @@ module.exports = { * @private */ function checkConditional(node) { - const nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent, "?"); + const nonSpacedConsequentNode = getFirstNonSpacedToken(node.test, node.consequent, "?"); const nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate, ":"); - if (nonSpacedConsequesntNode) { - report(node, nonSpacedConsequesntNode); + if (nonSpacedConsequentNode) { + report(node, nonSpacedConsequentNode); } else if (nonSpacedAlternateNode) { report(node, nonSpacedAlternateNode); } diff --git a/tools/node_modules/eslint/lib/rules/spaced-comment.js b/tools/node_modules/eslint/lib/rules/spaced-comment.js index daf56cd6bb42d0..d3221f0ea798ac 100644 --- a/tools/node_modules/eslint/lib/rules/spaced-comment.js +++ b/tools/node_modules/eslint/lib/rules/spaced-comment.js @@ -221,7 +221,16 @@ module.exports = { }, additionalProperties: false } - ] + ], + + messages: { + unexpectedSpaceAfterMarker: "Unexpected space or tab after marker ({{refChar}}) in comment.", + expectedExceptionAfter: "Expected exception block, space or tab after '{{refChar}}' in comment.", + unexpectedSpaceBefore: "Unexpected space or tab before '*/' in comment.", + unexpectedSpaceAfter: "Unexpected space or tab after '{{refChar}}' in comment.", + expectedSpaceBefore: "Expected space or tab before '*/' in comment.", + expectedSpaceAfter: "Expected space or tab after '{{refChar}}' in comment." + } }, create(context) { @@ -259,12 +268,12 @@ module.exports = { /** * 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} messageId An error message to report. * @param {Array} match An array of match results for markers. * @param {string} refChar Character used for reference in the error message. * @returns {void} */ - function reportBegin(node, message, match, refChar) { + function reportBegin(node, messageId, match, refChar) { const type = node.type.toLowerCase(), commentIdentifier = type === "block" ? "/*" : "//"; @@ -284,7 +293,7 @@ module.exports = { return fixer.replaceTextRange([start, end], commentIdentifier + (match[1] ? match[1] : "")); }, - message, + messageId, data: { refChar } }); } @@ -292,11 +301,11 @@ 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} messageId An error message to report. * @param {string} match An array of the matched whitespace characters. * @returns {void} */ - function reportEnd(node, message, match) { + function reportEnd(node, messageId, match) { context.report({ node, fix(fixer) { @@ -309,7 +318,7 @@ module.exports = { return fixer.replaceTextRange([start, end], ""); }, - message + messageId }); } @@ -338,26 +347,26 @@ module.exports = { const marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier; if (rule.hasExceptions) { - reportBegin(node, "Expected exception block, space or tab after '{{refChar}}' in comment.", hasMarker, marker); + reportBegin(node, "expectedExceptionAfter", hasMarker, marker); } else { - reportBegin(node, "Expected space or tab after '{{refChar}}' in comment.", hasMarker, marker); + reportBegin(node, "expectedSpaceAfter", hasMarker, marker); } } if (balanced && type === "block" && !endMatch) { - reportEnd(node, "Expected space or tab before '*/' in comment."); + reportEnd(node, "expectedSpaceBefore"); } } else { if (beginMatch) { if (!beginMatch[1]) { - reportBegin(node, "Unexpected space or tab after '{{refChar}}' in comment.", beginMatch, commentIdentifier); + reportBegin(node, "unexpectedSpaceAfter", beginMatch, commentIdentifier); } else { - reportBegin(node, "Unexpected space or tab after marker ({{refChar}}) in comment.", beginMatch, beginMatch[1]); + reportBegin(node, "unexpectedSpaceAfterMarker", beginMatch, beginMatch[1]); } } if (balanced && type === "block" && endMatch) { - reportEnd(node, "Unexpected space or tab before '*/' in comment.", endMatch); + reportEnd(node, "unexpectedSpaceBefore", endMatch); } } } diff --git a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js index 07da6a39b0e9bb..a16c0732df7b50 100644 --- a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js +++ b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js @@ -57,7 +57,7 @@ module.exports = { * @returns {void} */ function checkSpacingBefore(token) { - const prevToken = sourceCode.getTokenBefore(token); + const prevToken = sourceCode.getTokenBefore(token, { includeComments: true }); if (prevToken && CLOSE_PAREN.test(token.value) && @@ -86,7 +86,7 @@ module.exports = { * @returns {void} */ function checkSpacingAfter(token) { - const nextToken = sourceCode.getTokenAfter(token); + const nextToken = sourceCode.getTokenAfter(token, { includeComments: true }); if (nextToken && OPEN_PAREN.test(token.value) && diff --git a/tools/node_modules/eslint/lib/rules/use-isnan.js b/tools/node_modules/eslint/lib/rules/use-isnan.js index cd9ccdbaf898ee..7b466be75f2e5e 100644 --- a/tools/node_modules/eslint/lib/rules/use-isnan.js +++ b/tools/node_modules/eslint/lib/rules/use-isnan.js @@ -45,7 +45,7 @@ module.exports = { properties: { enforceForSwitchCase: { type: "boolean", - default: false + default: true }, enforceForIndexOf: { type: "boolean", @@ -66,7 +66,7 @@ module.exports = { create(context) { - const enforceForSwitchCase = context.options[0] && context.options[0].enforceForSwitchCase; + const enforceForSwitchCase = !context.options[0] || context.options[0].enforceForSwitchCase; const enforceForIndexOf = context.options[0] && context.options[0].enforceForIndexOf; /** diff --git a/tools/node_modules/eslint/lib/rules/utils/ast-utils.js b/tools/node_modules/eslint/lib/rules/utils/ast-utils.js index 01c6b47b82eefc..e10544dd61e9ca 100644 --- a/tools/node_modules/eslint/lib/rules/utils/ast-utils.js +++ b/tools/node_modules/eslint/lib/rules/utils/ast-utils.js @@ -865,6 +865,47 @@ module.exports = { return isFunction(node) && module.exports.isEmptyBlock(node.body); }, + /** + * Returns the result of the string conversion applied to the evaluated value of the given expression node, + * if it can be determined statically. + * + * This function returns a `string` value for all `Literal` nodes and simple `TemplateLiteral` nodes only. + * In all other cases, this function returns `null`. + * @param {ASTNode} node Expression node. + * @returns {string|null} String value if it can be determined. Otherwise, `null`. + */ + getStaticStringValue(node) { + switch (node.type) { + case "Literal": + if (node.value === null) { + if (module.exports.isNullLiteral(node)) { + return String(node.value); // "null" + } + if (node.regex) { + return `/${node.regex.pattern}/${node.regex.flags}`; + } + if (node.bigint) { + return node.bigint; + } + + // Otherwise, this is an unknown literal. The function will return null. + + } else { + return String(node.value); + } + break; + case "TemplateLiteral": + if (node.expressions.length === 0 && node.quasis.length === 1) { + return node.quasis[0].value.cooked; + } + break; + + // no default + } + + return null; + }, + /** * Gets the property name of a given node. * The node can be a MemberExpression, a Property, or a MethodDefinition. @@ -911,23 +952,12 @@ module.exports = { // no default } - switch (prop && prop.type) { - case "Literal": - return String(prop.value); - - case "TemplateLiteral": - if (prop.expressions.length === 0 && prop.quasis.length === 1) { - return prop.quasis[0].value.cooked; - } - break; - - case "Identifier": - if (!node.computed) { - return prop.name; - } - break; + if (prop) { + if (prop.type === "Identifier" && !node.computed) { + return prop.name; + } - // no default + return module.exports.getStaticStringValue(prop); } return null; @@ -987,6 +1017,7 @@ module.exports = { * 0o5 // false * 5e0 // false * '5' // false + * 5n // false */ isDecimalInteger(node) { return node.type === "Literal" && typeof node.value === "number" && @@ -1306,6 +1337,18 @@ module.exports = { return node.type === "Literal" && node.value === null && !node.regex && !node.bigint; }, + /** + * Check if a given node is a numeric literal or not. + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if the node is a number or bigint literal. + */ + isNumericLiteral(node) { + return ( + node.type === "Literal" && + (typeof node.value === "number" || Boolean(node.bigint)) + ); + }, + /** * Determines whether two tokens can safely be placed next to each other without merging into a single token * @param {Token|string} leftValue The left token. If this is a string, it will be tokenized and the last token will be used. diff --git a/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js b/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js index 0fa40ee4ae8630..0498b99a21ed45 100644 --- a/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js +++ b/tools/node_modules/eslint/lib/rules/utils/unicode/is-combining-character.js @@ -1,13 +1,13 @@ -// THIS FILE WAS GENERATED BY 'tools/update-unicode-utils.js' +/** + * @author Toru Nagashima + */ "use strict"; -const combiningChars = new Set([768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,1155,1156,1157,1158,1159,1160,1161,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1471,1473,1474,1476,1477,1479,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1648,1750,1751,1752,1753,1754,1755,1756,1759,1760,1761,1762,1763,1764,1767,1768,1770,1771,1772,1773,1809,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,2027,2028,2029,2030,2031,2032,2033,2034,2035,2070,2071,2072,2073,2075,2076,2077,2078,2079,2080,2081,2082,2083,2085,2086,2087,2089,2090,2091,2092,2093,2137,2138,2139,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2362,2363,2364,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2385,2386,2387,2388,2389,2390,2391,2402,2403,2433,2434,2435,2492,2494,2495,2496,2497,2498,2499,2500,2503,2504,2507,2508,2509,2519,2530,2531,2561,2562,2563,2620,2622,2623,2624,2625,2626,2631,2632,2635,2636,2637,2641,2672,2673,2677,2689,2690,2691,2748,2750,2751,2752,2753,2754,2755,2756,2757,2759,2760,2761,2763,2764,2765,2786,2787,2810,2811,2812,2813,2814,2815,2817,2818,2819,2876,2878,2879,2880,2881,2882,2883,2884,2887,2888,2891,2892,2893,2902,2903,2914,2915,2946,3006,3007,3008,3009,3010,3014,3015,3016,3018,3019,3020,3021,3031,3072,3073,3074,3075,3134,3135,3136,3137,3138,3139,3140,3142,3143,3144,3146,3147,3148,3149,3157,3158,3170,3171,3201,3202,3203,3260,3262,3263,3264,3265,3266,3267,3268,3270,3271,3272,3274,3275,3276,3277,3285,3286,3298,3299,3328,3329,3330,3331,3387,3388,3390,3391,3392,3393,3394,3395,3396,3398,3399,3400,3402,3403,3404,3405,3415,3426,3427,3458,3459,3530,3535,3536,3537,3538,3539,3540,3542,3544,3545,3546,3547,3548,3549,3550,3551,3570,3571,3633,3636,3637,3638,3639,3640,3641,3642,3655,3656,3657,3658,3659,3660,3661,3662,3761,3764,3765,3766,3767,3768,3769,3771,3772,3784,3785,3786,3787,3788,3789,3864,3865,3893,3895,3897,3902,3903,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3974,3975,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4038,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4182,4183,4184,4185,4190,4191,4192,4194,4195,4196,4199,4200,4201,4202,4203,4204,4205,4209,4210,4211,4212,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4239,4250,4251,4252,4253,4957,4958,4959,5906,5907,5908,5938,5939,5940,5970,5971,6002,6003,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6109,6155,6156,6157,6277,6278,6313,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6679,6680,6681,6682,6683,6741,6742,6743,6744,6745,6746,6747,6748,6749,6750,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779,6780,6783,6832,6833,6834,6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6912,6913,6914,6915,6916,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,7019,7020,7021,7022,7023,7024,7025,7026,7027,7040,7041,7042,7073,7074,7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,7154,7155,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7376,7377,7378,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7405,7410,7411,7412,7415,7416,7417,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7675,7676,7677,7678,7679,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,11503,11504,11505,11647,11744,11745,11746,11747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,12330,12331,12332,12333,12334,12335,12441,12442,42607,42608,42609,42610,42612,42613,42614,42615,42616,42617,42618,42619,42620,42621,42654,42655,42736,42737,43010,43014,43019,43043,43044,43045,43046,43047,43136,43137,43188,43189,43190,43191,43192,43193,43194,43195,43196,43197,43198,43199,43200,43201,43202,43203,43204,43205,43232,43233,43234,43235,43236,43237,43238,43239,43240,43241,43242,43243,43244,43245,43246,43247,43248,43249,43302,43303,43304,43305,43306,43307,43308,43309,43335,43336,43337,43338,43339,43340,43341,43342,43343,43344,43345,43346,43347,43392,43393,43394,43395,43443,43444,43445,43446,43447,43448,43449,43450,43451,43452,43453,43454,43455,43456,43493,43561,43562,43563,43564,43565,43566,43567,43568,43569,43570,43571,43572,43573,43574,43587,43596,43597,43643,43644,43645,43696,43698,43699,43700,43703,43704,43710,43711,43713,43755,43756,43757,43758,43759,43765,43766,44003,44004,44005,44006,44007,44008,44009,44010,44012,44013,64286,65024,65025,65026,65027,65028,65029,65030,65031,65032,65033,65034,65035,65036,65037,65038,65039,65056,65057,65058,65059,65060,65061,65062,65063,65064,65065,65066,65067,65068,65069,65070,65071,66045,66272,66422,66423,66424,66425,66426,68097,68098,68099,68101,68102,68108,68109,68110,68111,68152,68153,68154,68159,68325,68326,69632,69633,69634,69688,69689,69690,69691,69692,69693,69694,69695,69696,69697,69698,69699,69700,69701,69702,69759,69760,69761,69762,69808,69809,69810,69811,69812,69813,69814,69815,69816,69817,69818,69888,69889,69890,69927,69928,69929,69930,69931,69932,69933,69934,69935,69936,69937,69938,69939,69940,70003,70016,70017,70018,70067,70068,70069,70070,70071,70072,70073,70074,70075,70076,70077,70078,70079,70080,70090,70091,70092,70188,70189,70190,70191,70192,70193,70194,70195,70196,70197,70198,70199,70206,70367,70368,70369,70370,70371,70372,70373,70374,70375,70376,70377,70378,70400,70401,70402,70403,70460,70462,70463,70464,70465,70466,70467,70468,70471,70472,70475,70476,70477,70487,70498,70499,70502,70503,70504,70505,70506,70507,70508,70512,70513,70514,70515,70516,70709,70710,70711,70712,70713,70714,70715,70716,70717,70718,70719,70720,70721,70722,70723,70724,70725,70726,70832,70833,70834,70835,70836,70837,70838,70839,70840,70841,70842,70843,70844,70845,70846,70847,70848,70849,70850,70851,71087,71088,71089,71090,71091,71092,71093,71096,71097,71098,71099,71100,71101,71102,71103,71104,71132,71133,71216,71217,71218,71219,71220,71221,71222,71223,71224,71225,71226,71227,71228,71229,71230,71231,71232,71339,71340,71341,71342,71343,71344,71345,71346,71347,71348,71349,71350,71351,71453,71454,71455,71456,71457,71458,71459,71460,71461,71462,71463,71464,71465,71466,71467,72193,72194,72195,72196,72197,72198,72199,72200,72201,72202,72243,72244,72245,72246,72247,72248,72249,72251,72252,72253,72254,72263,72273,72274,72275,72276,72277,72278,72279,72280,72281,72282,72283,72330,72331,72332,72333,72334,72335,72336,72337,72338,72339,72340,72341,72342,72343,72344,72345,72751,72752,72753,72754,72755,72756,72757,72758,72760,72761,72762,72763,72764,72765,72766,72767,72850,72851,72852,72853,72854,72855,72856,72857,72858,72859,72860,72861,72862,72863,72864,72865,72866,72867,72868,72869,72870,72871,72873,72874,72875,72876,72877,72878,72879,72880,72881,72882,72883,72884,72885,72886,73009,73010,73011,73012,73013,73014,73018,73020,73021,73023,73024,73025,73026,73027,73028,73029,73031,92912,92913,92914,92915,92916,92976,92977,92978,92979,92980,92981,92982,94033,94034,94035,94036,94037,94038,94039,94040,94041,94042,94043,94044,94045,94046,94047,94048,94049,94050,94051,94052,94053,94054,94055,94056,94057,94058,94059,94060,94061,94062,94063,94064,94065,94066,94067,94068,94069,94070,94071,94072,94073,94074,94075,94076,94077,94078,94095,94096,94097,94098,113821,113822,119141,119142,119143,119144,119145,119149,119150,119151,119152,119153,119154,119163,119164,119165,119166,119167,119168,119169,119170,119173,119174,119175,119176,119177,119178,119179,119210,119211,119212,119213,119362,119363,119364,121344,121345,121346,121347,121348,121349,121350,121351,121352,121353,121354,121355,121356,121357,121358,121359,121360,121361,121362,121363,121364,121365,121366,121367,121368,121369,121370,121371,121372,121373,121374,121375,121376,121377,121378,121379,121380,121381,121382,121383,121384,121385,121386,121387,121388,121389,121390,121391,121392,121393,121394,121395,121396,121397,121398,121403,121404,121405,121406,121407,121408,121409,121410,121411,121412,121413,121414,121415,121416,121417,121418,121419,121420,121421,121422,121423,121424,121425,121426,121427,121428,121429,121430,121431,121432,121433,121434,121435,121436,121437,121438,121439,121440,121441,121442,121443,121444,121445,121446,121447,121448,121449,121450,121451,121452,121461,121476,121499,121500,121501,121502,121503,121505,121506,121507,121508,121509,121510,121511,121512,121513,121514,121515,121516,121517,121518,121519,122880,122881,122882,122883,122884,122885,122886,122888,122889,122890,122891,122892,122893,122894,122895,122896,122897,122898,122899,122900,122901,122902,122903,122904,122907,122908,122909,122910,122911,122912,122913,122915,122916,122918,122919,122920,122921,122922,125136,125137,125138,125139,125140,125141,125142,125252,125253,125254,125255,125256,125257,125258,917760,917761,917762,917763,917764,917765,917766,917767,917768,917769,917770,917771,917772,917773,917774,917775,917776,917777,917778,917779,917780,917781,917782,917783,917784,917785,917786,917787,917788,917789,917790,917791,917792,917793,917794,917795,917796,917797,917798,917799,917800,917801,917802,917803,917804,917805,917806,917807,917808,917809,917810,917811,917812,917813,917814,917815,917816,917817,917818,917819,917820,917821,917822,917823,917824,917825,917826,917827,917828,917829,917830,917831,917832,917833,917834,917835,917836,917837,917838,917839,917840,917841,917842,917843,917844,917845,917846,917847,917848,917849,917850,917851,917852,917853,917854,917855,917856,917857,917858,917859,917860,917861,917862,917863,917864,917865,917866,917867,917868,917869,917870,917871,917872,917873,917874,917875,917876,917877,917878,917879,917880,917881,917882,917883,917884,917885,917886,917887,917888,917889,917890,917891,917892,917893,917894,917895,917896,917897,917898,917899,917900,917901,917902,917903,917904,917905,917906,917907,917908,917909,917910,917911,917912,917913,917914,917915,917916,917917,917918,917919,917920,917921,917922,917923,917924,917925,917926,917927,917928,917929,917930,917931,917932,917933,917934,917935,917936,917937,917938,917939,917940,917941,917942,917943,917944,917945,917946,917947,917948,917949,917950,917951,917952,917953,917954,917955,917956,917957,917958,917959,917960,917961,917962,917963,917964,917965,917966,917967,917968,917969,917970,917971,917972,917973,917974,917975,917976,917977,917978,917979,917980,917981,917982,917983,917984,917985,917986,917987,917988,917989,917990,917991,917992,917993,917994,917995,917996,917997,917998,917999]) - /** * Check whether a given character is a combining mark or not. - * @param {number} c The character code to check. - * @returns {boolean} `true` if the character belongs to the category, one of `Mc`, `Me`, and `Mn`. + * @param {number} codePoint The character code to check. + * @returns {boolean} `true` if the character belongs to the category, any of `Mc`, `Me`, and `Mn`. */ -module.exports = function isCombiningCharacter(c) { - return combiningChars.has(c); +module.exports = function isCombiningCharacter(codePoint) { + return /^[\p{Mc}\p{Me}\p{Mn}]$/u.test(String.fromCodePoint(codePoint)); }; diff --git a/tools/node_modules/eslint/lib/rules/wrap-iife.js b/tools/node_modules/eslint/lib/rules/wrap-iife.js index 5e590be13e28b5..896aed63de5222 100644 --- a/tools/node_modules/eslint/lib/rules/wrap-iife.js +++ b/tools/node_modules/eslint/lib/rules/wrap-iife.js @@ -10,6 +10,21 @@ //------------------------------------------------------------------------------ const astUtils = require("./utils/ast-utils"); +const eslintUtils = require("eslint-utils"); + +//---------------------------------------------------------------------- +// Helpers +//---------------------------------------------------------------------- + +/** + * Check if the given node is callee of a `NewExpression` node + * @param {ASTNode} node node to check + * @returns {boolean} True if the node is callee of a `NewExpression` node + * @private + */ +function isCalleeOfNewExpression(node) { + return node.parent.type === "NewExpression" && node.parent.callee === node; +} //------------------------------------------------------------------------------ // Rule Definition @@ -58,15 +73,25 @@ module.exports = { const sourceCode = context.getSourceCode(); /** - * Check if the node is wrapped in () + * Check if the node is wrapped in any (). All parens count: grouping parens and parens for constructs such as if() * @param {ASTNode} node node to evaluate - * @returns {boolean} True if it is wrapped + * @returns {boolean} True if it is wrapped in any parens * @private */ - function wrapped(node) { + function isWrappedInAnyParens(node) { return astUtils.isParenthesised(sourceCode, node); } + /** + * Check if the node is wrapped in grouping (). Parens for constructs such as if() don't count + * @param {ASTNode} node node to evaluate + * @returns {boolean} True if it is wrapped in grouping parens + * @private + */ + function isWrappedInGroupingParens(node) { + return eslintUtils.isParenthesized(1, node, sourceCode); + } + /** * Get the function node from an IIFE * @param {ASTNode} node node to evaluate @@ -99,10 +124,10 @@ module.exports = { return; } - const callExpressionWrapped = wrapped(node), - functionExpressionWrapped = wrapped(innerNode); + const isCallExpressionWrapped = isWrappedInAnyParens(node), + isFunctionExpressionWrapped = isWrappedInAnyParens(innerNode); - if (!callExpressionWrapped && !functionExpressionWrapped) { + if (!isCallExpressionWrapped && !isFunctionExpressionWrapped) { context.report({ node, messageId: "wrapInvocation", @@ -112,27 +137,39 @@ module.exports = { return fixer.replaceText(nodeToSurround, `(${sourceCode.getText(nodeToSurround)})`); } }); - } else if (style === "inside" && !functionExpressionWrapped) { + } else if (style === "inside" && !isFunctionExpressionWrapped) { context.report({ node, messageId: "wrapExpression", fix(fixer) { + // The outer call expression will always be wrapped at this point. + + if (isWrappedInGroupingParens(node) && !isCalleeOfNewExpression(node)) { + + /* + * Parenthesize the function expression and remove unnecessary grouping parens around the call expression. + * Replace the range between the end of the function expression and the end of the call expression. + * for example, in `(function(foo) {}(bar))`, the range `(bar))` should get replaced with `)(bar)`. + */ + + const parenAfter = sourceCode.getTokenAfter(node); + + return fixer.replaceTextRange( + [innerNode.range[1], parenAfter.range[1]], + `)${sourceCode.getText().slice(innerNode.range[1], parenAfter.range[0])}` + ); + } + /* - * The outer call expression will always be wrapped at this point. - * Replace the range between the end of the function expression and the end of the call expression. - * for example, in `(function(foo) {}(bar))`, the range `(bar))` should get replaced with `)(bar)`. - * Replace the parens from the outer expression, and parenthesize the function expression. + * Call expression is wrapped in mandatory parens such as if(), or in necessary grouping parens. + * These parens cannot be removed, so just parenthesize the function expression. */ - const parenAfter = sourceCode.getTokenAfter(node); - return fixer.replaceTextRange( - [innerNode.range[1], parenAfter.range[1]], - `)${sourceCode.getText().slice(innerNode.range[1], parenAfter.range[0])}` - ); + return fixer.replaceText(innerNode, `(${sourceCode.getText(innerNode)})`); } }); - } else if (style === "outside" && !callExpressionWrapped) { + } else if (style === "outside" && !isCallExpressionWrapped) { context.report({ node, messageId: "moveInvocation", diff --git a/tools/node_modules/eslint/lib/rules/yoda.js b/tools/node_modules/eslint/lib/rules/yoda.js index b00acf82c702b0..c4ff3f81938595 100644 --- a/tools/node_modules/eslint/lib/rules/yoda.js +++ b/tools/node_modules/eslint/lib/rules/yoda.js @@ -49,12 +49,30 @@ function isRangeTestOperator(operator) { * @returns {boolean} True if the node is a negative number that looks like a * real literal and should be treated as such. */ -function looksLikeLiteral(node) { +function isNegativeNumericLiteral(node) { return (node.type === "UnaryExpression" && node.operator === "-" && node.prefix && - node.argument.type === "Literal" && - typeof node.argument.value === "number"); + astUtils.isNumericLiteral(node.argument)); +} + +/** + * Determines whether a node is a Template Literal which can be determined statically. + * @param {ASTNode} node Node to test + * @returns {boolean} True if the node is a Template Literal without expression. + */ +function isStaticTemplateLiteral(node) { + return node.type === "TemplateLiteral" && node.expressions.length === 0; +} + +/** + * Determines whether a non-Literal node should be treated as a single Literal node. + * @param {ASTNode} node Node to test + * @returns {boolean} True if the node should be treated as a single Literal node. + */ +function looksLikeLiteral(node) { + return isNegativeNumericLiteral(node) || + isStaticTemplateLiteral(node); } /** @@ -66,15 +84,17 @@ function looksLikeLiteral(node) { * 1. The original node if the node is already a Literal * 2. A normalized Literal node with the negative number as the value if the * node represents a negative number literal. - * 3. The Literal node which has the `defaultValue` argument if it exists. - * 4. Otherwise `null`. + * 3. A normalized Literal node with the string as the value if the node is + * a Template Literal without expression. + * 4. The Literal node which has the `defaultValue` argument if it exists. + * 5. Otherwise `null`. */ function getNormalizedLiteral(node, defaultValue) { if (node.type === "Literal") { return node; } - if (looksLikeLiteral(node)) { + if (isNegativeNumericLiteral(node)) { return { type: "Literal", value: -node.argument.value, @@ -82,6 +102,14 @@ function getNormalizedLiteral(node, defaultValue) { }; } + if (isStaticTemplateLiteral(node)) { + return { + type: "Literal", + value: node.quasis[0].value.cooked, + raw: node.quasis[0].value.raw + }; + } + if (defaultValue) { return { type: "Literal", diff --git a/tools/node_modules/eslint/lib/shared/config-validator.js b/tools/node_modules/eslint/lib/shared/config-validator.js index aca6e1fb274fdb..458bd2a802b95c 100644 --- a/tools/node_modules/eslint/lib/shared/config-validator.js +++ b/tools/node_modules/eslint/lib/shared/config-validator.js @@ -10,13 +10,12 @@ //------------------------------------------------------------------------------ const - path = require("path"), util = require("util"), - lodash = require("lodash"), configSchema = require("../../conf/config-schema"), BuiltInEnvironments = require("../../conf/environments"), BuiltInRules = require("../rules"), - ConfigOps = require("./config-ops"); + ConfigOps = require("./config-ops"), + { emitDeprecationWarning } = require("./deprecation-warnings"); const ajv = require("./ajv")(); const ruleValidators = new WeakMap(); @@ -26,11 +25,6 @@ const noop = Function.prototype; // Private //------------------------------------------------------------------------------ let validateSchema; - -// Defitions for deprecation warnings. -const deprecationWarningMessages = { - ESLINT_LEGACY_ECMAFEATURES: "The 'ecmaFeatures' config file property is deprecated, and has no effect." -}; const severityMap = { error: 2, warn: 1, @@ -196,7 +190,7 @@ function validateRules( /** * Validates a `globals` section of a config file - * @param {Object} globalsConfig The `glboals` section + * @param {Object} globalsConfig The `globals` section * @param {string|null} source The name of the configuration source to report in the event of an error. * @returns {void} */ @@ -254,25 +248,6 @@ function formatErrors(errors) { }).map(message => `\t- ${message}.\n`).join(""); } -/** - * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted - * for each unique file path, but repeated invocations with the same file path have no effect. - * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active. - * @param {string} source The name of the configuration source to report the warning for. - * @param {string} errorCode The warning message to show. - * @returns {void} - */ -const emitDeprecationWarning = lodash.memoize((source, errorCode) => { - const rel = path.relative(process.cwd(), source); - const message = deprecationWarningMessages[errorCode]; - - process.emitWarning( - `${message} (found in "${rel}")`, - "DeprecationWarning", - errorCode - ); -}); - /** * Validates the top level properties of the config object. * @param {Object} config The config object to validate. diff --git a/tools/node_modules/eslint/lib/shared/deprecation-warnings.js b/tools/node_modules/eslint/lib/shared/deprecation-warnings.js new file mode 100644 index 00000000000000..e1481a2e9aa0b8 --- /dev/null +++ b/tools/node_modules/eslint/lib/shared/deprecation-warnings.js @@ -0,0 +1,56 @@ +/** + * @fileoverview Provide the function that emits deprecation warnings. + * @author Toru Nagashima + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const path = require("path"); +const lodash = require("lodash"); + +//------------------------------------------------------------------------------ +// Private +//------------------------------------------------------------------------------ + +// Defitions for deprecation warnings. +const deprecationWarningMessages = { + ESLINT_LEGACY_ECMAFEATURES: + "The 'ecmaFeatures' config file property is deprecated and has no effect.", + ESLINT_PERSONAL_CONFIG_LOAD: + "'~/.eslintrc.*' config files have been deprecated. " + + "Please use a config file per project or the '--config' option.", + ESLINT_PERSONAL_CONFIG_SUPPRESS: + "'~/.eslintrc.*' config files have been deprecated. " + + "Please remove it or add 'root:true' to the config files in your " + + "projects in order to avoid loading '~/.eslintrc.*' accidentally." +}; + +/** + * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted + * for each unique file path, but repeated invocations with the same file path have no effect. + * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active. + * @param {string} source The name of the configuration source to report the warning for. + * @param {string} errorCode The warning message to show. + * @returns {void} + */ +const emitDeprecationWarning = lodash.memoize((source, errorCode) => { + const rel = path.relative(process.cwd(), source); + const message = deprecationWarningMessages[errorCode]; + + process.emitWarning( + `${message} (found in "${rel}")`, + "DeprecationWarning", + errorCode + ); +}, (...args) => JSON.stringify(args)); + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = { + emitDeprecationWarning +}; diff --git a/tools/node_modules/eslint/lib/shared/naming.js b/tools/node_modules/eslint/lib/shared/naming.js index b99155f15cafa7..32cff94538af22 100644 --- a/tools/node_modules/eslint/lib/shared/naming.js +++ b/tools/node_modules/eslint/lib/shared/naming.js @@ -78,7 +78,7 @@ function getShorthandName(fullname, prefix) { /** * Gets the scope (namespace) of a term. * @param {string} term The term which may have the namespace. - * @returns {string} The namepace of the term if it has one. + * @returns {string} The namespace of the term if it has one. */ function getNamespaceFromTerm(term) { const match = term.match(NAMESPACE_REGEX); diff --git a/tools/node_modules/eslint/lib/shared/relative-module-resolver.js b/tools/node_modules/eslint/lib/shared/relative-module-resolver.js index 5b25fa111214ed..fa6cca72361df5 100644 --- a/tools/node_modules/eslint/lib/shared/relative-module-resolver.js +++ b/tools/node_modules/eslint/lib/shared/relative-module-resolver.js @@ -6,35 +6,18 @@ "use strict"; const Module = require("module"); -const path = require("path"); -// Polyfill Node's `Module.createRequire` if not present. We only support the case where the argument is a filepath, not a URL. -const createRequire = ( - - // Added in v12.2.0 - Module.createRequire || - - // Added in v10.12.0, but deprecated in v12.2.0. - Module.createRequireFromPath || - - // Polyfill - This is not executed on the tests on node@>=10. - /* istanbul ignore next */ - (filename => { - const mod = new Module(filename, null); - - mod.filename = filename; - mod.paths = Module._nodeModulePaths(path.dirname(filename)); // eslint-disable-line no-underscore-dangle - mod._compile("module.exports = require;", filename); // eslint-disable-line no-underscore-dangle - return mod.exports; - }) -); +/* + * `Module.createRequire` is added in v12.2.0. It supports URL as well. + * We only support the case where the argument is a filepath, not a URL. + */ +const createRequire = Module.createRequire || Module.createRequireFromPath; module.exports = { /** * Resolves a Node module relative to another module * @param {string} moduleName The name of a Node module, or a path to a Node module. - * * @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be * a file rather than a directory, but the file need not actually exist. * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath` @@ -43,6 +26,8 @@ module.exports = { try { return createRequire(relativeToPath).resolve(moduleName); } catch (error) { + + // This `if` block is for older Node.js than 12.0.0. We can remove this block in the future. if ( typeof error === "object" && error !== null && diff --git a/tools/node_modules/eslint/lib/shared/types.js b/tools/node_modules/eslint/lib/shared/types.js index a5bd0200e2792a..f3d1a7f29f02f0 100644 --- a/tools/node_modules/eslint/lib/shared/types.js +++ b/tools/node_modules/eslint/lib/shared/types.js @@ -21,7 +21,7 @@ module.exports = {}; /** * @typedef {Object} ParserOptions * @property {EcmaFeatures} [ecmaFeatures] The optional features. - * @property {3|5|6|7|8|9|10|2015|2016|2017|2018|2019} [ecmaVersion] The ECMAScript version (or revision number). + * @property {3|5|6|7|8|9|10|11|2015|2016|2017|2018|2019|2020} [ecmaVersion] The ECMAScript version (or revision number). * @property {"script"|"module"} [sourceType] The source code type. */ diff --git a/tools/node_modules/eslint/lib/source-code/source-code.js b/tools/node_modules/eslint/lib/source-code/source-code.js index 30b4e9ab5c26e3..591d5a7e454ee2 100644 --- a/tools/node_modules/eslint/lib/source-code/source-code.js +++ b/tools/node_modules/eslint/lib/source-code/source-code.js @@ -121,7 +121,7 @@ function isSpaceBetween(sourceCode, first, second, checkInsideOfJSXText) { currentToken.range[1] !== nextToken.range[0] || /* - * For backward compatibility, check speces in JSXText. + * For backward compatibility, check spaces in JSXText. * https://github.com/eslint/eslint/issues/12614 */ ( diff --git a/tools/node_modules/eslint/lib/source-code/token-store/utils.js b/tools/node_modules/eslint/lib/source-code/token-store/utils.js index 444684b52f1bb0..21e1d6ff7c3b6d 100644 --- a/tools/node_modules/eslint/lib/source-code/token-store/utils.js +++ b/tools/node_modules/eslint/lib/source-code/token-store/utils.js @@ -1,5 +1,5 @@ /** - * @fileoverview Define utilify functions for token store. + * @fileoverview Define utility functions for token store. * @author Toru Nagashima */ "use strict"; diff --git a/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js b/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js index 35176fbc0682ca..62945f7782a774 100644 --- a/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js +++ b/tools/node_modules/eslint/node_modules/@babel/code-frame/lib/index.js @@ -6,17 +6,11 @@ Object.defineProperty(exports, "__esModule", { exports.codeFrameColumns = codeFrameColumns; exports.default = _default; -function _highlight() { - const data = _interopRequireWildcard(require("@babel/highlight")); +var _highlight = _interopRequireWildcard(require("@babel/highlight")); - _highlight = function () { - return data; - }; - - return data; -} +function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } -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)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } let deprecationWarningShown = false; @@ -35,7 +29,7 @@ function getMarkerLines(loc, source, opts) { column: 0, line: -1 }, loc.start); - const endLoc = Object.assign({}, startLoc, loc.end); + const endLoc = Object.assign({}, startLoc, {}, loc.end); const { linesAbove = 2, linesBelow = 3 @@ -94,8 +88,8 @@ function getMarkerLines(loc, source, opts) { } function codeFrameColumns(rawLines, loc, opts = {}) { - const highlighted = (opts.highlightCode || opts.forceColor) && (0, _highlight().shouldHighlight)(opts); - const chalk = (0, _highlight().getChalk)(opts); + const highlighted = (opts.highlightCode || opts.forceColor) && (0, _highlight.shouldHighlight)(opts); + const chalk = (0, _highlight.getChalk)(opts); const defs = getDefs(chalk); const maybeHighlight = (chalkFn, string) => { @@ -110,7 +104,7 @@ function codeFrameColumns(rawLines, loc, opts = {}) { } = getMarkerLines(loc, lines, opts); const hasColumns = loc.start && typeof loc.start.column === "number"; const numberMaxWidth = String(end).length; - const highlightedLines = highlighted ? (0, _highlight().default)(rawLines, opts) : rawLines; + const highlightedLines = highlighted ? (0, _highlight.default)(rawLines, opts) : rawLines; let frame = highlightedLines.split(NEWLINE).slice(start, end).map((line, index) => { const number = start + 1 + index; const paddedNumber = ` ${number}`.slice(-numberMaxWidth); diff --git a/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json b/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json index d619d9a8f53194..7508b5b1402c94 100644 --- a/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json +++ b/tools/node_modules/eslint/node_modules/@babel/code-frame/package.json @@ -5,7 +5,7 @@ }, "bundleDependencies": false, "dependencies": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "^7.8.3" }, "deprecated": false, "description": "Generate errors that contain a code frame that point to source locations.", @@ -13,7 +13,7 @@ "chalk": "^2.0.0", "strip-ansi": "^4.0.0" }, - "gitHead": "0407f034f09381b95e9cabefbf6b176c76485a43", + "gitHead": "a7620bd266ae1345975767bbc7abf09034437017", "homepage": "https://babeljs.io/", "license": "MIT", "main": "lib/index.js", @@ -25,5 +25,5 @@ "type": "git", "url": "https://github.com/babel/babel/tree/master/packages/babel-code-frame" }, - "version": "7.5.5" + "version": "7.8.3" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js b/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js index 6ac5b4a350b8e6..bf275748784b50 100644 --- a/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js +++ b/tools/node_modules/eslint/node_modules/@babel/highlight/lib/index.js @@ -7,39 +7,17 @@ exports.shouldHighlight = shouldHighlight; exports.getChalk = getChalk; exports.default = highlight; -function _jsTokens() { - const data = _interopRequireWildcard(require("js-tokens")); +var _jsTokens = _interopRequireWildcard(require("js-tokens")); - _jsTokens = function () { - return data; - }; - - return data; -} - -function _esutils() { - const data = _interopRequireDefault(require("esutils")); +var _esutils = _interopRequireDefault(require("esutils")); - _esutils = function () { - return data; - }; - - return data; -} - -function _chalk() { - const data = _interopRequireDefault(require("chalk")); - - _chalk = function () { - return data; - }; - - return data; -} +var _chalk = _interopRequireDefault(require("chalk")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -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)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } +function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function getDefs(chalk) { return { @@ -61,10 +39,10 @@ const BRACKET = /^[()[\]{}]$/; function getTokenType(match) { const [offset, text] = match.slice(-2); - const token = (0, _jsTokens().matchToToken)(match); + const token = (0, _jsTokens.matchToToken)(match); if (token.type === "name") { - if (_esutils().default.keyword.isReservedWordES6(token.value)) { + if (_esutils.default.keyword.isReservedWordES6(token.value)) { return "keyword"; } @@ -89,7 +67,7 @@ function getTokenType(match) { } function highlightTokens(defs, text) { - return text.replace(_jsTokens().default, function (...args) { + return text.replace(_jsTokens.default, function (...args) { const type = getTokenType(args); const colorize = defs[type]; @@ -102,14 +80,14 @@ function highlightTokens(defs, text) { } function shouldHighlight(options) { - return _chalk().default.supportsColor || options.forceColor; + return _chalk.default.supportsColor || options.forceColor; } function getChalk(options) { - let chalk = _chalk().default; + let chalk = _chalk.default; if (options.forceColor) { - chalk = new (_chalk().default.constructor)({ + chalk = new _chalk.default.constructor({ enabled: true, level: 1 }); diff --git a/tools/node_modules/eslint/node_modules/chalk/index.js b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js similarity index 100% rename from tools/node_modules/eslint/node_modules/chalk/index.js rename to tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js diff --git a/tools/node_modules/eslint/node_modules/chalk/index.js.flow b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js.flow similarity index 100% rename from tools/node_modules/eslint/node_modules/chalk/index.js.flow rename to tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/index.js.flow diff --git a/tools/node_modules/eslint/node_modules/string-width/node_modules/strip-ansi/license b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/license similarity index 100% rename from tools/node_modules/eslint/node_modules/string-width/node_modules/strip-ansi/license rename to tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/license diff --git a/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/package.json b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/package.json new file mode 100644 index 00000000000000..270fecdc347d42 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/package.json @@ -0,0 +1,80 @@ +{ + "bugs": { + "url": "https://github.com/chalk/chalk/issues" + }, + "bundleDependencies": false, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "deprecated": false, + "description": "Terminal string styling done right", + "devDependencies": { + "ava": "*", + "coveralls": "^3.0.0", + "execa": "^0.9.0", + "flow-bin": "^0.68.0", + "import-fresh": "^2.0.0", + "matcha": "^0.7.0", + "nyc": "^11.0.2", + "resolve-from": "^4.0.0", + "typescript": "^2.5.3", + "xo": "*" + }, + "engines": { + "node": ">=4" + }, + "files": [ + "index.js", + "templates.js", + "types/index.d.ts", + "index.js.flow" + ], + "homepage": "https://github.com/chalk/chalk#readme", + "keywords": [ + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "str", + "ansi", + "style", + "styles", + "tty", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "license": "MIT", + "name": "chalk", + "repository": { + "type": "git", + "url": "git+https://github.com/chalk/chalk.git" + }, + "scripts": { + "bench": "matcha benchmark.js", + "coveralls": "nyc report --reporter=text-lcov | coveralls", + "test": "xo && tsc --project types && flow --max-warnings=0 && nyc ava" + }, + "types": "types/index.d.ts", + "version": "2.4.2", + "xo": { + "envs": [ + "node", + "mocha" + ], + "ignores": [ + "test/_flow.js" + ] + } +} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/readme.md b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/readme.md new file mode 100644 index 00000000000000..d298e2c48d64a0 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk/readme.md @@ -0,0 +1,314 @@ +

+
+
+ Chalk +
+
+
+

+ +> Terminal string styling done right + +[![Build Status](https://travis-ci.org/chalk/chalk.svg?branch=master)](https://travis-ci.org/chalk/chalk) [![Coverage Status](https://coveralls.io/repos/github/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/github/chalk/chalk?branch=master) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) + +### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) + + + + +## Highlights + +- Expressive API +- Highly performant +- Ability to nest styles +- [256/Truecolor color support](#256-and-truecolor-color-support) +- Auto-detects color support +- Doesn't extend `String.prototype` +- Clean and focused +- Actively maintained +- [Used by ~23,000 packages](https://www.npmjs.com/browse/depended/chalk) as of December 31, 2017 + + +## Install + +```console +$ npm install chalk +``` + + + + + + +## Usage + +```js +const chalk = require('chalk'); + +console.log(chalk.blue('Hello world!')); +``` + +Chalk comes with an easy to use composable API where you just chain and nest the styles you want. + +```js +const chalk = require('chalk'); +const log = console.log; + +// Combine styled and normal strings +log(chalk.blue('Hello') + ' World' + chalk.red('!')); + +// Compose multiple styles using the chainable API +log(chalk.blue.bgRed.bold('Hello world!')); + +// Pass in multiple arguments +log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz')); + +// Nest styles +log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!')); + +// Nest styles of the same type even (color, underline, background) +log(chalk.green( + 'I am a green line ' + + chalk.blue.underline.bold('with a blue substring') + + ' that becomes green again!' +)); + +// ES2015 template literal +log(` +CPU: ${chalk.red('90%')} +RAM: ${chalk.green('40%')} +DISK: ${chalk.yellow('70%')} +`); + +// ES2015 tagged template literal +log(chalk` +CPU: {red ${cpu.totalPercent}%} +RAM: {green ${ram.used / ram.total * 100}%} +DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%} +`); + +// Use RGB colors in terminal emulators that support it. +log(chalk.keyword('orange')('Yay for orange colored text!')); +log(chalk.rgb(123, 45, 67).underline('Underlined reddish color')); +log(chalk.hex('#DEADED').bold('Bold gray!')); +``` + +Easily define your own themes: + +```js +const chalk = require('chalk'); + +const error = chalk.bold.red; +const warning = chalk.keyword('orange'); + +console.log(error('Error!')); +console.log(warning('Warning!')); +``` + +Take advantage of console.log [string substitution](https://nodejs.org/docs/latest/api/console.html#console_console_log_data_args): + +```js +const name = 'Sindre'; +console.log(chalk.green('Hello %s'), name); +//=> 'Hello Sindre' +``` + + +## API + +### chalk.`