diff --git a/.eslintrc.js b/.eslintrc.js index 9aa90c6366232d..cfada1f65c181e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -184,7 +184,11 @@ module.exports = { }, { selector: "CallExpression[callee.property.name='doesNotThrow']", - message: 'Please replace `assert.doesNotThrow()` and add a comment next to the code instead.', + message: 'Do not use `assert.doesNotThrow()`. Write the code without the wrapper and add a comment instead.', + }, + { + selector: "CallExpression[callee.property.name='doesNotReject']", + message: 'Do not use `assert.doesNotReject()`. Write the code without the wrapper and add a comment instead.', }, { selector: "CallExpression[callee.property.name='rejects'][arguments.length<2]", diff --git a/.gitignore b/.gitignore index 9c0d4eedac4ba4..9250c4bae7c3c2 100644 --- a/.gitignore +++ b/.gitignore @@ -42,8 +42,8 @@ coverage/ /out # various stuff that VC++ produces/uses and is not in /out -/Debug/ -/Release/ +/Debug +/Release !doc/blog/** *.sln !nodemsi.sln diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b9bcd9e768a73..3a7259e1caec06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,8 @@ release. -12.1.0
+12.2.0
+12.1.0
12.0.0
diff --git a/LICENSE b/LICENSE index 6125b8268a41ca..0990b3694b94ab 100644 --- a/LICENSE +++ b/LICENSE @@ -74,6 +74,29 @@ The externally maintained libraries used by Node.js are: THE SOFTWARE. """ +- Acorn plugins, located at deps/acorn-plugins, is licensed as follows: + """ + Copyright (C) 2017-2018 by Adrian Heine + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + - c-ares, located at deps/cares, is licensed as follows: """ Copyright (c) 2007 - 2018, Daniel Stenberg with many contributors, see AUTHORS diff --git a/Makefile b/Makefile index d41bf1601fb599..5834df883b0c23 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ GTEST_FILTER ?= "*" GNUMAKEFLAGS += --no-print-directory GCOV ?= gcov PWD = $(CURDIR) +BUILD_WITH ?= make ifdef JOBS PARALLEL_ARGS = -j $(JOBS) @@ -95,6 +96,7 @@ help: ## Print help for targets with comments. # Without the check there is a race condition between the link being deleted # and recreated which can break the addons build when running test-ci # See comments on the build-addons target for some more info +ifeq ($(BUILD_WITH), make) $(NODE_EXE): config.gypi out/Makefile $(MAKE) -C out BUILDTYPE=Release V=$(V) if [ ! -r $@ -o ! -L $@ ]; then ln -fs out/Release/$(NODE_EXE) $@; fi @@ -102,6 +104,29 @@ $(NODE_EXE): config.gypi out/Makefile $(NODE_G_EXE): config.gypi out/Makefile $(MAKE) -C out BUILDTYPE=Debug V=$(V) if [ ! -r $@ -o ! -L $@ ]; then ln -fs out/Debug/$(NODE_EXE) $@; fi +else +ifeq ($(BUILD_WITH), ninja) +ifeq ($(V),1) + NINJA_ARGS := $(NINJA_ARGS) -v +endif +ifdef JOBS + NINJA_ARGS := $(NINJA_ARGS) -j$(JOBS) +else + NINJA_ARGS := $(NINJA_ARGS) $(filter -j%,$(MAKEFLAGS)) +endif +$(NODE_EXE): config.gypi out/Release/build.ninja + ninja -C out/Release $(NINJA_ARGS) + if [ ! -r $@ -o ! -L $@ ]; then ln -fs out/Release/$(NODE_EXE) $@; fi + +$(NODE_G_EXE): config.gypi out/Debug/build.ninja + ninja -C out/Debug $(NINJA_ARGS) + if [ ! -r $@ -o ! -L $@ ]; then ln -fs out/Debug/$(NODE_EXE) $@; fi +else +$(NODE_EXE) $(NODE_G_EXE): + echo This Makefile currently only supports building with 'make' or 'ninja' +endif +endif + ifeq ($(BUILDTYPE),Debug) CONFIG_FLAGS += --debug diff --git a/README.md b/README.md index b5fdf80c65010a..3689be0481644e 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,8 @@ For information about the governance of the Node.js project, see **Gabriel Schulhof** <gabriel.schulhof@intel.com> * [gireeshpunathil](https://github.com/gireeshpunathil) - **Gireesh Punathil** <gpunathi@in.ibm.com> (he/him) +* [jasnell](https://github.com/jasnell) - +**James M Snell** <jasnell@gmail.com> (he/him) * [joyeecheung](https://github.com/joyeecheung) - **Joyee Cheung** <joyeec9h3@gmail.com> (she/her) * [mcollina](https://github.com/mcollina) - @@ -216,8 +218,6 @@ For information about the governance of the Node.js project, see **Fedor Indutny** <fedor.indutny@gmail.com> * [isaacs](https://github.com/isaacs) - **Isaac Z. Schlueter** <i@izs.me> -* [jasnell](https://github.com/jasnell) - -**James M Snell** <jasnell@gmail.com> (he/him) * [joshgav](https://github.com/joshgav) - **Josh Gavant** <josh.gavant@outlook.com> * [mscdex](https://github.com/mscdex) - @@ -243,8 +243,6 @@ For information about the governance of the Node.js project, see **Anna Henningsen** <anna@addaleax.net> (she/her) * [ak239](https://github.com/ak239) - **Aleksei Koziatinskii** <ak239spb@gmail.com> -* [andrasq](https://github.com/andrasq) - -**Andras** <andras@kinvey.com> * [AndreasMadsen](https://github.com/AndreasMadsen) - **Andreas Madsen** <amwebdk@gmail.com> (he/him) * [AnnaMag](https://github.com/AnnaMag) - @@ -279,6 +277,8 @@ For information about the governance of the Node.js project, see **Bartosz Sosnowski** <bartosz@janeasystems.com> * [calvinmetcalf](https://github.com/calvinmetcalf) - **Calvin Metcalf** <calvin.metcalf@gmail.com> +* [cclauss](https://github.com/cclauss) - +**Christian Clauss** <cclauss@me.com> (he/him) * [ChALkeR](https://github.com/ChALkeR) - **Сковорода Никита Андреевич** <chalkerx@gmail.com> (he/him) * [chrisdickinson](https://github.com/chrisdickinson) - @@ -401,8 +401,6 @@ For information about the governance of the Node.js project, see **Ali Ijaz Sheikh** <ofrobots@google.com> (he/him) * [orangemocha](https://github.com/orangemocha) - **Alexis Campailla** <orangemocha@nodejs.org> -* [othiym23](https://github.com/othiym23) - -**Forrest L Norvell** <ogd@aoaioxxysz.net> (he/him) * [oyyd](https://github.com/oyyd) - **Ouyang Yadong** <oyydoibh@gmail.com> (he/him) * [pmq20](https://github.com/pmq20) - @@ -447,8 +445,6 @@ For information about the governance of the Node.js project, see **Steven R Loomis** <srloomis@us.ibm.com> * [starkwang](https://github.com/starkwang) - **Weijia Wang** <starkwang@126.com> -* [stefanmb](https://github.com/stefanmb) - -**Stefan Budeanu** <stefan@budeanu.com> * [targos](https://github.com/targos) - **Michaël Zasso** <targos@protonmail.com> (he/him) * [thefourtheye](https://github.com/thefourtheye) - @@ -471,8 +467,6 @@ For information about the governance of the Node.js project, see **Vladimir de Turckheim** <vlad2t@hotmail.com> (he/him) * [vkurchatkin](https://github.com/vkurchatkin) - **Vladimir Kurchatkin** <vladimir.kurchatkin@gmail.com> -* [vsemozhetbyt](https://github.com/vsemozhetbyt) - -**Vse Mozhet Byt** <vsemozhetbyt@gmail.com> (he/him) * [watilde](https://github.com/watilde) - **Daijiro Wachi** <daijiro.wachi@gmail.com> (he/him) * [watson](https://github.com/watson) - @@ -492,6 +486,8 @@ For information about the governance of the Node.js project, see ### Collaborator Emeriti +* [andrasq](https://github.com/andrasq) - +**Andras** <andras@kinvey.com> * [imran-iq](https://github.com/imran-iq) - **Imran Iqbal** <imran@imraniqbal.org> * [isaacs](https://github.com/isaacs) - @@ -508,6 +504,8 @@ For information about the governance of the Node.js project, see **Christopher Monsanto** <chris@monsan.to> * [Olegas](https://github.com/Olegas) - **Oleg Elifantiev** <oleg@elifantiev.ru> +* [othiym23](https://github.com/othiym23) - +**Forrest L Norvell** <ogd@aoaioxxysz.net> (he/him) * [petkaantonov](https://github.com/petkaantonov) - **Petka Antonov** <petka_antonov@hotmail.com> * [phillipj](https://github.com/phillipj) - @@ -522,10 +520,14 @@ For information about the governance of the Node.js project, see **Robert Kowalski** <rok@kowalski.gd> * [romankl](https://github.com/romankl) - **Roman Klauke** <romaaan.git@gmail.com> +* [stefanmb](https://github.com/stefanmb) - +**Stefan Budeanu** <stefan@budeanu.com> * [tellnes](https://github.com/tellnes) - **Christian Tellnes** <christian@tellnes.no> * [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe** <m.j.tunnicliffe@gmail.com> +* [vsemozhetbyt](https://github.com/vsemozhetbyt) - +**Vse Mozhet Byt** <vsemozhetbyt@gmail.com> (he/him) Collaborators follow the [COLLABORATOR_GUIDE.md](./COLLABORATOR_GUIDE.md) in maintaining the Node.js project. diff --git a/benchmark/http/bench-parser.js b/benchmark/http/bench-parser.js index 271ac55d007028..05776f2d8a3500 100644 --- a/benchmark/http/bench-parser.js +++ b/benchmark/http/bench-parser.js @@ -24,13 +24,14 @@ function main({ len, n }) { bench.start(); for (var i = 0; i < n; i++) { parser.execute(header, 0, header.length); - parser.initialize(REQUEST, header); + parser.initialize(REQUEST, {}); } bench.end(n); } function newParser(type) { - const parser = new HTTPParser(type); + const parser = new HTTPParser(); + parser.initialize(type, {}); parser.headers = []; diff --git a/benchmark/misc/print.js b/benchmark/misc/print.js new file mode 100644 index 00000000000000..e048d22f7b76ab --- /dev/null +++ b/benchmark/misc/print.js @@ -0,0 +1,59 @@ +'use strict'; +const common = require('../common.js'); +const { spawn } = require('child_process'); + +const bench = common.createBenchmark(main, { + dur: [1], + code: ['1', '"string"', 'process.versions', 'process'] +}); + +function spawnProcess(code) { + const cmd = process.execPath || process.argv[0]; + const argv = ['-p', code]; + return spawn(cmd, argv); +} + +function start(state, code, bench, getNode) { + const node = getNode(code); + let stdout = ''; + let stderr = ''; + + node.stdout.on('data', (data) => { + stdout += data; + }); + + node.stderr.on('data', (data) => { + stderr += data; + }); + + node.on('exit', (code) => { + if (code !== 0) { + console.error('------ stdout ------'); + console.error(stdout); + console.error('------ stderr ------'); + console.error(stderr); + throw new Error(`Error during node startup, exit code ${code}`); + } + state.throughput++; + + if (state.go) { + start(state, code, bench, getNode); + } else { + bench.end(state.throughput); + } + }); +} + +function main({ dur, code }) { + const state = { + go: true, + throughput: 0 + }; + + setTimeout(() => { + state.go = false; + }, dur * 1000); + + bench.start(); + start(state, code, bench, spawnProcess); +} diff --git a/benchmark/timers/timers-breadth-args.js b/benchmark/timers/timers-breadth-args.js new file mode 100644 index 00000000000000..5f91603caa0a5c --- /dev/null +++ b/benchmark/timers/timers-breadth-args.js @@ -0,0 +1,42 @@ +'use strict'; +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + n: [1e6], +}); + +function main({ n }) { + var j = 0; + function cb1(arg1) { + j++; + if (j === n) + bench.end(n); + } + function cb2(arg1, arg2) { + j++; + if (j === n) + bench.end(n); + } + function cb3(arg1, arg2, arg3) { + j++; + if (j === n) + bench.end(n); + } + function cb4(arg1, arg2, arg3, arg4) { + j++; + if (j === n) + bench.end(n); + } + + bench.start(); + for (var i = 0; i < n; i++) { + if (i % 4 === 0) + setTimeout(cb4, 1, 3.14, 1024, true, false); + else if (i % 3 === 0) + setTimeout(cb3, 1, 512, true, null); + else if (i % 2 === 0) + setTimeout(cb2, 1, false, 5.1); + else + setTimeout(cb1, 1, 0); + } +} diff --git a/common.gypi b/common.gypi index 9f9870b95abe4e..83efbb8898956b 100644 --- a/common.gypi +++ b/common.gypi @@ -38,7 +38,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.16', + 'v8_embedder_string': '-node.17', ##### V8 defaults for Node.js ##### diff --git a/configure b/configure index 495d0e8848860c..9156e13f7aed0d 100755 --- a/configure +++ b/configure @@ -13,10 +13,10 @@ del _ import sys from distutils.spawn import find_executable as which -if sys.version_info[0] != 2 or sys.version_info[1] not in (6, 7): - sys.stderr.write('Please use either Python 2.6 or 2.7') +if sys.version_info[:2] != (2, 7): + sys.stderr.write('Please use Python 2.7') - python2 = which('python2') or which('python2.6') or which('python2.7') + python2 = which('python2') or which('python2.7') if python2: sys.stderr.write(':\n\n') diff --git a/configure.py b/configure.py index 1dd6da6d2b997a..15ea5687cf1cd8 100755 --- a/configure.py +++ b/configure.py @@ -1627,23 +1627,35 @@ def make_bin_override(): ' '.join([pipes.quote(arg) for arg in original_argv]) + '\n') os.chmod('config.status', 0o775) + config = { 'BUILDTYPE': 'Debug' if options.debug else 'Release', - 'PYTHON': sys.executable, 'NODE_TARGET_TYPE': variables['node_target_type'], } +# Not needed for trivial case. Useless when it's a win32 path. +if sys.executable != 'python' and ':\\' not in sys.executable: + config['PYTHON'] = sys.executable + if options.prefix: config['PREFIX'] = options.prefix -config = '\n'.join(['='.join(item) for item in config.items()]) + '\n' +if options.use_ninja: + config['BUILD_WITH'] = 'ninja' + +config_lines = ['='.join((k,v)) for k,v in config.items()] +# Add a blank string to get a blank line at the end. +config_lines += [''] +config_str = '\n'.join(config_lines) # On Windows there's no reason to search for a different python binary. bin_override = None if sys.platform == 'win32' else make_bin_override() if bin_override: - config = 'export PATH:=' + bin_override + ':$(PATH)\n' + config + config_str = 'export PATH:=' + bin_override + ':$(PATH)\n' + config_str + +write('config.mk', do_not_edit + config_str) + -write('config.mk', do_not_edit + config) gyp_args = ['--no-parallel', '-Dconfiguring_node=1'] diff --git a/deps/acorn-plugins/acorn-bigint/CHANGELOG.md b/deps/acorn-plugins/acorn-bigint/CHANGELOG.md new file mode 100644 index 00000000000000..1d12d708f2cb75 --- /dev/null +++ b/deps/acorn-plugins/acorn-bigint/CHANGELOG.md @@ -0,0 +1,21 @@ +## 0.4.0 (2019-04-04) + +* Make compatible with acorn-numeric-separator + +## 0.3.1 (2018-10-06) + +* Fix creation of BigInt values everywhere (Thanks, Gus Caplan!) + +## 0.3.0 (2018-09-14) + +* Update to new acorn 6 interface +* Actually support creating BigInt values in AST in Chrome +* Change license to MIT + +## 0.2.0 (2017-12-20) + +* Emit BigInt values in AST if supported by runtime engine + +## 0.1.0 (2017-12-19) + +Initial release diff --git a/deps/acorn-plugins/acorn-bigint/LICENSE b/deps/acorn-plugins/acorn-bigint/LICENSE new file mode 100644 index 00000000000000..7c2b27a19c033c --- /dev/null +++ b/deps/acorn-plugins/acorn-bigint/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2017-2018 by Adrian Heine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/deps/acorn-plugins/acorn-bigint/README.md b/deps/acorn-plugins/acorn-bigint/README.md new file mode 100644 index 00000000000000..b0b6bb55543a58 --- /dev/null +++ b/deps/acorn-plugins/acorn-bigint/README.md @@ -0,0 +1,21 @@ +# BigInt support for Acorn + +[![NPM version](https://img.shields.io/npm/v/acorn-bigint.svg)](https://www.npmjs.org/package/acorn-bigint) + +This is a plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript. + +It implements support for arbitrary precision integers as defined in the stage 3 proposal [BigInt: Arbitrary precision integers in JavaScript](https://github.com/tc39/proposal-bigint). The emitted AST follows [an ESTree proposal](https://github.com/estree/estree/blob/132be9b9ec376adbc082dd5f6ba78aefd7a1a864/experimental/bigint.md). + +## Usage + +This module provides a plugin that can be used to extend the Acorn `Parser` class: + +```javascript +const {Parser} = require('acorn'); +const bigInt = require('acorn-bigint'); +Parser.extend(bigInt).parse('100n'); +``` + +## License + +This plugin is released under an [MIT License](./LICENSE). diff --git a/deps/acorn-plugins/acorn-bigint/index.js b/deps/acorn-plugins/acorn-bigint/index.js new file mode 100644 index 00000000000000..8e63515e11bbc5 --- /dev/null +++ b/deps/acorn-plugins/acorn-bigint/index.js @@ -0,0 +1,59 @@ +"use strict" + +const acorn = require('internal/deps/acorn/acorn/dist/acorn') +const tt = acorn.tokTypes +const isIdentifierStart = acorn.isIdentifierStart + +module.exports = function(Parser) { + return class extends Parser { + parseLiteral(value) { + const node = super.parseLiteral(value) + if (node.raw.charCodeAt(node.raw.length - 1) == 110) node.bigint = this.getNumberInput(node.start, node.end) + return node + } + + readRadixNumber(radix) { + let start = this.pos + this.pos += 2 // 0x + let val = this.readInt(radix) + if (val === null) this.raise(this.start + 2, `Expected number in radix ${radix}`) + if (this.input.charCodeAt(this.pos) == 110) { + let str = this.getNumberInput(start, this.pos) + val = typeof BigInt !== "undefined" ? BigInt(str) : null + ++this.pos + } else if (isIdentifierStart(this.fullCharCodeAtPos())) this.raise(this.pos, "Identifier directly after number") + return this.finishToken(tt.num, val) + } + + readNumber(startsWithDot) { + let start = this.pos + + // Not an int + if (startsWithDot) return super.readNumber(startsWithDot) + + // Legacy octal + if (this.input.charCodeAt(start) === 48 && this.input.charCodeAt(start + 1) !== 110) { + return super.readNumber(startsWithDot) + } + + if (this.readInt(10) === null) this.raise(start, "Invalid number") + + // Not a BigInt, reset and parse again + if (this.input.charCodeAt(this.pos) != 110) { + this.pos = start + return super.readNumber(startsWithDot) + } + + let str = this.getNumberInput(start, this.pos) + let val = typeof BigInt !== "undefined" ? BigInt(str) : null + ++this.pos + return this.finishToken(tt.num, val) + } + + // This is basically a hook for acorn-numeric-separator + getNumberInput(start, end) { + if (super.getNumberInput) return super.getNumberInput(start, end) + return this.input.slice(start, end) + } + } +} diff --git a/deps/acorn-plugins/acorn-bigint/package.json b/deps/acorn-plugins/acorn-bigint/package.json new file mode 100644 index 00000000000000..073cdfb86c309d --- /dev/null +++ b/deps/acorn-plugins/acorn-bigint/package.json @@ -0,0 +1,65 @@ +{ + "_from": "acorn-bigint", + "_id": "acorn-bigint@0.4.0", + "_inBundle": false, + "_integrity": "sha512-W9iaqWzqFo7ZBLmI9dMjHYGrN0Nm/ZgToqhvd3RELJux7RsX6k1/80h+bD9TtTpeKky/kYNbr3+vHWqI3hdyfA==", + "_location": "/acorn-bigint", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "acorn-bigint", + "name": "acorn-bigint", + "escapedName": "acorn-bigint", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/acorn-bigint/-/acorn-bigint-0.4.0.tgz", + "_shasum": "af3245ed8a7c3747387fca4680ae1960f617c4cd", + "_spec": "acorn-bigint", + "_where": "/home/ruben/repos/node/node", + "bugs": { + "url": "https://github.com/acornjs/acorn-bigint/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Adrian Heine", + "email": "mail@adrianheine.de" + } + ], + "deprecated": false, + "description": "Support for BigInt in acorn", + "devDependencies": { + "acorn": "^6.1.1", + "eslint": "^5.16.0", + "eslint-plugin-node": "^8.0.1", + "mocha": "^6.0.2", + "test262": "git+https://github.com/tc39/test262.git#611919174ffe060503691a0c7e3eb2a65b646124", + "test262-parser-runner": "^0.5.0" + }, + "engines": { + "node": ">=4.8.2" + }, + "homepage": "https://github.com/acornjs/acorn-bigint", + "license": "MIT", + "name": "acorn-bigint", + "peerDependencies": { + "acorn": "^6.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acornjs/acorn-bigint.git" + }, + "scripts": { + "lint": "eslint -c .eslintrc.json .", + "test": "mocha", + "test:test262": "node run_test262.js" + }, + "version": "0.4.0" +} diff --git a/deps/acorn-plugins/acorn-class-fields/CHANGELOG.md b/deps/acorn-plugins/acorn-class-fields/CHANGELOG.md new file mode 100644 index 00000000000000..de2c66b0c3bc65 --- /dev/null +++ b/deps/acorn-plugins/acorn-class-fields/CHANGELOG.md @@ -0,0 +1,28 @@ +## 0.3.1 (2019-02-09) + +* Restore compatibility with acorn-private-methods + +## 0.3.0 (2019-02-09) + +* Require acorn >= 6.1.0 + +## 0.2.1 (2018-11-06) + +* Adapt to changes in acorn 6.0.3 + +## 0.2.0 (2018-09-14) + +* Update to new acorn 6 interface +* Change license to MIT + +## 0.1.2 (2018-01-26) + +* Don't accept whitespace between hash and private name + +## 0.1.1 (2018-01-17) + +* Correctly parse all fields named `async` + +## 0.1.0 (2018-01-13) + +Initial release diff --git a/deps/acorn-plugins/acorn-class-fields/LICENSE b/deps/acorn-plugins/acorn-class-fields/LICENSE new file mode 100644 index 00000000000000..7c2b27a19c033c --- /dev/null +++ b/deps/acorn-plugins/acorn-class-fields/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2017-2018 by Adrian Heine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/deps/acorn-plugins/acorn-class-fields/README.md b/deps/acorn-plugins/acorn-class-fields/README.md new file mode 100644 index 00000000000000..60f3463e94d315 --- /dev/null +++ b/deps/acorn-plugins/acorn-class-fields/README.md @@ -0,0 +1,21 @@ +# Class fields support for Acorn + +[![NPM version](https://img.shields.io/npm/v/acorn-class-fields.svg)](https://www.npmjs.org/package/acorn-class-fields) + +This is a plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript. + +It implements support for class fields as defined in the stage 3 proposal [Class field declarations for JavaScript](https://github.com/tc39/proposal-class-fields). The emitted AST follows [an ESTree proposal](https://github.com/estree/estree/pull/180). + +## Usage + +This module provides a plugin that can be used to extend the Acorn `Parser` class: + +```javascript +const {Parser} = require('acorn'); +const classFields = require('acorn-class-fields'); +Parser.extend(classFields).parse('class X { x = 0 }'); +``` + +## License + +This plugin is released under an [MIT License](./LICENSE). diff --git a/deps/acorn-plugins/acorn-class-fields/index.js b/deps/acorn-plugins/acorn-class-fields/index.js new file mode 100644 index 00000000000000..20348c80c6bcbf --- /dev/null +++ b/deps/acorn-plugins/acorn-class-fields/index.js @@ -0,0 +1,59 @@ +"use strict" + +const acorn = require('internal/deps/acorn/acorn/dist/acorn') +const tt = acorn.tokTypes +const privateClassElements = require('internal/deps/acorn-plugins/acorn-private-class-elements/index') + +function maybeParseFieldValue(field) { + if (this.eat(tt.eq)) { + const oldInFieldValue = this._inFieldValue + this._inFieldValue = true + field.value = this.parseExpression() + this._inFieldValue = oldInFieldValue + } else field.value = null +} + +module.exports = function(Parser) { + Parser = privateClassElements(Parser) + return class extends Parser { + // Parse fields + parseClassElement(_constructorAllowsSuper) { + if (this.options.ecmaVersion >= 8 && (this.type == tt.name || this.type == this.privateNameToken || this.type == tt.bracketL || this.type == tt.string)) { + const branch = this._branch() + if (branch.type == tt.bracketL) { + let count = 0 + do { + if (branch.eat(tt.bracketL)) ++count + else if (branch.eat(tt.bracketR)) --count + else branch.next() + } while (count > 0) + } else branch.next() + if (branch.type == tt.eq || branch.canInsertSemicolon() || branch.type == tt.semi) { + const node = this.startNode() + if (this.type == this.privateNameToken) { + this.parsePrivateClassElementName(node) + } else { + this.parsePropertyName(node) + } + if ((node.key.type === "Identifier" && node.key.name === "constructor") || + (node.key.type === "Literal" && node.key.value === "constructor")) { + this.raise(node.key.start, "Classes may not have a field called constructor") + } + maybeParseFieldValue.call(this, node) + this.finishNode(node, "FieldDefinition") + this.semicolon() + return node + } + } + + return super.parseClassElement.apply(this, arguments) + } + + // Prohibit arguments in class field initializers + parseIdent(liberal, isBinding) { + const ident = super.parseIdent(liberal, isBinding) + if (this._inFieldValue && ident.name == "arguments") this.raise(ident.start, "A class field initializer may not contain arguments") + return ident + } + } +} diff --git a/deps/acorn-plugins/acorn-class-fields/package.json b/deps/acorn-plugins/acorn-class-fields/package.json new file mode 100644 index 00000000000000..4df166ba19fa4a --- /dev/null +++ b/deps/acorn-plugins/acorn-class-fields/package.json @@ -0,0 +1,68 @@ +{ + "_from": "acorn-class-fields", + "_id": "acorn-class-fields@0.3.1", + "_inBundle": false, + "_integrity": "sha512-X/8hSJuregAnrvfV1Y80VJNfeJx1uhw7yskOwvL631ygYeCGVLPumCnnPDHYZ8acV3ytHhg53K171H3tAemgiw==", + "_location": "/acorn-class-fields", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "acorn-class-fields", + "name": "acorn-class-fields", + "escapedName": "acorn-class-fields", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/acorn-class-fields/-/acorn-class-fields-0.3.1.tgz", + "_shasum": "032ce47a9688a71d4713ee366fadcb7fefaea9e0", + "_spec": "acorn-class-fields", + "_where": "/home/ruben/repos/node/node", + "bugs": { + "url": "https://github.com/acornjs/acorn-class-fields/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Adrian Heine", + "email": "mail@adrianheine.de" + } + ], + "dependencies": { + "acorn-private-class-elements": "^0.1.1" + }, + "deprecated": false, + "description": "Support for class fields in acorn", + "devDependencies": { + "acorn": "^6.1.0", + "eslint": "^5.13.0", + "eslint-plugin-node": "^8.0.1", + "mocha": "^5.2.0", + "test262": "git+https://github.com/tc39/test262.git#33a306d1026b72227eb50a918db19ada16f12b3d", + "test262-parser-runner": "^0.5.0" + }, + "engines": { + "node": ">=4.8.2" + }, + "homepage": "https://github.com/acornjs/acorn-class-fields", + "license": "MIT", + "name": "acorn-class-fields", + "peerDependencies": { + "acorn": "^6.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acornjs/acorn-class-fields.git" + }, + "scripts": { + "lint": "eslint -c .eslintrc.json .", + "test": "mocha", + "test:test262": "node run_test262.js" + }, + "version": "0.3.1" +} diff --git a/deps/acorn-plugins/acorn-numeric-separator/CHANGELOG.md b/deps/acorn-plugins/acorn-numeric-separator/CHANGELOG.md new file mode 100644 index 00000000000000..dfe8e3ea9dedb8 --- /dev/null +++ b/deps/acorn-plugins/acorn-numeric-separator/CHANGELOG.md @@ -0,0 +1,16 @@ +## 0.3.0 (2019-04-04) + +* Make compatible with acorn-bigint + +## 0.2.0 (2018-09-14) + +* Update to new acorn 6 interface +* Change license to MIT + +## 0.1.1 (2018-01-16) + +* Don't bail on empty integers as in `1.` + +## 0.1.0 (2017-12-19) + +Initial release diff --git a/deps/acorn-plugins/acorn-numeric-separator/LICENSE b/deps/acorn-plugins/acorn-numeric-separator/LICENSE new file mode 100644 index 00000000000000..7c2b27a19c033c --- /dev/null +++ b/deps/acorn-plugins/acorn-numeric-separator/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2017-2018 by Adrian Heine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/deps/acorn-plugins/acorn-numeric-separator/README.md b/deps/acorn-plugins/acorn-numeric-separator/README.md new file mode 100644 index 00000000000000..27188572d1bf40 --- /dev/null +++ b/deps/acorn-plugins/acorn-numeric-separator/README.md @@ -0,0 +1,21 @@ +# Numeric separator support for Acorn + +[![NPM version](https://img.shields.io/npm/v/acorn-numeric-separator.svg)](https://www.npmjs.org/package/acorn-numeric-separator) + +This is a plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript. + +It implements support for numeric separators as defined in the stage 3 proposal [Numeric Separators](https://github.com/tc39/proposal-numeric-separator). + +## Usage + +This module provides a plugin that can be used to extend the Acorn `Parser` class to parse numeric separators: + +```javascript +var acorn = require('acorn'); +var numericSeparator = require('acorn-numeric-separator'); +acorn.Parser.extend(numericSeparator).parse('100_000'); +``` + +## License + +This plugin is released under an [MIT License](./LICENSE). diff --git a/deps/acorn-plugins/acorn-numeric-separator/index.js b/deps/acorn-plugins/acorn-numeric-separator/index.js new file mode 100644 index 00000000000000..52f207cfd8d454 --- /dev/null +++ b/deps/acorn-plugins/acorn-numeric-separator/index.js @@ -0,0 +1,49 @@ +"use strict" + +module.exports = function(Parser) { + return class extends Parser { + readInt(radix, len) { + // Hack: len is only != null for unicode escape sequences, + // where numeric separators are not allowed + if (len != null) return super.readInt(radix, len) + + let start = this.pos, total = 0, acceptUnderscore = false + for (;;) { + let code = this.input.charCodeAt(this.pos), val + if (code >= 97) val = code - 97 + 10 // a + else if (code == 95) { + if (!acceptUnderscore) this.raise(this.pos, "Invalid numeric separator") + ++this.pos + acceptUnderscore = false + continue + } else if (code >= 65) val = code - 65 + 10 // A + else if (code >= 48 && code <= 57) val = code - 48 // 0-9 + else val = Infinity + if (val >= radix) break + ++this.pos + total = total * radix + val + acceptUnderscore = true + } + if (this.pos === start) return null + if (!acceptUnderscore) this.raise(this.pos - 1, "Invalid numeric separator") + + return total + } + + readNumber(startsWithDot) { + const token = super.readNumber(startsWithDot) + let octal = this.end - this.start >= 2 && this.input.charCodeAt(this.start) === 48 + const stripped = this.getNumberInput(this.start, this.end) + if (stripped.length < this.end - this.start) { + if (octal) this.raise(this.start, "Invalid number") + this.value = parseFloat(stripped) + } + return token + } + + // This is used by acorn-bigint + getNumberInput(start, end) { + return this.input.slice(start, end).replace(/_/g, "") + } + } +} diff --git a/deps/acorn-plugins/acorn-numeric-separator/package.json b/deps/acorn-plugins/acorn-numeric-separator/package.json new file mode 100644 index 00000000000000..bf3615e6b7e7ea --- /dev/null +++ b/deps/acorn-plugins/acorn-numeric-separator/package.json @@ -0,0 +1,65 @@ +{ + "_from": "acorn-numeric-separator", + "_id": "acorn-numeric-separator@0.3.0", + "_inBundle": false, + "_integrity": "sha512-g9FikQZHwG/P1Xs+dDzecqagmGBbU4b8OF4UbDQK8Wr8apwuFGG1c7KiaFxC4ClYU8D7zNl60vzqOCUuhKM3kA==", + "_location": "/acorn-numeric-separator", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "acorn-numeric-separator", + "name": "acorn-numeric-separator", + "escapedName": "acorn-numeric-separator", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/acorn-numeric-separator/-/acorn-numeric-separator-0.3.0.tgz", + "_shasum": "15e2f9a698bbec83a339a70a7026ab1d9d257de2", + "_spec": "acorn-numeric-separator", + "_where": "/home/ruben/repos/node/node", + "bugs": { + "url": "https://github.com/acornjs/acorn-numeric-separator/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Adrian Heine", + "email": "mail@adrianheine.de" + } + ], + "deprecated": false, + "description": "Support for numeric separators in acorn", + "devDependencies": { + "acorn": "^6.0.0", + "eslint": "^5.5.0", + "eslint-plugin-node": "^8.0.1", + "mocha": "^6.0.2", + "test262": "git+https://github.com/tc39/test262.git#de567d3aa5de4eaa11e00131d26b9fe77997dfb0", + "test262-parser-runner": "^0.5.0" + }, + "engines": { + "node": ">=4.8.2" + }, + "homepage": "https://github.com/acornjs/acorn-numeric-separator", + "license": "MIT", + "name": "acorn-numeric-separator", + "peerDependencies": { + "acorn": "^6.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acornjs/acorn-numeric-separator.git" + }, + "scripts": { + "lint": "eslint -c .eslintrc.json .", + "test": "mocha", + "test:test262": "node run_test262.js" + }, + "version": "0.3.0" +} diff --git a/deps/acorn-plugins/acorn-private-class-elements/CHANGELOG.md b/deps/acorn-plugins/acorn-private-class-elements/CHANGELOG.md new file mode 100644 index 00000000000000..5b49344b7ac5b6 --- /dev/null +++ b/deps/acorn-plugins/acorn-private-class-elements/CHANGELOG.md @@ -0,0 +1,7 @@ +## 0.1.1 (2019-02-09) + +* Add \_branch() method + +## 0.1.0 (2019-02-09) + +Initial release diff --git a/deps/acorn-plugins/acorn-private-class-elements/LICENSE b/deps/acorn-plugins/acorn-private-class-elements/LICENSE new file mode 100644 index 00000000000000..7c2b27a19c033c --- /dev/null +++ b/deps/acorn-plugins/acorn-private-class-elements/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2017-2018 by Adrian Heine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/deps/acorn-plugins/acorn-private-class-elements/README.md b/deps/acorn-plugins/acorn-private-class-elements/README.md new file mode 100644 index 00000000000000..0d228820cd1d01 --- /dev/null +++ b/deps/acorn-plugins/acorn-private-class-elements/README.md @@ -0,0 +1,11 @@ +# Helpers for supporting private class methods and fields for Acorn + +[![NPM version](https://img.shields.io/npm/v/acorn-private-class-elements.svg)](https://www.npmjs.org/package/acorn-private-class-elements) + +This is a plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript. + +It provides helpers for implementing support for private class elements. The emitted AST follows [an ESTree proposal](https://github.com/estree/estree/pull/180). + +## License + +This plugin is released under an [MIT License](./LICENSE). diff --git a/deps/acorn-plugins/acorn-private-class-elements/index.js b/deps/acorn-plugins/acorn-private-class-elements/index.js new file mode 100644 index 00000000000000..90f2b704371c9f --- /dev/null +++ b/deps/acorn-plugins/acorn-private-class-elements/index.js @@ -0,0 +1,123 @@ +"use strict" + +const acorn = require('internal/deps/acorn/acorn/dist/acorn') +if (acorn.version.indexOf("6.") != 0 || acorn.version.indexOf("6.0.") == 0) { + throw new Error(`acorn-private-class-elements requires acorn@^6.1.0, not ${acorn.version}`) +} +const tt = acorn.tokTypes +const TokenType = acorn.TokenType + +module.exports = function(Parser) { + // Only load this plugin once. + if (Parser.prototype.parsePrivateName) { + return Parser + } + + // Make sure `Parser` comes from the same acorn as our `tt`, + // otherwise the comparisons fail. + let cur = Parser + while (cur && cur !== acorn.Parser) { + cur = cur.__proto__ + } + if (cur !== acorn.Parser) { + throw new Error("acorn-private-class-elements does not support mixing different acorn copies") + } + + Parser = class extends Parser { + _branch() { + this.__branch = this.__branch || new Parser({ecmaVersion: this.options.ecmaVersion}, this.input) + this.__branch.end = this.end + this.__branch.pos = this.pos + this.__branch.type = this.type + this.__branch.value = this.value + this.__branch.containsEsc = this.containsEsc + return this.__branch + } + + parsePrivateClassElementName(element) { + element.computed = false + element.key = this.parsePrivateName() + if (element.key.name == "constructor") this.raise(element.key.start, "Classes may not have a private element named constructor") + const accept = {get: "set", set: "get"}[element.kind] + const privateBoundNames = this._privateBoundNamesStack[this._privateBoundNamesStack.length - 1] + if (Object.prototype.hasOwnProperty.call(privateBoundNames, element.key.name) && privateBoundNames[element.key.name] !== accept) { + this.raise(element.start, "Duplicate private element") + } + privateBoundNames[element.key.name] = element.kind || true + delete this._unresolvedPrivateNamesStack[this._unresolvedPrivateNamesStack.length - 1][element.key.name] + return element.key + } + + parsePrivateName() { + const node = this.startNode() + node.name = this.value + this.next() + this.finishNode(node, "PrivateName") + if (this.options.allowReserved == "never") this.checkUnreserved(node) + return node + } + + // Parse # token + getTokenFromCode(code) { + if (code === 35) { + ++this.pos + const word = this.readWord1() + return this.finishToken(this.privateNameToken, word) + } + return super.getTokenFromCode(code) + } + + // Manage stacks and check for undeclared private names + parseClass(node, isStatement) { + this._privateBoundNamesStack = this._privateBoundNamesStack || [] + const privateBoundNames = Object.create(this._privateBoundNamesStack[this._privateBoundNamesStack.length - 1] || null) + this._privateBoundNamesStack.push(privateBoundNames) + this._unresolvedPrivateNamesStack = this._unresolvedPrivateNamesStack || [] + const unresolvedPrivateNames = Object.create(null) + this._unresolvedPrivateNamesStack.push(unresolvedPrivateNames) + const _return = super.parseClass(node, isStatement) + this._privateBoundNamesStack.pop() + this._unresolvedPrivateNamesStack.pop() + if (!this._unresolvedPrivateNamesStack.length) { + const names = Object.keys(unresolvedPrivateNames) + if (names.length) { + names.sort((n1, n2) => unresolvedPrivateNames[n1] - unresolvedPrivateNames[n2]) + this.raise(unresolvedPrivateNames[names[0]], "Usage of undeclared private name") + } + } else Object.assign(this._unresolvedPrivateNamesStack[this._unresolvedPrivateNamesStack.length - 1], unresolvedPrivateNames) + return _return + } + + // Parse private element access + parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow) { + if (!this.eat(tt.dot)) { + return super.parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow) + } + let node = this.startNodeAt(startPos, startLoc) + node.object = base + node.computed = false + if (this.type == this.privateNameToken) { + node.property = this.parsePrivateName() + if (!this._privateBoundNamesStack.length || !this._privateBoundNamesStack[this._privateBoundNamesStack.length - 1][node.property.name]) { + this._unresolvedPrivateNamesStack[this._unresolvedPrivateNamesStack.length - 1][node.property.name] = node.property.start + } + } else { + node.property = this.parseIdent(true) + } + return this.finishNode(node, "MemberExpression") + } + + // Prohibit delete of private class elements + parseMaybeUnary(refDestructuringErrors, sawUnary) { + const _return = super.parseMaybeUnary(refDestructuringErrors, sawUnary) + if (_return.operator == "delete") { + if (_return.argument.type == "MemberExpression" && _return.argument.property.type == "PrivateName") { + this.raise(_return.start, "Private elements may not be deleted") + } + } + return _return + } + } + Parser.prototype.privateNameToken = new TokenType("privateName") + return Parser +} diff --git a/deps/acorn-plugins/acorn-private-class-elements/package.json b/deps/acorn-plugins/acorn-private-class-elements/package.json new file mode 100644 index 00000000000000..cd43012dc79884 --- /dev/null +++ b/deps/acorn-plugins/acorn-private-class-elements/package.json @@ -0,0 +1,63 @@ +{ + "_from": "acorn-private-class-elements@^0.1.1", + "_id": "acorn-private-class-elements@0.1.1", + "_inBundle": false, + "_integrity": "sha512-bZpmSnaOsK3jkF7J8xaLJ05f008vapPX+XliIv8+jjkclvDR+M4OnTHLhFnCCSeJ0fMwRKjbY+BXsglSNpVZtw==", + "_location": "/acorn-private-class-elements", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "acorn-private-class-elements@^0.1.1", + "name": "acorn-private-class-elements", + "escapedName": "acorn-private-class-elements", + "rawSpec": "^0.1.1", + "saveSpec": null, + "fetchSpec": "^0.1.1" + }, + "_requiredBy": [ + "/acorn-class-fields" + ], + "_resolved": "https://registry.npmjs.org/acorn-private-class-elements/-/acorn-private-class-elements-0.1.1.tgz", + "_shasum": "85209cb5791ab84fde2362cb208fa51e7679bcdc", + "_spec": "acorn-private-class-elements@^0.1.1", + "_where": "/home/ruben/repos/node/node/node_modules/acorn-class-fields", + "bugs": { + "url": "https://github.com/acornjs/acorn-private-class-elements/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Adrian Heine", + "email": "mail@adrianheine.de" + } + ], + "dependencies": { + "mocha": "^5.2.0" + }, + "deprecated": false, + "description": "Helpers for supporting private class methods and fields in acorn", + "devDependencies": { + "acorn": "^6.1.0", + "eslint": "^5.13.0", + "eslint-plugin-node": "^8.0.1" + }, + "engines": { + "node": ">=4.8.2" + }, + "homepage": "https://github.com/acornjs/acorn-private-class-elements", + "license": "MIT", + "name": "acorn-private-class-elements", + "peerDependencies": { + "acorn": "^6.1.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acornjs/acorn-private-class-elements.git" + }, + "scripts": { + "lint": "eslint -c .eslintrc.json .", + "test": "mocha" + }, + "version": "0.1.1" +} diff --git a/deps/acorn-plugins/acorn-private-methods/CHANGELOG.md b/deps/acorn-plugins/acorn-private-methods/CHANGELOG.md new file mode 100644 index 00000000000000..5de4b97b8111b0 --- /dev/null +++ b/deps/acorn-plugins/acorn-private-methods/CHANGELOG.md @@ -0,0 +1,29 @@ +## 0.3.0 (2019-02-09) + +* Require acorn >= 6.1.0 + +## 0.2.3 (2019-02-09) + +* Forbid binding await in async arrow function's parameter list + +## 0.2.2 (2019-01-30) + +* Fix parsing of chained subscripts + +## 0.2.1 (2018-11-06) + +* Adapt to changes in acorn 6.0.3 + +## 0.2.0 (2018-09-14) + +* Update to new acorn 6 interface +* Change license to MIT +* Don't allow direct super() calls in private methods + +## 0.1.1 (2018-02-09) + +* Don't accept whitespace between hash and private name + +## 0.1.0 (2018-01-13) + +Initial release diff --git a/deps/acorn-plugins/acorn-private-methods/LICENSE b/deps/acorn-plugins/acorn-private-methods/LICENSE new file mode 100644 index 00000000000000..7c2b27a19c033c --- /dev/null +++ b/deps/acorn-plugins/acorn-private-methods/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2017-2018 by Adrian Heine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/deps/acorn-plugins/acorn-private-methods/README.md b/deps/acorn-plugins/acorn-private-methods/README.md new file mode 100644 index 00000000000000..6929e84ba620a8 --- /dev/null +++ b/deps/acorn-plugins/acorn-private-methods/README.md @@ -0,0 +1,21 @@ +# Private methods and getter/setters support for Acorn + +[![NPM version](https://img.shields.io/npm/v/acorn-private-methods.svg)](https://www.npmjs.org/package/acorn-private-methods) + +This is a plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript. + +It implements support for private methods, getters and setters as defined in the stage 3 proposal [Private methods and getter/setters for JavaScript classes](https://github.com/tc39/proposal-private-methods). The emitted AST follows [an ESTree proposal](https://github.com/estree/estree/pull/180). + +## Usage + +This module provides a plugin that can be used to extend the Acorn `Parser` class: + +```javascript +const {Parser} = require('acorn'); +const privateMethods = require('acorn-private-methods'); +Parser.extend(privateMethods).parse('class X { #a() {} }'); +``` + +## License + +This plugin is released under an [MIT License](./LICENSE). diff --git a/deps/acorn-plugins/acorn-private-methods/index.js b/deps/acorn-plugins/acorn-private-methods/index.js new file mode 100644 index 00000000000000..a2964251680565 --- /dev/null +++ b/deps/acorn-plugins/acorn-private-methods/index.js @@ -0,0 +1,25 @@ +"use strict" + +const privateClassElements = require('internal/deps/acorn-plugins/acorn-private-class-elements/index') + +module.exports = function(Parser) { + const ExtendedParser = privateClassElements(Parser) + + return class extends ExtendedParser { + // Parse private methods + parseClassElement(_constructorAllowsSuper) { + const oldInClassMemberName = this._inClassMemberName + this._inClassMemberName = true + const result = super.parseClassElement.apply(this, arguments) + this._inClassMemberName = oldInClassMemberName + return result + } + + parsePropertyName(prop) { + const isPrivate = this.options.ecmaVersion >= 8 && this._inClassMemberName && this.type == this.privateNameToken + this._inClassMemberName = false + if (!isPrivate) return super.parsePropertyName(prop) + return this.parsePrivateClassElementName(prop) + } + } +} diff --git a/deps/acorn-plugins/acorn-private-methods/package.json b/deps/acorn-plugins/acorn-private-methods/package.json new file mode 100644 index 00000000000000..d25c611316019f --- /dev/null +++ b/deps/acorn-plugins/acorn-private-methods/package.json @@ -0,0 +1,68 @@ +{ + "_from": "acorn-private-methods", + "_id": "acorn-private-methods@0.3.0", + "_inBundle": false, + "_integrity": "sha512-+gWTjSA+13lsv1mwCPosSrLzEyghYtWgrr/1Ck7i7Pu5iK7Ke0hOgw3IW1RUxhc4qS2QTQBQx2+qHYqsa4Qlqw==", + "_location": "/acorn-private-methods", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "acorn-private-methods", + "name": "acorn-private-methods", + "escapedName": "acorn-private-methods", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/acorn-private-methods/-/acorn-private-methods-0.3.0.tgz", + "_shasum": "a5a9f8cd83d175bc138fa22592fababd0afda35d", + "_spec": "acorn-private-methods", + "_where": "/home/ruben/repos/node/node", + "bugs": { + "url": "https://github.com/acornjs/acorn-private-methods/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Adrian Heine", + "email": "mail@adrianheine.de" + } + ], + "dependencies": { + "acorn-private-class-elements": "^0.1.0" + }, + "deprecated": false, + "description": "Support for private methods in acorn", + "devDependencies": { + "acorn": "^6.1.0", + "eslint": "^5.13.0", + "eslint-plugin-node": "^8.0.1", + "mocha": "^5.2.0", + "test262": "git+https://github.com/tc39/test262.git#33a306d1026b72227eb50a918db19ada16f12b3d", + "test262-parser-runner": "^0.5.0" + }, + "engines": { + "node": ">=4.8.2" + }, + "homepage": "https://github.com/acornjs/acorn-private-methods", + "license": "MIT", + "name": "acorn-private-methods", + "peerDependencies": { + "acorn": "^6.1.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acornjs/acorn-private-methods.git" + }, + "scripts": { + "lint": "eslint -c .eslintrc.json .", + "test": "mocha", + "test:test262": "node run_test262.js" + }, + "version": "0.3.0" +} diff --git a/deps/acorn-plugins/acorn-static-class-features/CHANGELOG.md b/deps/acorn-plugins/acorn-static-class-features/CHANGELOG.md new file mode 100644 index 00000000000000..b9896a4bc5a45e --- /dev/null +++ b/deps/acorn-plugins/acorn-static-class-features/CHANGELOG.md @@ -0,0 +1,11 @@ +## 0.2.0 (2019-02-09) + +* Require acorn >= 6.1.0 + +## 0.1.1 (2018-11-06) + +* Adapt to changes in acorn 6.0.3 + +## 0.1.0 (2018-09-14) + +Initial release diff --git a/deps/acorn-plugins/acorn-static-class-features/LICENSE b/deps/acorn-plugins/acorn-static-class-features/LICENSE new file mode 100644 index 00000000000000..7c2b27a19c033c --- /dev/null +++ b/deps/acorn-plugins/acorn-static-class-features/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2017-2018 by Adrian Heine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/deps/acorn-plugins/acorn-static-class-features/README.md b/deps/acorn-plugins/acorn-static-class-features/README.md new file mode 100644 index 00000000000000..bb214fce164a1a --- /dev/null +++ b/deps/acorn-plugins/acorn-static-class-features/README.md @@ -0,0 +1,21 @@ +# Static class features support for Acorn + +[![NPM version](https://img.shields.io/npm/v/acorn-class-fields.svg)](https://www.npmjs.org/package/acorn-static-class-features) + +This is a plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript. + +It implements support for static class features as defined in the stage 3 proposal [Static class features](https://github.com/tc39/proposal-static-class-features). The emitted AST follows [an ESTree proposal](https://github.com/estree/estree/pull/180). + +## Usage + +This module provides a plugin that can be used to extend the Acorn `Parser` class: + +```javascript +const {Parser} = require('acorn'); +const staticClassFeatures = require('acorn-static-class-features'); +Parser.extend(staticClassFeatures).parse('class X { static x = 0 }'); +``` + +## License + +This plugin is released under an [MIT License](./LICENSE). diff --git a/deps/acorn-plugins/acorn-static-class-features/index.js b/deps/acorn-plugins/acorn-static-class-features/index.js new file mode 100644 index 00000000000000..d8954bf3275e0e --- /dev/null +++ b/deps/acorn-plugins/acorn-static-class-features/index.js @@ -0,0 +1,126 @@ +"use strict" + +const skipWhiteSpace = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g + +const acorn = require('internal/deps/acorn/acorn/dist/acorn') +const tt = acorn.tokTypes + +function maybeParseFieldValue(field) { + if (this.eat(tt.eq)) { + const oldInFieldValue = this._inStaticFieldValue + this._inStaticFieldValue = true + field.value = this.parseExpression() + this._inStaticFieldValue = oldInFieldValue + } else field.value = null +} + +const privateClassElements = require("internal/deps/acorn-plugins/acorn-private-class-elements/index") + +module.exports = function(Parser) { + const ExtendedParser = privateClassElements(Parser) + + return class extends ExtendedParser { + // Parse private fields + parseClassElement(_constructorAllowsSuper) { + if (this.eat(tt.semi)) return null + + const node = this.startNode() + + const tryContextual = (k, noLineBreak) => { + if (typeof noLineBreak == "undefined") noLineBreak = false + const start = this.start, startLoc = this.startLoc + if (!this.eatContextual(k)) return false + if (this.type !== tt.parenL && (!noLineBreak || !this.canInsertSemicolon())) return true + if (node.key) this.unexpected() + node.computed = false + node.key = this.startNodeAt(start, startLoc) + node.key.name = k + this.finishNode(node.key, "Identifier") + return false + } + + node.static = tryContextual("static") + if (!node.static) return super.parseClassElement.apply(this, arguments) + + let isGenerator = this.eat(tt.star) + let isAsync = false + if (!isGenerator) { + // Special-case for `async`, since `parseClassMember` currently looks + // for `(` to determine whether `async` is a method name + if (this.options.ecmaVersion >= 8 && this.isContextual("async")) { + skipWhiteSpace.lastIndex = this.pos + let skip = skipWhiteSpace.exec(this.input) + let next = this.input.charAt(this.pos + skip[0].length) + if (next === ";" || next === "=") { + node.key = this.parseIdent(true) + node.computed = false + maybeParseFieldValue.call(this, node) + this.finishNode(node, "FieldDefinition") + this.semicolon() + return node + } else if (this.options.ecmaVersion >= 8 && tryContextual("async", true)) { + isAsync = true + isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star) + } + } else if (tryContextual("get")) { + node.kind = "get" + } else if (tryContextual("set")) { + node.kind = "set" + } + } + if (this.type === this.privateNameToken) { + this.parsePrivateClassElementName(node) + if (this.type !== tt.parenL) { + if (node.key.name === "prototype") { + this.raise(node.key.start, "Classes may not have a private static property named prototype") + } + maybeParseFieldValue.call(this, node) + this.finishNode(node, "FieldDefinition") + this.semicolon() + return node + } + } else if (!node.key) { + this.parsePropertyName(node) + if ((node.key.name || node.key.value) === "prototype" && !node.computed) { + this.raise(node.key.start, "Classes may not have a static property named prototype") + } + } + if (!node.kind) node.kind = "method" + this.parseClassMethod(node, isGenerator, isAsync) + if (!node.kind && (node.key.name || node.key.value) === "constructor" && !node.computed) { + this.raise(node.key.start, "Classes may not have a static field named constructor") + } + if (node.kind === "get" && node.value.params.length !== 0) { + this.raiseRecoverable(node.value.start, "getter should have no params") + } + if (node.kind === "set" && node.value.params.length !== 1) { + this.raiseRecoverable(node.value.start, "setter should have exactly one param") + } + if (node.kind === "set" && node.value.params[0].type === "RestElement") { + this.raiseRecoverable(node.value.params[0].start, "Setter cannot use rest params") + } + + return node + + } + + // Parse public static fields + parseClassMethod(method, isGenerator, isAsync, _allowsDirectSuper) { + if (isGenerator || isAsync || method.kind != "method" || !method.static || this.options.ecmaVersion < 8 || this.type == tt.parenL) { + return super.parseClassMethod.apply(this, arguments) + } + maybeParseFieldValue.call(this, method) + delete method.kind + method = this.finishNode(method, "FieldDefinition") + this.semicolon() + return method + } + + // Prohibit arguments in class field initializers + parseIdent(liberal, isBinding) { + const ident = super.parseIdent(liberal, isBinding) + if (this._inStaticFieldValue && ident.name == "arguments") this.raise(ident.start, "A static class field initializer may not contain arguments") + return ident + } + } +} diff --git a/deps/acorn-plugins/acorn-static-class-features/package.json b/deps/acorn-plugins/acorn-static-class-features/package.json new file mode 100644 index 00000000000000..ff9ff30c05911b --- /dev/null +++ b/deps/acorn-plugins/acorn-static-class-features/package.json @@ -0,0 +1,68 @@ +{ + "_from": "acorn-static-class-features", + "_id": "acorn-static-class-features@0.2.0", + "_inBundle": false, + "_integrity": "sha512-46IooHSRsvgSi+t36Wx9iPfF9BKFKVDcAWELXVqvKHmZogSCk11iUCi2FiZmLeTaM0hlJ3EYDyYiVmHRUGPzWA==", + "_location": "/acorn-static-class-features", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "acorn-static-class-features", + "name": "acorn-static-class-features", + "escapedName": "acorn-static-class-features", + "rawSpec": "", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/acorn-static-class-features/-/acorn-static-class-features-0.2.0.tgz", + "_shasum": "8a12b0b280b2e067e268fdbb14116a5b02affd71", + "_spec": "acorn-static-class-features", + "_where": "/home/ruben/repos/node/node", + "bugs": { + "url": "https://github.com/acornjs/acorn-static-class-features/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Adrian Heine", + "email": "mail@adrianheine.de" + } + ], + "dependencies": { + "acorn-private-class-elements": "^0.1.0" + }, + "deprecated": false, + "description": "Support for static class features in acorn", + "devDependencies": { + "acorn": "^6.1.0", + "eslint": "^5.13.0", + "eslint-plugin-node": "^8.0.1", + "mocha": "^5.2.0", + "test262": "git+https://github.com/tc39/test262.git#33a306d1026b72227eb50a918db19ada16f12b3d", + "test262-parser-runner": "^0.5.0" + }, + "engines": { + "node": ">=4.8.2" + }, + "homepage": "https://github.com/acornjs/acorn-static-class-features", + "license": "MIT", + "name": "acorn-static-class-features", + "peerDependencies": { + "acorn": "^6.1.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acornjs/acorn-static-class-features.git" + }, + "scripts": { + "lint": "eslint -c .eslintrc.json .", + "test": "mocha", + "test:test262": "node run_test262.js" + }, + "version": "0.2.0" +} diff --git a/deps/acorn/acorn-walk/dist/walk.js.map b/deps/acorn/acorn-walk/dist/walk.js.map deleted file mode 100644 index 5590a2924f2de6..00000000000000 --- a/deps/acorn/acorn-walk/dist/walk.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"walk.js","sources":["../src/index.js"],"sourcesContent":["// AST walker module for Mozilla Parser API compatible trees\n\n// A simple walk is one where you simply specify callbacks to be\n// called on specific nodes. The last two arguments are optional. A\n// simple use would be\n//\n// walk.simple(myTree, {\n// Expression: function(node) { ... }\n// });\n//\n// to do something with all expressions. All Parser API node types\n// can be used to identify node types, as well as Expression and\n// Statement, which denote categories of nodes.\n//\n// The base argument can be used to pass a custom (recursive)\n// walker, and state can be used to give this walked an initial\n// state.\n\nexport function simple(node, visitors, baseVisitor, state, override) {\n if (!baseVisitor) baseVisitor = base\n ;(function c(node, st, override) {\n let type = override || node.type, found = visitors[type]\n baseVisitor[type](node, st, c)\n if (found) found(node, st)\n })(node, state, override)\n}\n\n// An ancestor walk keeps an array of ancestor nodes (including the\n// current node) and passes them to the callback as third parameter\n// (and also as state parameter when no other state is present).\nexport function ancestor(node, visitors, baseVisitor, state) {\n let ancestors = []\n if (!baseVisitor) baseVisitor = base\n ;(function c(node, st, override) {\n let type = override || node.type, found = visitors[type]\n let isNew = node !== ancestors[ancestors.length - 1]\n if (isNew) ancestors.push(node)\n baseVisitor[type](node, st, c)\n if (found) found(node, st || ancestors, ancestors)\n if (isNew) ancestors.pop()\n })(node, state)\n}\n\n// A recursive walk is one where your functions override the default\n// walkers. They can modify and replace the state parameter that's\n// threaded through the walk, and can opt how and whether to walk\n// their child nodes (by calling their third argument on these\n// nodes).\nexport function recursive(node, state, funcs, baseVisitor, override) {\n let visitor = funcs ? make(funcs, baseVisitor || undefined) : baseVisitor\n ;(function c(node, st, override) {\n visitor[override || node.type](node, st, c)\n })(node, state, override)\n}\n\nfunction makeTest(test) {\n if (typeof test === \"string\")\n return type => type === test\n else if (!test)\n return () => true\n else\n return test\n}\n\nclass Found {\n constructor(node, state) { this.node = node; this.state = state }\n}\n\n// A full walk triggers the callback on each node\nexport function full(node, callback, baseVisitor, state, override) {\n if (!baseVisitor) baseVisitor = base\n ;(function c(node, st, override) {\n let type = override || node.type\n baseVisitor[type](node, st, c)\n if (!override) callback(node, st, type)\n })(node, state, override)\n}\n\n// An fullAncestor walk is like an ancestor walk, but triggers\n// the callback on each node\nexport function fullAncestor(node, callback, baseVisitor, state) {\n if (!baseVisitor) baseVisitor = base\n let ancestors = []\n ;(function c(node, st, override) {\n let type = override || node.type\n let isNew = node !== ancestors[ancestors.length - 1]\n if (isNew) ancestors.push(node)\n baseVisitor[type](node, st, c)\n if (!override) callback(node, st || ancestors, ancestors, type)\n if (isNew) ancestors.pop()\n })(node, state)\n}\n\n// Find a node with a given start, end, and type (all are optional,\n// null can be used as wildcard). Returns a {node, state} object, or\n// undefined when it doesn't find a matching node.\nexport function findNodeAt(node, start, end, test, baseVisitor, state) {\n if (!baseVisitor) baseVisitor = base\n test = makeTest(test)\n try {\n (function c(node, st, override) {\n let type = override || node.type\n if ((start == null || node.start <= start) &&\n (end == null || node.end >= end))\n baseVisitor[type](node, st, c)\n if ((start == null || node.start === start) &&\n (end == null || node.end === end) &&\n test(type, node))\n throw new Found(node, st)\n })(node, state)\n } catch (e) {\n if (e instanceof Found) return e\n throw e\n }\n}\n\n// Find the innermost node of a given type that contains the given\n// position. Interface similar to findNodeAt.\nexport function findNodeAround(node, pos, test, baseVisitor, state) {\n test = makeTest(test)\n if (!baseVisitor) baseVisitor = base\n try {\n (function c(node, st, override) {\n let type = override || node.type\n if (node.start > pos || node.end < pos) return\n baseVisitor[type](node, st, c)\n if (test(type, node)) throw new Found(node, st)\n })(node, state)\n } catch (e) {\n if (e instanceof Found) return e\n throw e\n }\n}\n\n// Find the outermost matching node after a given position.\nexport function findNodeAfter(node, pos, test, baseVisitor, state) {\n test = makeTest(test)\n if (!baseVisitor) baseVisitor = base\n try {\n (function c(node, st, override) {\n if (node.end < pos) return\n let type = override || node.type\n if (node.start >= pos && test(type, node)) throw new Found(node, st)\n baseVisitor[type](node, st, c)\n })(node, state)\n } catch (e) {\n if (e instanceof Found) return e\n throw e\n }\n}\n\n// Find the outermost matching node before a given position.\nexport function findNodeBefore(node, pos, test, baseVisitor, state) {\n test = makeTest(test)\n if (!baseVisitor) baseVisitor = base\n let max\n ;(function c(node, st, override) {\n if (node.start > pos) return\n let type = override || node.type\n if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))\n max = new Found(node, st)\n baseVisitor[type](node, st, c)\n })(node, state)\n return max\n}\n\n// Fallback to an Object.create polyfill for older environments.\nconst create = Object.create || function(proto) {\n function Ctor() {}\n Ctor.prototype = proto\n return new Ctor\n}\n\n// Used to create a custom walker. Will fill in all missing node\n// type properties with the defaults.\nexport function make(funcs, baseVisitor) {\n let visitor = create(baseVisitor || base)\n for (let type in funcs) visitor[type] = funcs[type]\n return visitor\n}\n\nfunction skipThrough(node, st, c) { c(node, st) }\nfunction ignore(_node, _st, _c) {}\n\n// Node walkers.\n\nexport const base = {}\n\nbase.Program = base.BlockStatement = (node, st, c) => {\n for (let stmt of node.body)\n c(stmt, st, \"Statement\")\n}\nbase.Statement = skipThrough\nbase.EmptyStatement = ignore\nbase.ExpressionStatement = base.ParenthesizedExpression =\n (node, st, c) => c(node.expression, st, \"Expression\")\nbase.IfStatement = (node, st, c) => {\n c(node.test, st, \"Expression\")\n c(node.consequent, st, \"Statement\")\n if (node.alternate) c(node.alternate, st, \"Statement\")\n}\nbase.LabeledStatement = (node, st, c) => c(node.body, st, \"Statement\")\nbase.BreakStatement = base.ContinueStatement = ignore\nbase.WithStatement = (node, st, c) => {\n c(node.object, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.SwitchStatement = (node, st, c) => {\n c(node.discriminant, st, \"Expression\")\n for (let cs of node.cases) {\n if (cs.test) c(cs.test, st, \"Expression\")\n for (let cons of cs.consequent)\n c(cons, st, \"Statement\")\n }\n}\nbase.SwitchCase = (node, st, c) => {\n if (node.test) c(node.test, st, \"Expression\")\n for (let cons of node.consequent)\n c(cons, st, \"Statement\")\n}\nbase.ReturnStatement = base.YieldExpression = base.AwaitExpression = (node, st, c) => {\n if (node.argument) c(node.argument, st, \"Expression\")\n}\nbase.ThrowStatement = base.SpreadElement =\n (node, st, c) => c(node.argument, st, \"Expression\")\nbase.TryStatement = (node, st, c) => {\n c(node.block, st, \"Statement\")\n if (node.handler) c(node.handler, st)\n if (node.finalizer) c(node.finalizer, st, \"Statement\")\n}\nbase.CatchClause = (node, st, c) => {\n if (node.param) c(node.param, st, \"Pattern\")\n c(node.body, st, \"Statement\")\n}\nbase.WhileStatement = base.DoWhileStatement = (node, st, c) => {\n c(node.test, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.ForStatement = (node, st, c) => {\n if (node.init) c(node.init, st, \"ForInit\")\n if (node.test) c(node.test, st, \"Expression\")\n if (node.update) c(node.update, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.ForInStatement = base.ForOfStatement = (node, st, c) => {\n c(node.left, st, \"ForInit\")\n c(node.right, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.ForInit = (node, st, c) => {\n if (node.type === \"VariableDeclaration\") c(node, st)\n else c(node, st, \"Expression\")\n}\nbase.DebuggerStatement = ignore\n\nbase.FunctionDeclaration = (node, st, c) => c(node, st, \"Function\")\nbase.VariableDeclaration = (node, st, c) => {\n for (let decl of node.declarations)\n c(decl, st)\n}\nbase.VariableDeclarator = (node, st, c) => {\n c(node.id, st, \"Pattern\")\n if (node.init) c(node.init, st, \"Expression\")\n}\n\nbase.Function = (node, st, c) => {\n if (node.id) c(node.id, st, \"Pattern\")\n for (let param of node.params)\n c(param, st, \"Pattern\")\n c(node.body, st, node.expression ? \"Expression\" : \"Statement\")\n}\n\nbase.Pattern = (node, st, c) => {\n if (node.type === \"Identifier\")\n c(node, st, \"VariablePattern\")\n else if (node.type === \"MemberExpression\")\n c(node, st, \"MemberPattern\")\n else\n c(node, st)\n}\nbase.VariablePattern = ignore\nbase.MemberPattern = skipThrough\nbase.RestElement = (node, st, c) => c(node.argument, st, \"Pattern\")\nbase.ArrayPattern = (node, st, c) => {\n for (let elt of node.elements) {\n if (elt) c(elt, st, \"Pattern\")\n }\n}\nbase.ObjectPattern = (node, st, c) => {\n for (let prop of node.properties) {\n if (prop.type === \"Property\") {\n if (prop.computed) c(prop.key, st, \"Expression\")\n c(prop.value, st, \"Pattern\")\n } else if (prop.type === \"RestElement\") {\n c(prop.argument, st, \"Pattern\")\n }\n }\n}\n\nbase.Expression = skipThrough\nbase.ThisExpression = base.Super = base.MetaProperty = ignore\nbase.ArrayExpression = (node, st, c) => {\n for (let elt of node.elements) {\n if (elt) c(elt, st, \"Expression\")\n }\n}\nbase.ObjectExpression = (node, st, c) => {\n for (let prop of node.properties)\n c(prop, st)\n}\nbase.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration\nbase.SequenceExpression = (node, st, c) => {\n for (let expr of node.expressions)\n c(expr, st, \"Expression\")\n}\nbase.TemplateLiteral = (node, st, c) => {\n for (let quasi of node.quasis)\n c(quasi, st)\n\n for (let expr of node.expressions)\n c(expr, st, \"Expression\")\n}\nbase.TemplateElement = ignore\nbase.UnaryExpression = base.UpdateExpression = (node, st, c) => {\n c(node.argument, st, \"Expression\")\n}\nbase.BinaryExpression = base.LogicalExpression = (node, st, c) => {\n c(node.left, st, \"Expression\")\n c(node.right, st, \"Expression\")\n}\nbase.AssignmentExpression = base.AssignmentPattern = (node, st, c) => {\n c(node.left, st, \"Pattern\")\n c(node.right, st, \"Expression\")\n}\nbase.ConditionalExpression = (node, st, c) => {\n c(node.test, st, \"Expression\")\n c(node.consequent, st, \"Expression\")\n c(node.alternate, st, \"Expression\")\n}\nbase.NewExpression = base.CallExpression = (node, st, c) => {\n c(node.callee, st, \"Expression\")\n if (node.arguments)\n for (let arg of node.arguments)\n c(arg, st, \"Expression\")\n}\nbase.MemberExpression = (node, st, c) => {\n c(node.object, st, \"Expression\")\n if (node.computed) c(node.property, st, \"Expression\")\n}\nbase.ExportNamedDeclaration = base.ExportDefaultDeclaration = (node, st, c) => {\n if (node.declaration)\n c(node.declaration, st, node.type === \"ExportNamedDeclaration\" || node.declaration.id ? \"Statement\" : \"Expression\")\n if (node.source) c(node.source, st, \"Expression\")\n}\nbase.ExportAllDeclaration = (node, st, c) => {\n c(node.source, st, \"Expression\")\n}\nbase.ImportDeclaration = (node, st, c) => {\n for (let spec of node.specifiers)\n c(spec, st)\n c(node.source, st, \"Expression\")\n}\nbase.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = ignore\n\nbase.TaggedTemplateExpression = (node, st, c) => {\n c(node.tag, st, \"Expression\")\n c(node.quasi, st, \"Expression\")\n}\nbase.ClassDeclaration = base.ClassExpression = (node, st, c) => c(node, st, \"Class\")\nbase.Class = (node, st, c) => {\n if (node.id) c(node.id, st, \"Pattern\")\n if (node.superClass) c(node.superClass, st, \"Expression\")\n c(node.body, st)\n}\nbase.ClassBody = (node, st, c) => {\n for (let elt of node.body)\n c(elt, st)\n}\nbase.MethodDefinition = base.Property = (node, st, c) => {\n if (node.computed) c(node.key, st, \"Expression\")\n c(node.value, st, \"Expression\")\n}\n"],"names":["let","const"],"mappings":"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"} \ No newline at end of file diff --git a/deps/acorn/acorn-walk/dist/walk.mjs b/deps/acorn/acorn-walk/dist/walk.mjs deleted file mode 100644 index 0f4100b8c87c57..00000000000000 --- a/deps/acorn/acorn-walk/dist/walk.mjs +++ /dev/null @@ -1,436 +0,0 @@ -// AST walker module for Mozilla Parser API compatible trees - -// A simple walk is one where you simply specify callbacks to be -// called on specific nodes. The last two arguments are optional. A -// simple use would be -// -// walk.simple(myTree, { -// Expression: function(node) { ... } -// }); -// -// to do something with all expressions. All Parser API node types -// can be used to identify node types, as well as Expression and -// Statement, which denote categories of nodes. -// -// The base argument can be used to pass a custom (recursive) -// walker, and state can be used to give this walked an initial -// state. - -function simple(node, visitors, baseVisitor, state, override) { - if (!baseVisitor) { baseVisitor = base - ; }(function c(node, st, override) { - var type = override || node.type, found = visitors[type]; - baseVisitor[type](node, st, c); - if (found) { found(node, st); } - })(node, state, override); -} - -// An ancestor walk keeps an array of ancestor nodes (including the -// current node) and passes them to the callback as third parameter -// (and also as state parameter when no other state is present). -function ancestor(node, visitors, baseVisitor, state) { - var ancestors = []; - if (!baseVisitor) { baseVisitor = base - ; }(function c(node, st, override) { - var type = override || node.type, found = visitors[type]; - var isNew = node !== ancestors[ancestors.length - 1]; - if (isNew) { ancestors.push(node); } - baseVisitor[type](node, st, c); - if (found) { found(node, st || ancestors, ancestors); } - if (isNew) { ancestors.pop(); } - })(node, state); -} - -// A recursive walk is one where your functions override the default -// walkers. They can modify and replace the state parameter that's -// threaded through the walk, and can opt how and whether to walk -// their child nodes (by calling their third argument on these -// nodes). -function recursive(node, state, funcs, baseVisitor, override) { - var visitor = funcs ? make(funcs, baseVisitor || undefined) : baseVisitor;(function c(node, st, override) { - visitor[override || node.type](node, st, c); - })(node, state, override); -} - -function makeTest(test) { - if (typeof test === "string") - { return function (type) { return type === test; } } - else if (!test) - { return function () { return true; } } - else - { return test } -} - -var Found = function Found(node, state) { this.node = node; this.state = state; }; - -// A full walk triggers the callback on each node -function full(node, callback, baseVisitor, state, override) { - if (!baseVisitor) { baseVisitor = base - ; }(function c(node, st, override) { - var type = override || node.type; - baseVisitor[type](node, st, c); - if (!override) { callback(node, st, type); } - })(node, state, override); -} - -// An fullAncestor walk is like an ancestor walk, but triggers -// the callback on each node -function fullAncestor(node, callback, baseVisitor, state) { - if (!baseVisitor) { baseVisitor = base; } - var ancestors = [];(function c(node, st, override) { - var type = override || node.type; - var isNew = node !== ancestors[ancestors.length - 1]; - if (isNew) { ancestors.push(node); } - baseVisitor[type](node, st, c); - if (!override) { callback(node, st || ancestors, ancestors, type); } - if (isNew) { ancestors.pop(); } - })(node, state); -} - -// Find a node with a given start, end, and type (all are optional, -// null can be used as wildcard). Returns a {node, state} object, or -// undefined when it doesn't find a matching node. -function findNodeAt(node, start, end, test, baseVisitor, state) { - if (!baseVisitor) { baseVisitor = base; } - test = makeTest(test); - try { - (function c(node, st, override) { - var type = override || node.type; - if ((start == null || node.start <= start) && - (end == null || node.end >= end)) - { baseVisitor[type](node, st, c); } - if ((start == null || node.start === start) && - (end == null || node.end === end) && - test(type, node)) - { throw new Found(node, st) } - })(node, state); - } catch (e) { - if (e instanceof Found) { return e } - throw e - } -} - -// Find the innermost node of a given type that contains the given -// position. Interface similar to findNodeAt. -function findNodeAround(node, pos, test, baseVisitor, state) { - test = makeTest(test); - if (!baseVisitor) { baseVisitor = base; } - try { - (function c(node, st, override) { - var type = override || node.type; - if (node.start > pos || node.end < pos) { return } - baseVisitor[type](node, st, c); - if (test(type, node)) { throw new Found(node, st) } - })(node, state); - } catch (e) { - if (e instanceof Found) { return e } - throw e - } -} - -// Find the outermost matching node after a given position. -function findNodeAfter(node, pos, test, baseVisitor, state) { - test = makeTest(test); - if (!baseVisitor) { baseVisitor = base; } - try { - (function c(node, st, override) { - if (node.end < pos) { return } - var type = override || node.type; - if (node.start >= pos && test(type, node)) { throw new Found(node, st) } - baseVisitor[type](node, st, c); - })(node, state); - } catch (e) { - if (e instanceof Found) { return e } - throw e - } -} - -// Find the outermost matching node before a given position. -function findNodeBefore(node, pos, test, baseVisitor, state) { - test = makeTest(test); - if (!baseVisitor) { baseVisitor = base; } - var max;(function c(node, st, override) { - if (node.start > pos) { return } - var type = override || node.type; - if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node)) - { max = new Found(node, st); } - baseVisitor[type](node, st, c); - })(node, state); - return max -} - -// Fallback to an Object.create polyfill for older environments. -var create = Object.create || function(proto) { - function Ctor() {} - Ctor.prototype = proto; - return new Ctor -}; - -// Used to create a custom walker. Will fill in all missing node -// type properties with the defaults. -function make(funcs, baseVisitor) { - var visitor = create(baseVisitor || base); - for (var type in funcs) { visitor[type] = funcs[type]; } - return visitor -} - -function skipThrough(node, st, c) { c(node, st); } -function ignore(_node, _st, _c) {} - -// Node walkers. - -var base = {}; - -base.Program = base.BlockStatement = function (node, st, c) { - for (var i = 0, list = node.body; i < list.length; i += 1) - { - var stmt = list[i]; - - c(stmt, st, "Statement"); - } -}; -base.Statement = skipThrough; -base.EmptyStatement = ignore; -base.ExpressionStatement = base.ParenthesizedExpression = - function (node, st, c) { return c(node.expression, st, "Expression"); }; -base.IfStatement = function (node, st, c) { - c(node.test, st, "Expression"); - c(node.consequent, st, "Statement"); - if (node.alternate) { c(node.alternate, st, "Statement"); } -}; -base.LabeledStatement = function (node, st, c) { return c(node.body, st, "Statement"); }; -base.BreakStatement = base.ContinueStatement = ignore; -base.WithStatement = function (node, st, c) { - c(node.object, st, "Expression"); - c(node.body, st, "Statement"); -}; -base.SwitchStatement = function (node, st, c) { - c(node.discriminant, st, "Expression"); - for (var i = 0, list = node.cases; i < list.length; i += 1) { - var cs = list[i]; - - if (cs.test) { c(cs.test, st, "Expression"); } - for (var i$1 = 0, list$1 = cs.consequent; i$1 < list$1.length; i$1 += 1) - { - var cons = list$1[i$1]; - - c(cons, st, "Statement"); - } - } -}; -base.SwitchCase = function (node, st, c) { - if (node.test) { c(node.test, st, "Expression"); } - for (var i = 0, list = node.consequent; i < list.length; i += 1) - { - var cons = list[i]; - - c(cons, st, "Statement"); - } -}; -base.ReturnStatement = base.YieldExpression = base.AwaitExpression = function (node, st, c) { - if (node.argument) { c(node.argument, st, "Expression"); } -}; -base.ThrowStatement = base.SpreadElement = - function (node, st, c) { return c(node.argument, st, "Expression"); }; -base.TryStatement = function (node, st, c) { - c(node.block, st, "Statement"); - if (node.handler) { c(node.handler, st); } - if (node.finalizer) { c(node.finalizer, st, "Statement"); } -}; -base.CatchClause = function (node, st, c) { - if (node.param) { c(node.param, st, "Pattern"); } - c(node.body, st, "Statement"); -}; -base.WhileStatement = base.DoWhileStatement = function (node, st, c) { - c(node.test, st, "Expression"); - c(node.body, st, "Statement"); -}; -base.ForStatement = function (node, st, c) { - if (node.init) { c(node.init, st, "ForInit"); } - if (node.test) { c(node.test, st, "Expression"); } - if (node.update) { c(node.update, st, "Expression"); } - c(node.body, st, "Statement"); -}; -base.ForInStatement = base.ForOfStatement = function (node, st, c) { - c(node.left, st, "ForInit"); - c(node.right, st, "Expression"); - c(node.body, st, "Statement"); -}; -base.ForInit = function (node, st, c) { - if (node.type === "VariableDeclaration") { c(node, st); } - else { c(node, st, "Expression"); } -}; -base.DebuggerStatement = ignore; - -base.FunctionDeclaration = function (node, st, c) { return c(node, st, "Function"); }; -base.VariableDeclaration = function (node, st, c) { - for (var i = 0, list = node.declarations; i < list.length; i += 1) - { - var decl = list[i]; - - c(decl, st); - } -}; -base.VariableDeclarator = function (node, st, c) { - c(node.id, st, "Pattern"); - if (node.init) { c(node.init, st, "Expression"); } -}; - -base.Function = function (node, st, c) { - if (node.id) { c(node.id, st, "Pattern"); } - for (var i = 0, list = node.params; i < list.length; i += 1) - { - var param = list[i]; - - c(param, st, "Pattern"); - } - c(node.body, st, node.expression ? "Expression" : "Statement"); -}; - -base.Pattern = function (node, st, c) { - if (node.type === "Identifier") - { c(node, st, "VariablePattern"); } - else if (node.type === "MemberExpression") - { c(node, st, "MemberPattern"); } - else - { c(node, st); } -}; -base.VariablePattern = ignore; -base.MemberPattern = skipThrough; -base.RestElement = function (node, st, c) { return c(node.argument, st, "Pattern"); }; -base.ArrayPattern = function (node, st, c) { - for (var i = 0, list = node.elements; i < list.length; i += 1) { - var elt = list[i]; - - if (elt) { c(elt, st, "Pattern"); } - } -}; -base.ObjectPattern = function (node, st, c) { - for (var i = 0, list = node.properties; i < list.length; i += 1) { - var prop = list[i]; - - if (prop.type === "Property") { - if (prop.computed) { c(prop.key, st, "Expression"); } - c(prop.value, st, "Pattern"); - } else if (prop.type === "RestElement") { - c(prop.argument, st, "Pattern"); - } - } -}; - -base.Expression = skipThrough; -base.ThisExpression = base.Super = base.MetaProperty = ignore; -base.ArrayExpression = function (node, st, c) { - for (var i = 0, list = node.elements; i < list.length; i += 1) { - var elt = list[i]; - - if (elt) { c(elt, st, "Expression"); } - } -}; -base.ObjectExpression = function (node, st, c) { - for (var i = 0, list = node.properties; i < list.length; i += 1) - { - var prop = list[i]; - - c(prop, st); - } -}; -base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration; -base.SequenceExpression = function (node, st, c) { - for (var i = 0, list = node.expressions; i < list.length; i += 1) - { - var expr = list[i]; - - c(expr, st, "Expression"); - } -}; -base.TemplateLiteral = function (node, st, c) { - for (var i = 0, list = node.quasis; i < list.length; i += 1) - { - var quasi = list[i]; - - c(quasi, st); - } - - for (var i$1 = 0, list$1 = node.expressions; i$1 < list$1.length; i$1 += 1) - { - var expr = list$1[i$1]; - - c(expr, st, "Expression"); - } -}; -base.TemplateElement = ignore; -base.UnaryExpression = base.UpdateExpression = function (node, st, c) { - c(node.argument, st, "Expression"); -}; -base.BinaryExpression = base.LogicalExpression = function (node, st, c) { - c(node.left, st, "Expression"); - c(node.right, st, "Expression"); -}; -base.AssignmentExpression = base.AssignmentPattern = function (node, st, c) { - c(node.left, st, "Pattern"); - c(node.right, st, "Expression"); -}; -base.ConditionalExpression = function (node, st, c) { - c(node.test, st, "Expression"); - c(node.consequent, st, "Expression"); - c(node.alternate, st, "Expression"); -}; -base.NewExpression = base.CallExpression = function (node, st, c) { - c(node.callee, st, "Expression"); - if (node.arguments) - { for (var i = 0, list = node.arguments; i < list.length; i += 1) - { - var arg = list[i]; - - c(arg, st, "Expression"); - } } -}; -base.MemberExpression = function (node, st, c) { - c(node.object, st, "Expression"); - if (node.computed) { c(node.property, st, "Expression"); } -}; -base.ExportNamedDeclaration = base.ExportDefaultDeclaration = function (node, st, c) { - if (node.declaration) - { c(node.declaration, st, node.type === "ExportNamedDeclaration" || node.declaration.id ? "Statement" : "Expression"); } - if (node.source) { c(node.source, st, "Expression"); } -}; -base.ExportAllDeclaration = function (node, st, c) { - c(node.source, st, "Expression"); -}; -base.ImportDeclaration = function (node, st, c) { - for (var i = 0, list = node.specifiers; i < list.length; i += 1) - { - var spec = list[i]; - - c(spec, st); - } - c(node.source, st, "Expression"); -}; -base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = ignore; - -base.TaggedTemplateExpression = function (node, st, c) { - c(node.tag, st, "Expression"); - c(node.quasi, st, "Expression"); -}; -base.ClassDeclaration = base.ClassExpression = function (node, st, c) { return c(node, st, "Class"); }; -base.Class = function (node, st, c) { - if (node.id) { c(node.id, st, "Pattern"); } - if (node.superClass) { c(node.superClass, st, "Expression"); } - c(node.body, st); -}; -base.ClassBody = function (node, st, c) { - for (var i = 0, list = node.body; i < list.length; i += 1) - { - var elt = list[i]; - - c(elt, st); - } -}; -base.MethodDefinition = base.Property = function (node, st, c) { - if (node.computed) { c(node.key, st, "Expression"); } - c(node.value, st, "Expression"); -}; - -export { simple, ancestor, recursive, full, fullAncestor, findNodeAt, findNodeAround, findNodeAfter, findNodeBefore, make, base }; -//# sourceMappingURL=walk.mjs.map diff --git a/deps/acorn/acorn-walk/dist/walk.mjs.map b/deps/acorn/acorn-walk/dist/walk.mjs.map deleted file mode 100644 index 2a94219c3bada4..00000000000000 --- a/deps/acorn/acorn-walk/dist/walk.mjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"walk.mjs","sources":["../src/index.js"],"sourcesContent":["// AST walker module for Mozilla Parser API compatible trees\n\n// A simple walk is one where you simply specify callbacks to be\n// called on specific nodes. The last two arguments are optional. A\n// simple use would be\n//\n// walk.simple(myTree, {\n// Expression: function(node) { ... }\n// });\n//\n// to do something with all expressions. All Parser API node types\n// can be used to identify node types, as well as Expression and\n// Statement, which denote categories of nodes.\n//\n// The base argument can be used to pass a custom (recursive)\n// walker, and state can be used to give this walked an initial\n// state.\n\nexport function simple(node, visitors, baseVisitor, state, override) {\n if (!baseVisitor) baseVisitor = base\n ;(function c(node, st, override) {\n let type = override || node.type, found = visitors[type]\n baseVisitor[type](node, st, c)\n if (found) found(node, st)\n })(node, state, override)\n}\n\n// An ancestor walk keeps an array of ancestor nodes (including the\n// current node) and passes them to the callback as third parameter\n// (and also as state parameter when no other state is present).\nexport function ancestor(node, visitors, baseVisitor, state) {\n let ancestors = []\n if (!baseVisitor) baseVisitor = base\n ;(function c(node, st, override) {\n let type = override || node.type, found = visitors[type]\n let isNew = node !== ancestors[ancestors.length - 1]\n if (isNew) ancestors.push(node)\n baseVisitor[type](node, st, c)\n if (found) found(node, st || ancestors, ancestors)\n if (isNew) ancestors.pop()\n })(node, state)\n}\n\n// A recursive walk is one where your functions override the default\n// walkers. They can modify and replace the state parameter that's\n// threaded through the walk, and can opt how and whether to walk\n// their child nodes (by calling their third argument on these\n// nodes).\nexport function recursive(node, state, funcs, baseVisitor, override) {\n let visitor = funcs ? make(funcs, baseVisitor || undefined) : baseVisitor\n ;(function c(node, st, override) {\n visitor[override || node.type](node, st, c)\n })(node, state, override)\n}\n\nfunction makeTest(test) {\n if (typeof test === \"string\")\n return type => type === test\n else if (!test)\n return () => true\n else\n return test\n}\n\nclass Found {\n constructor(node, state) { this.node = node; this.state = state }\n}\n\n// A full walk triggers the callback on each node\nexport function full(node, callback, baseVisitor, state, override) {\n if (!baseVisitor) baseVisitor = base\n ;(function c(node, st, override) {\n let type = override || node.type\n baseVisitor[type](node, st, c)\n if (!override) callback(node, st, type)\n })(node, state, override)\n}\n\n// An fullAncestor walk is like an ancestor walk, but triggers\n// the callback on each node\nexport function fullAncestor(node, callback, baseVisitor, state) {\n if (!baseVisitor) baseVisitor = base\n let ancestors = []\n ;(function c(node, st, override) {\n let type = override || node.type\n let isNew = node !== ancestors[ancestors.length - 1]\n if (isNew) ancestors.push(node)\n baseVisitor[type](node, st, c)\n if (!override) callback(node, st || ancestors, ancestors, type)\n if (isNew) ancestors.pop()\n })(node, state)\n}\n\n// Find a node with a given start, end, and type (all are optional,\n// null can be used as wildcard). Returns a {node, state} object, or\n// undefined when it doesn't find a matching node.\nexport function findNodeAt(node, start, end, test, baseVisitor, state) {\n if (!baseVisitor) baseVisitor = base\n test = makeTest(test)\n try {\n (function c(node, st, override) {\n let type = override || node.type\n if ((start == null || node.start <= start) &&\n (end == null || node.end >= end))\n baseVisitor[type](node, st, c)\n if ((start == null || node.start === start) &&\n (end == null || node.end === end) &&\n test(type, node))\n throw new Found(node, st)\n })(node, state)\n } catch (e) {\n if (e instanceof Found) return e\n throw e\n }\n}\n\n// Find the innermost node of a given type that contains the given\n// position. Interface similar to findNodeAt.\nexport function findNodeAround(node, pos, test, baseVisitor, state) {\n test = makeTest(test)\n if (!baseVisitor) baseVisitor = base\n try {\n (function c(node, st, override) {\n let type = override || node.type\n if (node.start > pos || node.end < pos) return\n baseVisitor[type](node, st, c)\n if (test(type, node)) throw new Found(node, st)\n })(node, state)\n } catch (e) {\n if (e instanceof Found) return e\n throw e\n }\n}\n\n// Find the outermost matching node after a given position.\nexport function findNodeAfter(node, pos, test, baseVisitor, state) {\n test = makeTest(test)\n if (!baseVisitor) baseVisitor = base\n try {\n (function c(node, st, override) {\n if (node.end < pos) return\n let type = override || node.type\n if (node.start >= pos && test(type, node)) throw new Found(node, st)\n baseVisitor[type](node, st, c)\n })(node, state)\n } catch (e) {\n if (e instanceof Found) return e\n throw e\n }\n}\n\n// Find the outermost matching node before a given position.\nexport function findNodeBefore(node, pos, test, baseVisitor, state) {\n test = makeTest(test)\n if (!baseVisitor) baseVisitor = base\n let max\n ;(function c(node, st, override) {\n if (node.start > pos) return\n let type = override || node.type\n if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))\n max = new Found(node, st)\n baseVisitor[type](node, st, c)\n })(node, state)\n return max\n}\n\n// Fallback to an Object.create polyfill for older environments.\nconst create = Object.create || function(proto) {\n function Ctor() {}\n Ctor.prototype = proto\n return new Ctor\n}\n\n// Used to create a custom walker. Will fill in all missing node\n// type properties with the defaults.\nexport function make(funcs, baseVisitor) {\n let visitor = create(baseVisitor || base)\n for (let type in funcs) visitor[type] = funcs[type]\n return visitor\n}\n\nfunction skipThrough(node, st, c) { c(node, st) }\nfunction ignore(_node, _st, _c) {}\n\n// Node walkers.\n\nexport const base = {}\n\nbase.Program = base.BlockStatement = (node, st, c) => {\n for (let stmt of node.body)\n c(stmt, st, \"Statement\")\n}\nbase.Statement = skipThrough\nbase.EmptyStatement = ignore\nbase.ExpressionStatement = base.ParenthesizedExpression =\n (node, st, c) => c(node.expression, st, \"Expression\")\nbase.IfStatement = (node, st, c) => {\n c(node.test, st, \"Expression\")\n c(node.consequent, st, \"Statement\")\n if (node.alternate) c(node.alternate, st, \"Statement\")\n}\nbase.LabeledStatement = (node, st, c) => c(node.body, st, \"Statement\")\nbase.BreakStatement = base.ContinueStatement = ignore\nbase.WithStatement = (node, st, c) => {\n c(node.object, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.SwitchStatement = (node, st, c) => {\n c(node.discriminant, st, \"Expression\")\n for (let cs of node.cases) {\n if (cs.test) c(cs.test, st, \"Expression\")\n for (let cons of cs.consequent)\n c(cons, st, \"Statement\")\n }\n}\nbase.SwitchCase = (node, st, c) => {\n if (node.test) c(node.test, st, \"Expression\")\n for (let cons of node.consequent)\n c(cons, st, \"Statement\")\n}\nbase.ReturnStatement = base.YieldExpression = base.AwaitExpression = (node, st, c) => {\n if (node.argument) c(node.argument, st, \"Expression\")\n}\nbase.ThrowStatement = base.SpreadElement =\n (node, st, c) => c(node.argument, st, \"Expression\")\nbase.TryStatement = (node, st, c) => {\n c(node.block, st, \"Statement\")\n if (node.handler) c(node.handler, st)\n if (node.finalizer) c(node.finalizer, st, \"Statement\")\n}\nbase.CatchClause = (node, st, c) => {\n if (node.param) c(node.param, st, \"Pattern\")\n c(node.body, st, \"Statement\")\n}\nbase.WhileStatement = base.DoWhileStatement = (node, st, c) => {\n c(node.test, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.ForStatement = (node, st, c) => {\n if (node.init) c(node.init, st, \"ForInit\")\n if (node.test) c(node.test, st, \"Expression\")\n if (node.update) c(node.update, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.ForInStatement = base.ForOfStatement = (node, st, c) => {\n c(node.left, st, \"ForInit\")\n c(node.right, st, \"Expression\")\n c(node.body, st, \"Statement\")\n}\nbase.ForInit = (node, st, c) => {\n if (node.type === \"VariableDeclaration\") c(node, st)\n else c(node, st, \"Expression\")\n}\nbase.DebuggerStatement = ignore\n\nbase.FunctionDeclaration = (node, st, c) => c(node, st, \"Function\")\nbase.VariableDeclaration = (node, st, c) => {\n for (let decl of node.declarations)\n c(decl, st)\n}\nbase.VariableDeclarator = (node, st, c) => {\n c(node.id, st, \"Pattern\")\n if (node.init) c(node.init, st, \"Expression\")\n}\n\nbase.Function = (node, st, c) => {\n if (node.id) c(node.id, st, \"Pattern\")\n for (let param of node.params)\n c(param, st, \"Pattern\")\n c(node.body, st, node.expression ? \"Expression\" : \"Statement\")\n}\n\nbase.Pattern = (node, st, c) => {\n if (node.type === \"Identifier\")\n c(node, st, \"VariablePattern\")\n else if (node.type === \"MemberExpression\")\n c(node, st, \"MemberPattern\")\n else\n c(node, st)\n}\nbase.VariablePattern = ignore\nbase.MemberPattern = skipThrough\nbase.RestElement = (node, st, c) => c(node.argument, st, \"Pattern\")\nbase.ArrayPattern = (node, st, c) => {\n for (let elt of node.elements) {\n if (elt) c(elt, st, \"Pattern\")\n }\n}\nbase.ObjectPattern = (node, st, c) => {\n for (let prop of node.properties) {\n if (prop.type === \"Property\") {\n if (prop.computed) c(prop.key, st, \"Expression\")\n c(prop.value, st, \"Pattern\")\n } else if (prop.type === \"RestElement\") {\n c(prop.argument, st, \"Pattern\")\n }\n }\n}\n\nbase.Expression = skipThrough\nbase.ThisExpression = base.Super = base.MetaProperty = ignore\nbase.ArrayExpression = (node, st, c) => {\n for (let elt of node.elements) {\n if (elt) c(elt, st, \"Expression\")\n }\n}\nbase.ObjectExpression = (node, st, c) => {\n for (let prop of node.properties)\n c(prop, st)\n}\nbase.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration\nbase.SequenceExpression = (node, st, c) => {\n for (let expr of node.expressions)\n c(expr, st, \"Expression\")\n}\nbase.TemplateLiteral = (node, st, c) => {\n for (let quasi of node.quasis)\n c(quasi, st)\n\n for (let expr of node.expressions)\n c(expr, st, \"Expression\")\n}\nbase.TemplateElement = ignore\nbase.UnaryExpression = base.UpdateExpression = (node, st, c) => {\n c(node.argument, st, \"Expression\")\n}\nbase.BinaryExpression = base.LogicalExpression = (node, st, c) => {\n c(node.left, st, \"Expression\")\n c(node.right, st, \"Expression\")\n}\nbase.AssignmentExpression = base.AssignmentPattern = (node, st, c) => {\n c(node.left, st, \"Pattern\")\n c(node.right, st, \"Expression\")\n}\nbase.ConditionalExpression = (node, st, c) => {\n c(node.test, st, \"Expression\")\n c(node.consequent, st, \"Expression\")\n c(node.alternate, st, \"Expression\")\n}\nbase.NewExpression = base.CallExpression = (node, st, c) => {\n c(node.callee, st, \"Expression\")\n if (node.arguments)\n for (let arg of node.arguments)\n c(arg, st, \"Expression\")\n}\nbase.MemberExpression = (node, st, c) => {\n c(node.object, st, \"Expression\")\n if (node.computed) c(node.property, st, \"Expression\")\n}\nbase.ExportNamedDeclaration = base.ExportDefaultDeclaration = (node, st, c) => {\n if (node.declaration)\n c(node.declaration, st, node.type === \"ExportNamedDeclaration\" || node.declaration.id ? \"Statement\" : \"Expression\")\n if (node.source) c(node.source, st, \"Expression\")\n}\nbase.ExportAllDeclaration = (node, st, c) => {\n c(node.source, st, \"Expression\")\n}\nbase.ImportDeclaration = (node, st, c) => {\n for (let spec of node.specifiers)\n c(spec, st)\n c(node.source, st, \"Expression\")\n}\nbase.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = ignore\n\nbase.TaggedTemplateExpression = (node, st, c) => {\n c(node.tag, st, \"Expression\")\n c(node.quasi, st, \"Expression\")\n}\nbase.ClassDeclaration = base.ClassExpression = (node, st, c) => c(node, st, \"Class\")\nbase.Class = (node, st, c) => {\n if (node.id) c(node.id, st, \"Pattern\")\n if (node.superClass) c(node.superClass, st, \"Expression\")\n c(node.body, st)\n}\nbase.ClassBody = (node, st, c) => {\n for (let elt of node.body)\n c(elt, st)\n}\nbase.MethodDefinition = base.Property = (node, st, c) => {\n if (node.computed) c(node.key, st, \"Expression\")\n c(node.value, st, \"Expression\")\n}\n"],"names":["let","const"],"mappings":"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"} \ No newline at end of file diff --git a/deps/acorn/acorn/bin/acorn b/deps/acorn/acorn/bin/acorn deleted file mode 100644 index cf7df46890fdd4..00000000000000 --- a/deps/acorn/acorn/bin/acorn +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -require('../dist/bin.js'); diff --git a/deps/acorn/acorn/dist/acorn.d.ts b/deps/acorn/acorn/dist/acorn.d.ts deleted file mode 100644 index c6f9841b809a48..00000000000000 --- a/deps/acorn/acorn/dist/acorn.d.ts +++ /dev/null @@ -1,209 +0,0 @@ -export as namespace acorn -export = acorn - -declare namespace acorn { - function parse(input: string, options?: Options): Node - - function parseExpressionAt(input: string, pos?: number, options?: Options): Node - - function tokenizer(input: string, options?: Options): { - getToken(): Token - [Symbol.iterator](): Iterator - } - - interface Options { - ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 2015 | 2016 | 2017 | 2018 | 2019 - sourceType?: 'script' | 'module' - onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void - onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void - allowReserved?: boolean - allowReturnOutsideFunction?: boolean - allowImportExportEverywhere?: boolean - allowAwaitOutsideFunction?: boolean - allowHashBang?: boolean - locations?: boolean - onToken?: ((token: Token) => any) | Token[] - onComment?: (( - isBlock: boolean, text: string, start: number, end: number, startLoc?: Position, - endLoc?: Position - ) => void) | Comment[] - ranges?: boolean - program?: Node - sourceFile?: string - directSourceFile?: string - preserveParens?: boolean - } - - class Parser { - constructor(options: Options, input: string, startPos?: number) - parse(): Node - static parse(input: string, options?: Options): Node - static parseExpressionAt(input: string, pos: number, options?: Options): Node - static tokenizer(input: string, options?: Options): { - getToken(): Token - [Symbol.iterator](): Iterator - } - static extend(...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser - } - - interface Position { line: number; column: number; offset: number } - - const defaultOptions: Options - - function getLineInfo(input: string, offset: number): Position - - class SourceLocation { - start: Position - end: Position - source?: string | null - constructor(p: Parser, start: Position, end: Position) - } - - class Node { - type: string - start: number - end: number - loc?: SourceLocation - sourceFile?: string - range?: [number, number] - constructor(parser: Parser, pos: number, loc?: SourceLocation) - } - - class TokenType { - label: string - keyword: string - beforeExpr: boolean - startsExpr: boolean - isLoop: boolean - isAssign: boolean - prefix: boolean - postfix: boolean - binop: number - updateContext?: (prevType: TokenType) => void - constructor(label: string, conf?: any) - } - - const tokTypes: { - num: TokenType - regexp: TokenType - string: TokenType - name: TokenType - eof: TokenType - bracketL: TokenType - bracketR: TokenType - braceL: TokenType - braceR: TokenType - parenL: TokenType - parenR: TokenType - comma: TokenType - semi: TokenType - colon: TokenType - dot: TokenType - question: TokenType - arrow: TokenType - template: TokenType - ellipsis: TokenType - backQuote: TokenType - dollarBraceL: TokenType - eq: TokenType - assign: TokenType - incDec: TokenType - prefix: TokenType - logicalOR: TokenType - logicalAND: TokenType - bitwiseOR: TokenType - bitwiseXOR: TokenType - bitwiseAND: TokenType - equality: TokenType - relational: TokenType - bitShift: TokenType - plusMin: TokenType - modulo: TokenType - star: TokenType - slash: TokenType - starstar: TokenType - _break: TokenType - _case: TokenType - _catch: TokenType - _continue: TokenType - _debugger: TokenType - _default: TokenType - _do: TokenType - _else: TokenType - _finally: TokenType - _for: TokenType - _function: TokenType - _if: TokenType - _return: TokenType - _switch: TokenType - _throw: TokenType - _try: TokenType - _var: TokenType - _const: TokenType - _while: TokenType - _with: TokenType - _new: TokenType - _this: TokenType - _super: TokenType - _class: TokenType - _extends: TokenType - _export: TokenType - _import: TokenType - _null: TokenType - _true: TokenType - _false: TokenType - _in: TokenType - _instanceof: TokenType - _typeof: TokenType - _void: TokenType - _delete: TokenType - } - - class TokContext { - constructor(token: string, isExpr: boolean, preserveSpace: boolean, override?: (p: Parser) => void) - } - - const tokContexts: { - b_stat: TokContext - b_expr: TokContext - b_tmpl: TokContext - p_stat: TokContext - p_expr: TokContext - q_tmpl: TokContext - f_expr: TokContext - } - - function isIdentifierStart(code: number, astral?: boolean): boolean - - function isIdentifierChar(code: number, astral?: boolean): boolean - - interface AbstractToken { - } - - interface Comment extends AbstractToken { - type: string - value: string - start: number - end: number - loc?: SourceLocation - range?: [number, number] - } - - class Token { - type: TokenType - value: any - start: number - end: number - loc?: SourceLocation - range?: [number, number] - constructor(p: Parser) - } - - function isNewLine(code: number): boolean - - const lineBreak: RegExp - - const lineBreakG: RegExp - - const version: string -} diff --git a/deps/acorn/acorn/dist/acorn.js.map b/deps/acorn/acorn/dist/acorn.js.map deleted file mode 100644 index 219dac5954a3be..00000000000000 --- a/deps/acorn/acorn/dist/acorn.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"acorn.js","sources":["../src/identifier.js","../src/tokentype.js","../src/whitespace.js","../src/util.js","../src/locutil.js","../src/options.js","../src/scopeflags.js","../src/state.js","../src/parseutil.js","../src/statement.js","../src/lval.js","../src/expression.js","../src/location.js","../src/scope.js","../src/node.js","../src/tokencontext.js","../src/unicode-property-data.js","../src/regexp.js","../src/tokenize.js","../src/index.js"],"sourcesContent":["// Reserved word lists for various dialects of the language\n\nexport const reservedWords = {\n 3: \"abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile\",\n 5: \"class enum extends super const export import\",\n 6: \"enum\",\n strict: \"implements interface let package private protected public static yield\",\n strictBind: \"eval arguments\"\n}\n\n// And the keywords\n\nconst ecma5AndLessKeywords = \"break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this\"\n\nexport const keywords = {\n 5: ecma5AndLessKeywords,\n 6: ecma5AndLessKeywords + \" const class extends export import super\"\n}\n\nexport const keywordRelationalOperator = /^in(stanceof)?$/\n\n// ## Character categories\n\n// Big ugly regular expressions that match characters in the\n// whitespace, identifier, and identifier-start categories. These\n// are only applied when a character is found to actually have a\n// code point above 128.\n// Generated by `bin/generate-identifier-regex.js`.\n\nlet nonASCIIidentifierStartChars = \"\\xaa\\xb5\\xba\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\u02c1\\u02c6-\\u02d1\\u02e0-\\u02e4\\u02ec\\u02ee\\u0370-\\u0374\\u0376\\u0377\\u037a-\\u037d\\u037f\\u0386\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03f5\\u03f7-\\u0481\\u048a-\\u052f\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05d0-\\u05ea\\u05ef-\\u05f2\\u0620-\\u064a\\u066e\\u066f\\u0671-\\u06d3\\u06d5\\u06e5\\u06e6\\u06ee\\u06ef\\u06fa-\\u06fc\\u06ff\\u0710\\u0712-\\u072f\\u074d-\\u07a5\\u07b1\\u07ca-\\u07ea\\u07f4\\u07f5\\u07fa\\u0800-\\u0815\\u081a\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086a\\u08a0-\\u08b4\\u08b6-\\u08bd\\u0904-\\u0939\\u093d\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098c\\u098f\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2\\u09b6-\\u09b9\\u09bd\\u09ce\\u09dc\\u09dd\\u09df-\\u09e1\\u09f0\\u09f1\\u09fc\\u0a05-\\u0a0a\\u0a0f\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32\\u0a33\\u0a35\\u0a36\\u0a38\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8d\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2\\u0ab3\\u0ab5-\\u0ab9\\u0abd\\u0ad0\\u0ae0\\u0ae1\\u0af9\\u0b05-\\u0b0c\\u0b0f\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30\\u0b32\\u0b33\\u0b35-\\u0b39\\u0b3d\\u0b5c\\u0b5d\\u0b5f-\\u0b61\\u0b71\\u0b83\\u0b85-\\u0b8a\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99\\u0b9a\\u0b9c\\u0b9e\\u0b9f\\u0ba3\\u0ba4\\u0ba8-\\u0baa\\u0bae-\\u0bb9\\u0bd0\\u0c05-\\u0c0c\\u0c0e-\\u0c10\\u0c12-\\u0c28\\u0c2a-\\u0c39\\u0c3d\\u0c58-\\u0c5a\\u0c60\\u0c61\\u0c80\\u0c85-\\u0c8c\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cbd\\u0cde\\u0ce0\\u0ce1\\u0cf1\\u0cf2\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d3a\\u0d3d\\u0d4e\\u0d54-\\u0d56\\u0d5f-\\u0d61\\u0d7a-\\u0d7f\\u0d85-\\u0d96\\u0d9a-\\u0db1\\u0db3-\\u0dbb\\u0dbd\\u0dc0-\\u0dc6\\u0e01-\\u0e30\\u0e32\\u0e33\\u0e40-\\u0e46\\u0e81\\u0e82\\u0e84\\u0e87\\u0e88\\u0e8a\\u0e8d\\u0e94-\\u0e97\\u0e99-\\u0e9f\\u0ea1-\\u0ea3\\u0ea5\\u0ea7\\u0eaa\\u0eab\\u0ead-\\u0eb0\\u0eb2\\u0eb3\\u0ebd\\u0ec0-\\u0ec4\\u0ec6\\u0edc-\\u0edf\\u0f00\\u0f40-\\u0f47\\u0f49-\\u0f6c\\u0f88-\\u0f8c\\u1000-\\u102a\\u103f\\u1050-\\u1055\\u105a-\\u105d\\u1061\\u1065\\u1066\\u106e-\\u1070\\u1075-\\u1081\\u108e\\u10a0-\\u10c5\\u10c7\\u10cd\\u10d0-\\u10fa\\u10fc-\\u1248\\u124a-\\u124d\\u1250-\\u1256\\u1258\\u125a-\\u125d\\u1260-\\u1288\\u128a-\\u128d\\u1290-\\u12b0\\u12b2-\\u12b5\\u12b8-\\u12be\\u12c0\\u12c2-\\u12c5\\u12c8-\\u12d6\\u12d8-\\u1310\\u1312-\\u1315\\u1318-\\u135a\\u1380-\\u138f\\u13a0-\\u13f5\\u13f8-\\u13fd\\u1401-\\u166c\\u166f-\\u167f\\u1681-\\u169a\\u16a0-\\u16ea\\u16ee-\\u16f8\\u1700-\\u170c\\u170e-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176c\\u176e-\\u1770\\u1780-\\u17b3\\u17d7\\u17dc\\u1820-\\u1878\\u1880-\\u18a8\\u18aa\\u18b0-\\u18f5\\u1900-\\u191e\\u1950-\\u196d\\u1970-\\u1974\\u1980-\\u19ab\\u19b0-\\u19c9\\u1a00-\\u1a16\\u1a20-\\u1a54\\u1aa7\\u1b05-\\u1b33\\u1b45-\\u1b4b\\u1b83-\\u1ba0\\u1bae\\u1baf\\u1bba-\\u1be5\\u1c00-\\u1c23\\u1c4d-\\u1c4f\\u1c5a-\\u1c7d\\u1c80-\\u1c88\\u1c90-\\u1cba\\u1cbd-\\u1cbf\\u1ce9-\\u1cec\\u1cee-\\u1cf1\\u1cf5\\u1cf6\\u1d00-\\u1dbf\\u1e00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2071\\u207f\\u2090-\\u209c\\u2102\\u2107\\u210a-\\u2113\\u2115\\u2118-\\u211d\\u2124\\u2126\\u2128\\u212a-\\u2139\\u213c-\\u213f\\u2145-\\u2149\\u214e\\u2160-\\u2188\\u2c00-\\u2c2e\\u2c30-\\u2c5e\\u2c60-\\u2ce4\\u2ceb-\\u2cee\\u2cf2\\u2cf3\\u2d00-\\u2d25\\u2d27\\u2d2d\\u2d30-\\u2d67\\u2d6f\\u2d80-\\u2d96\\u2da0-\\u2da6\\u2da8-\\u2dae\\u2db0-\\u2db6\\u2db8-\\u2dbe\\u2dc0-\\u2dc6\\u2dc8-\\u2dce\\u2dd0-\\u2dd6\\u2dd8-\\u2dde\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303c\\u3041-\\u3096\\u309b-\\u309f\\u30a1-\\u30fa\\u30fc-\\u30ff\\u3105-\\u312f\\u3131-\\u318e\\u31a0-\\u31ba\\u31f0-\\u31ff\\u3400-\\u4db5\\u4e00-\\u9fef\\ua000-\\ua48c\\ua4d0-\\ua4fd\\ua500-\\ua60c\\ua610-\\ua61f\\ua62a\\ua62b\\ua640-\\ua66e\\ua67f-\\ua69d\\ua6a0-\\ua6ef\\ua717-\\ua71f\\ua722-\\ua788\\ua78b-\\ua7b9\\ua7f7-\\ua801\\ua803-\\ua805\\ua807-\\ua80a\\ua80c-\\ua822\\ua840-\\ua873\\ua882-\\ua8b3\\ua8f2-\\ua8f7\\ua8fb\\ua8fd\\ua8fe\\ua90a-\\ua925\\ua930-\\ua946\\ua960-\\ua97c\\ua984-\\ua9b2\\ua9cf\\ua9e0-\\ua9e4\\ua9e6-\\ua9ef\\ua9fa-\\ua9fe\\uaa00-\\uaa28\\uaa40-\\uaa42\\uaa44-\\uaa4b\\uaa60-\\uaa76\\uaa7a\\uaa7e-\\uaaaf\\uaab1\\uaab5\\uaab6\\uaab9-\\uaabd\\uaac0\\uaac2\\uaadb-\\uaadd\\uaae0-\\uaaea\\uaaf2-\\uaaf4\\uab01-\\uab06\\uab09-\\uab0e\\uab11-\\uab16\\uab20-\\uab26\\uab28-\\uab2e\\uab30-\\uab5a\\uab5c-\\uab65\\uab70-\\uabe2\\uac00-\\ud7a3\\ud7b0-\\ud7c6\\ud7cb-\\ud7fb\\uf900-\\ufa6d\\ufa70-\\ufad9\\ufb00-\\ufb06\\ufb13-\\ufb17\\ufb1d\\ufb1f-\\ufb28\\ufb2a-\\ufb36\\ufb38-\\ufb3c\\ufb3e\\ufb40\\ufb41\\ufb43\\ufb44\\ufb46-\\ufbb1\\ufbd3-\\ufd3d\\ufd50-\\ufd8f\\ufd92-\\ufdc7\\ufdf0-\\ufdfb\\ufe70-\\ufe74\\ufe76-\\ufefc\\uff21-\\uff3a\\uff41-\\uff5a\\uff66-\\uffbe\\uffc2-\\uffc7\\uffca-\\uffcf\\uffd2-\\uffd7\\uffda-\\uffdc\"\nlet nonASCIIidentifierChars = \"\\u200c\\u200d\\xb7\\u0300-\\u036f\\u0387\\u0483-\\u0487\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u0669\\u0670\\u06d6-\\u06dc\\u06df-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u06f0-\\u06f9\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07c0-\\u07c9\\u07eb-\\u07f3\\u07fd\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0859-\\u085b\\u08d3-\\u08e1\\u08e3-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962\\u0963\\u0966-\\u096f\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09cb-\\u09cd\\u09d7\\u09e2\\u09e3\\u09e6-\\u09ef\\u09fe\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a66-\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2\\u0ae3\\u0ae6-\\u0aef\\u0afa-\\u0aff\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b66-\\u0b6f\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0be6-\\u0bef\\u0c00-\\u0c04\\u0c3e-\\u0c44\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0c66-\\u0c6f\\u0c81-\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0ce6-\\u0cef\\u0d00-\\u0d03\\u0d3b\\u0d3c\\u0d3e-\\u0d44\\u0d46-\\u0d48\\u0d4a-\\u0d4d\\u0d57\\u0d62\\u0d63\\u0d66-\\u0d6f\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0de6-\\u0def\\u0df2\\u0df3\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0e50-\\u0e59\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0ed0-\\u0ed9\\u0f18\\u0f19\\u0f20-\\u0f29\\u0f35\\u0f37\\u0f39\\u0f3e\\u0f3f\\u0f71-\\u0f84\\u0f86\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102b-\\u103e\\u1040-\\u1049\\u1056-\\u1059\\u105e-\\u1060\\u1062-\\u1064\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f-\\u109d\\u135d-\\u135f\\u1369-\\u1371\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b4-\\u17d3\\u17dd\\u17e0-\\u17e9\\u180b-\\u180d\\u1810-\\u1819\\u18a9\\u1920-\\u192b\\u1930-\\u193b\\u1946-\\u194f\\u19d0-\\u19da\\u1a17-\\u1a1b\\u1a55-\\u1a5e\\u1a60-\\u1a7c\\u1a7f-\\u1a89\\u1a90-\\u1a99\\u1ab0-\\u1abd\\u1b00-\\u1b04\\u1b34-\\u1b44\\u1b50-\\u1b59\\u1b6b-\\u1b73\\u1b80-\\u1b82\\u1ba1-\\u1bad\\u1bb0-\\u1bb9\\u1be6-\\u1bf3\\u1c24-\\u1c37\\u1c40-\\u1c49\\u1c50-\\u1c59\\u1cd0-\\u1cd2\\u1cd4-\\u1ce8\\u1ced\\u1cf2-\\u1cf4\\u1cf7-\\u1cf9\\u1dc0-\\u1df9\\u1dfb-\\u1dff\\u203f\\u2040\\u2054\\u20d0-\\u20dc\\u20e1\\u20e5-\\u20f0\\u2cef-\\u2cf1\\u2d7f\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua620-\\ua629\\ua66f\\ua674-\\ua67d\\ua69e\\ua69f\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua823-\\ua827\\ua880\\ua881\\ua8b4-\\ua8c5\\ua8d0-\\ua8d9\\ua8e0-\\ua8f1\\ua8ff-\\ua909\\ua926-\\ua92d\\ua947-\\ua953\\ua980-\\ua983\\ua9b3-\\ua9c0\\ua9d0-\\ua9d9\\ua9e5\\ua9f0-\\ua9f9\\uaa29-\\uaa36\\uaa43\\uaa4c\\uaa4d\\uaa50-\\uaa59\\uaa7b-\\uaa7d\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uaaeb-\\uaaef\\uaaf5\\uaaf6\\uabe3-\\uabea\\uabec\\uabed\\uabf0-\\uabf9\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe2f\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff10-\\uff19\\uff3f\"\n\nconst nonASCIIidentifierStart = new RegExp(\"[\" + nonASCIIidentifierStartChars + \"]\")\nconst nonASCIIidentifier = new RegExp(\"[\" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + \"]\")\n\nnonASCIIidentifierStartChars = nonASCIIidentifierChars = null\n\n// These are a run-length and offset encoded representation of the\n// >0xffff code points that are a valid part of identifiers. The\n// offset starts at 0x10000, and each pair of numbers represents an\n// offset to the next range, and then a size of the range. They were\n// generated by bin/generate-identifier-regex.js\n\n// eslint-disable-next-line comma-spacing\nconst astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,477,28,11,0,9,21,190,52,76,44,33,24,27,35,30,0,12,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,26,230,43,117,63,32,0,257,0,11,39,8,0,22,0,12,39,3,3,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,270,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,68,12,0,67,12,65,1,31,6129,15,754,9486,286,82,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,15,7472,3104,541]\n\n// eslint-disable-next-line comma-spacing\nconst astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,525,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,4,9,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,280,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239]\n\n// This has a complexity linear to the value of the code. The\n// assumption is that looking up astral identifier characters is\n// rare.\nfunction isInAstralSet(code, set) {\n let pos = 0x10000\n for (let i = 0; i < set.length; i += 2) {\n pos += set[i]\n if (pos > code) return false\n pos += set[i + 1]\n if (pos >= code) return true\n }\n}\n\n// Test whether a given character code starts an identifier.\n\nexport function isIdentifierStart(code, astral) {\n if (code < 65) return code === 36\n if (code < 91) return true\n if (code < 97) return code === 95\n if (code < 123) return true\n if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code))\n if (astral === false) return false\n return isInAstralSet(code, astralIdentifierStartCodes)\n}\n\n// Test whether a given character is part of an identifier.\n\nexport function isIdentifierChar(code, astral) {\n if (code < 48) return code === 36\n if (code < 58) return true\n if (code < 65) return false\n if (code < 91) return true\n if (code < 97) return code === 95\n if (code < 123) return true\n if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code))\n if (astral === false) return false\n return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes)\n}\n","// ## Token types\n\n// The assignment of fine-grained, information-carrying type objects\n// allows the tokenizer to store the information it has about a\n// token in a way that is very cheap for the parser to look up.\n\n// All token type variables start with an underscore, to make them\n// easy to recognize.\n\n// The `beforeExpr` property is used to disambiguate between regular\n// expressions and divisions. It is set on all token types that can\n// be followed by an expression (thus, a slash after them would be a\n// regular expression).\n//\n// The `startsExpr` property is used to check if the token ends a\n// `yield` expression. It is set on all token types that either can\n// directly start an expression (like a quotation mark) or can\n// continue an expression (like the body of a string).\n//\n// `isLoop` marks a keyword as starting a loop, which is important\n// to know when parsing a label, in order to allow or disallow\n// continue jumps to that label.\n\nexport class TokenType {\n constructor(label, conf = {}) {\n this.label = label\n this.keyword = conf.keyword\n this.beforeExpr = !!conf.beforeExpr\n this.startsExpr = !!conf.startsExpr\n this.isLoop = !!conf.isLoop\n this.isAssign = !!conf.isAssign\n this.prefix = !!conf.prefix\n this.postfix = !!conf.postfix\n this.binop = conf.binop || null\n this.updateContext = null\n }\n}\n\nfunction binop(name, prec) {\n return new TokenType(name, {beforeExpr: true, binop: prec})\n}\nconst beforeExpr = {beforeExpr: true}, startsExpr = {startsExpr: true}\n\n// Map keyword names to token types.\n\nexport const keywords = {}\n\n// Succinct definitions of keyword token types\nfunction kw(name, options = {}) {\n options.keyword = name\n return keywords[name] = new TokenType(name, options)\n}\n\nexport const types = {\n num: new TokenType(\"num\", startsExpr),\n regexp: new TokenType(\"regexp\", startsExpr),\n string: new TokenType(\"string\", startsExpr),\n name: new TokenType(\"name\", startsExpr),\n eof: new TokenType(\"eof\"),\n\n // Punctuation token types.\n bracketL: new TokenType(\"[\", {beforeExpr: true, startsExpr: true}),\n bracketR: new TokenType(\"]\"),\n braceL: new TokenType(\"{\", {beforeExpr: true, startsExpr: true}),\n braceR: new TokenType(\"}\"),\n parenL: new TokenType(\"(\", {beforeExpr: true, startsExpr: true}),\n parenR: new TokenType(\")\"),\n comma: new TokenType(\",\", beforeExpr),\n semi: new TokenType(\";\", beforeExpr),\n colon: new TokenType(\":\", beforeExpr),\n dot: new TokenType(\".\"),\n question: new TokenType(\"?\", beforeExpr),\n arrow: new TokenType(\"=>\", beforeExpr),\n template: new TokenType(\"template\"),\n invalidTemplate: new TokenType(\"invalidTemplate\"),\n ellipsis: new TokenType(\"...\", beforeExpr),\n backQuote: new TokenType(\"`\", startsExpr),\n dollarBraceL: new TokenType(\"${\", {beforeExpr: true, startsExpr: true}),\n\n // Operators. These carry several kinds of properties to help the\n // parser use them properly (the presence of these properties is\n // what categorizes them as operators).\n //\n // `binop`, when present, specifies that this operator is a binary\n // operator, and will refer to its precedence.\n //\n // `prefix` and `postfix` mark the operator as a prefix or postfix\n // unary operator.\n //\n // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as\n // binary operators with a very low precedence, that should result\n // in AssignmentExpression nodes.\n\n eq: new TokenType(\"=\", {beforeExpr: true, isAssign: true}),\n assign: new TokenType(\"_=\", {beforeExpr: true, isAssign: true}),\n incDec: new TokenType(\"++/--\", {prefix: true, postfix: true, startsExpr: true}),\n prefix: new TokenType(\"!/~\", {beforeExpr: true, prefix: true, startsExpr: true}),\n logicalOR: binop(\"||\", 1),\n logicalAND: binop(\"&&\", 2),\n bitwiseOR: binop(\"|\", 3),\n bitwiseXOR: binop(\"^\", 4),\n bitwiseAND: binop(\"&\", 5),\n equality: binop(\"==/!=/===/!==\", 6),\n relational: binop(\"/<=/>=\", 7),\n bitShift: binop(\"<>/>>>\", 8),\n plusMin: new TokenType(\"+/-\", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}),\n modulo: binop(\"%\", 10),\n star: binop(\"*\", 10),\n slash: binop(\"/\", 10),\n starstar: new TokenType(\"**\", {beforeExpr: true}),\n\n // Keyword token types.\n _break: kw(\"break\"),\n _case: kw(\"case\", beforeExpr),\n _catch: kw(\"catch\"),\n _continue: kw(\"continue\"),\n _debugger: kw(\"debugger\"),\n _default: kw(\"default\", beforeExpr),\n _do: kw(\"do\", {isLoop: true, beforeExpr: true}),\n _else: kw(\"else\", beforeExpr),\n _finally: kw(\"finally\"),\n _for: kw(\"for\", {isLoop: true}),\n _function: kw(\"function\", startsExpr),\n _if: kw(\"if\"),\n _return: kw(\"return\", beforeExpr),\n _switch: kw(\"switch\"),\n _throw: kw(\"throw\", beforeExpr),\n _try: kw(\"try\"),\n _var: kw(\"var\"),\n _const: kw(\"const\"),\n _while: kw(\"while\", {isLoop: true}),\n _with: kw(\"with\"),\n _new: kw(\"new\", {beforeExpr: true, startsExpr: true}),\n _this: kw(\"this\", startsExpr),\n _super: kw(\"super\", startsExpr),\n _class: kw(\"class\", startsExpr),\n _extends: kw(\"extends\", beforeExpr),\n _export: kw(\"export\"),\n _import: kw(\"import\"),\n _null: kw(\"null\", startsExpr),\n _true: kw(\"true\", startsExpr),\n _false: kw(\"false\", startsExpr),\n _in: kw(\"in\", {beforeExpr: true, binop: 7}),\n _instanceof: kw(\"instanceof\", {beforeExpr: true, binop: 7}),\n _typeof: kw(\"typeof\", {beforeExpr: true, prefix: true, startsExpr: true}),\n _void: kw(\"void\", {beforeExpr: true, prefix: true, startsExpr: true}),\n _delete: kw(\"delete\", {beforeExpr: true, prefix: true, startsExpr: true})\n}\n","// Matches a whole line break (where CRLF is considered a single\n// line break). Used to count lines.\n\nexport const lineBreak = /\\r\\n?|\\n|\\u2028|\\u2029/\nexport const lineBreakG = new RegExp(lineBreak.source, \"g\")\n\nexport function isNewLine(code, ecma2019String) {\n return code === 10 || code === 13 || (!ecma2019String && (code === 0x2028 || code === 0x2029))\n}\n\nexport const nonASCIIwhitespace = /[\\u1680\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]/\n\nexport const skipWhiteSpace = /(?:\\s|\\/\\/.*|\\/\\*[^]*?\\*\\/)*/g\n","const {hasOwnProperty, toString} = Object.prototype\n\n// Checks if an object has a property.\n\nexport function has(obj, propName) {\n return hasOwnProperty.call(obj, propName)\n}\n\nexport const isArray = Array.isArray || ((obj) => (\n toString.call(obj) === \"[object Array]\"\n))\n\nexport function wordsRegexp(words) {\n return new RegExp(\"^(?:\" + words.replace(/ /g, \"|\") + \")$\")\n}\n","import {lineBreakG} from \"./whitespace\"\n\n// These are used when `options.locations` is on, for the\n// `startLoc` and `endLoc` properties.\n\nexport class Position {\n constructor(line, col) {\n this.line = line\n this.column = col\n }\n\n offset(n) {\n return new Position(this.line, this.column + n)\n }\n}\n\nexport class SourceLocation {\n constructor(p, start, end) {\n this.start = start\n this.end = end\n if (p.sourceFile !== null) this.source = p.sourceFile\n }\n}\n\n// The `getLineInfo` function is mostly useful when the\n// `locations` option is off (for performance reasons) and you\n// want to find the line/column position for a given character\n// offset. `input` should be the code string that the offset refers\n// into.\n\nexport function getLineInfo(input, offset) {\n for (let line = 1, cur = 0;;) {\n lineBreakG.lastIndex = cur\n let match = lineBreakG.exec(input)\n if (match && match.index < offset) {\n ++line\n cur = match.index + match[0].length\n } else {\n return new Position(line, offset - cur)\n }\n }\n}\n","import {has, isArray} from \"./util\"\nimport {SourceLocation} from \"./locutil\"\n\n// A second optional argument can be given to further configure\n// the parser process. These options are recognized:\n\nexport const defaultOptions = {\n // `ecmaVersion` indicates the ECMAScript version to parse. Must be\n // either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), or 10\n // (2019). This influences support for strict mode, the set of\n // reserved words, and support for new syntax features. The default\n // is 9.\n ecmaVersion: 9,\n // `sourceType` indicates the mode the code should be parsed in.\n // Can be either `\"script\"` or `\"module\"`. This influences global\n // strict mode and parsing of `import` and `export` declarations.\n sourceType: \"script\",\n // `onInsertedSemicolon` can be a callback that will be called\n // when a semicolon is automatically inserted. It will be passed\n // the position of the comma as an offset, and if `locations` is\n // enabled, it is given the location as a `{line, column}` object\n // as second argument.\n onInsertedSemicolon: null,\n // `onTrailingComma` is similar to `onInsertedSemicolon`, but for\n // trailing commas.\n onTrailingComma: null,\n // By default, reserved words are only enforced if ecmaVersion >= 5.\n // Set `allowReserved` to a boolean value to explicitly turn this on\n // an off. When this option has the value \"never\", reserved words\n // and keywords can also not be used as property names.\n allowReserved: null,\n // When enabled, a return at the top level is not considered an\n // error.\n allowReturnOutsideFunction: false,\n // When enabled, import/export statements are not constrained to\n // appearing at the top of the program.\n allowImportExportEverywhere: false,\n // When enabled, await identifiers are allowed to appear at the top-level scope,\n // but they are still not allowed in non-async functions.\n allowAwaitOutsideFunction: false,\n // When enabled, hashbang directive in the beginning of file\n // is allowed and treated as a line comment.\n allowHashBang: false,\n // When `locations` is on, `loc` properties holding objects with\n // `start` and `end` properties in `{line, column}` form (with\n // line being 1-based and column 0-based) will be attached to the\n // nodes.\n locations: false,\n // A function can be passed as `onToken` option, which will\n // cause Acorn to call that function with object in the same\n // format as tokens returned from `tokenizer().getToken()`. Note\n // that you are not allowed to call the parser from the\n // callback—that will corrupt its internal state.\n onToken: null,\n // A function can be passed as `onComment` option, which will\n // cause Acorn to call that function with `(block, text, start,\n // end)` parameters whenever a comment is skipped. `block` is a\n // boolean indicating whether this is a block (`/* */`) comment,\n // `text` is the content of the comment, and `start` and `end` are\n // character offsets that denote the start and end of the comment.\n // When the `locations` option is on, two more parameters are\n // passed, the full `{line, column}` locations of the start and\n // end of the comments. Note that you are not allowed to call the\n // parser from the callback—that will corrupt its internal state.\n onComment: null,\n // Nodes have their start and end characters offsets recorded in\n // `start` and `end` properties (directly on the node, rather than\n // the `loc` object, which holds line/column data. To also add a\n // [semi-standardized][range] `range` property holding a `[start,\n // end]` array with the same numbers, set the `ranges` option to\n // `true`.\n //\n // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678\n ranges: false,\n // It is possible to parse multiple files into a single AST by\n // passing the tree produced by parsing the first file as\n // `program` option in subsequent parses. This will add the\n // toplevel forms of the parsed file to the `Program` (top) node\n // of an existing parse tree.\n program: null,\n // When `locations` is on, you can pass this to record the source\n // file in every node's `loc` object.\n sourceFile: null,\n // This value, if given, is stored in every node, whether\n // `locations` is on or off.\n directSourceFile: null,\n // When enabled, parenthesized expressions are represented by\n // (non-standard) ParenthesizedExpression nodes\n preserveParens: false\n}\n\n// Interpret and default an options object\n\nexport function getOptions(opts) {\n let options = {}\n\n for (let opt in defaultOptions)\n options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt]\n\n if (options.ecmaVersion >= 2015)\n options.ecmaVersion -= 2009\n\n if (options.allowReserved == null)\n options.allowReserved = options.ecmaVersion < 5\n\n if (isArray(options.onToken)) {\n let tokens = options.onToken\n options.onToken = (token) => tokens.push(token)\n }\n if (isArray(options.onComment))\n options.onComment = pushComment(options, options.onComment)\n\n return options\n}\n\nfunction pushComment(options, array) {\n return function(block, text, start, end, startLoc, endLoc) {\n let comment = {\n type: block ? \"Block\" : \"Line\",\n value: text,\n start: start,\n end: end\n }\n if (options.locations)\n comment.loc = new SourceLocation(this, startLoc, endLoc)\n if (options.ranges)\n comment.range = [start, end]\n array.push(comment)\n }\n}\n","// Each scope gets a bitset that may contain these flags\nexport const\n SCOPE_TOP = 1,\n SCOPE_FUNCTION = 2,\n SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION,\n SCOPE_ASYNC = 4,\n SCOPE_GENERATOR = 8,\n SCOPE_ARROW = 16,\n SCOPE_SIMPLE_CATCH = 32,\n SCOPE_SUPER = 64,\n SCOPE_DIRECT_SUPER = 128\n\nexport function functionFlags(async, generator) {\n return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0)\n}\n\n// Used in checkLVal and declareName to determine the type of a binding\nexport const\n BIND_NONE = 0, // Not a binding\n BIND_VAR = 1, // Var-style binding\n BIND_LEXICAL = 2, // Let- or const-style binding\n BIND_FUNCTION = 3, // Function declaration\n BIND_SIMPLE_CATCH = 4, // Simple (identifier pattern) catch binding\n BIND_OUTSIDE = 5 // Special case for function names as bound inside the function\n","import {reservedWords, keywords} from \"./identifier\"\nimport {types as tt} from \"./tokentype\"\nimport {lineBreak} from \"./whitespace\"\nimport {getOptions} from \"./options\"\nimport {wordsRegexp} from \"./util\"\nimport {SCOPE_TOP, SCOPE_FUNCTION, SCOPE_ASYNC, SCOPE_GENERATOR, SCOPE_SUPER, SCOPE_DIRECT_SUPER} from \"./scopeflags\"\n\nexport class Parser {\n constructor(options, input, startPos) {\n this.options = options = getOptions(options)\n this.sourceFile = options.sourceFile\n this.keywords = wordsRegexp(keywords[options.ecmaVersion >= 6 ? 6 : 5])\n let reserved = \"\"\n if (!options.allowReserved) {\n for (let v = options.ecmaVersion;; v--)\n if (reserved = reservedWords[v]) break\n if (options.sourceType === \"module\") reserved += \" await\"\n }\n this.reservedWords = wordsRegexp(reserved)\n let reservedStrict = (reserved ? reserved + \" \" : \"\") + reservedWords.strict\n this.reservedWordsStrict = wordsRegexp(reservedStrict)\n this.reservedWordsStrictBind = wordsRegexp(reservedStrict + \" \" + reservedWords.strictBind)\n this.input = String(input)\n\n // Used to signal to callers of `readWord1` whether the word\n // contained any escape sequences. This is needed because words with\n // escape sequences must not be interpreted as keywords.\n this.containsEsc = false\n\n // Set up token state\n\n // The current position of the tokenizer in the input.\n if (startPos) {\n this.pos = startPos\n this.lineStart = this.input.lastIndexOf(\"\\n\", startPos - 1) + 1\n this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length\n } else {\n this.pos = this.lineStart = 0\n this.curLine = 1\n }\n\n // Properties of the current token:\n // Its type\n this.type = tt.eof\n // For tokens that include more information than their type, the value\n this.value = null\n // Its start and end offset\n this.start = this.end = this.pos\n // And, if locations are used, the {line, column} object\n // corresponding to those offsets\n this.startLoc = this.endLoc = this.curPosition()\n\n // Position information for the previous token\n this.lastTokEndLoc = this.lastTokStartLoc = null\n this.lastTokStart = this.lastTokEnd = this.pos\n\n // The context stack is used to superficially track syntactic\n // context to predict whether a regular expression is allowed in a\n // given position.\n this.context = this.initialContext()\n this.exprAllowed = true\n\n // Figure out if it's a module code.\n this.inModule = options.sourceType === \"module\"\n this.strict = this.inModule || this.strictDirective(this.pos)\n\n // Used to signify the start of a potential arrow function\n this.potentialArrowAt = -1\n\n // Positions to delayed-check that yield/await does not exist in default parameters.\n this.yieldPos = this.awaitPos = this.awaitIdentPos = 0\n // Labels in scope.\n this.labels = []\n // Thus-far undefined exports.\n this.undefinedExports = {}\n\n // If enabled, skip leading hashbang line.\n if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === \"#!\")\n this.skipLineComment(2)\n\n // Scope tracking for duplicate variable names (see scope.js)\n this.scopeStack = []\n this.enterScope(SCOPE_TOP)\n\n // For RegExp validation\n this.regexpState = null\n }\n\n parse() {\n let node = this.options.program || this.startNode()\n this.nextToken()\n return this.parseTopLevel(node)\n }\n\n get inFunction() { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }\n get inGenerator() { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 }\n get inAsync() { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 }\n get allowSuper() { return (this.currentThisScope().flags & SCOPE_SUPER) > 0 }\n get allowDirectSuper() { return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0 }\n get treatFunctionsAsVar() { return this.treatFunctionsAsVarInScope(this.currentScope()) }\n\n // Switch to a getter for 7.0.0.\n inNonArrowFunction() { return (this.currentThisScope().flags & SCOPE_FUNCTION) > 0 }\n\n static extend(...plugins) {\n let cls = this\n for (let i = 0; i < plugins.length; i++) cls = plugins[i](cls)\n return cls\n }\n\n static parse(input, options) {\n return new this(options, input).parse()\n }\n\n static parseExpressionAt(input, pos, options) {\n let parser = new this(options, input, pos)\n parser.nextToken()\n return parser.parseExpression()\n }\n\n static tokenizer(input, options) {\n return new this(options, input)\n }\n}\n","import {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {lineBreak, skipWhiteSpace} from \"./whitespace\"\n\nconst pp = Parser.prototype\n\n// ## Parser utilities\n\nconst literal = /^(?:'((?:\\\\.|[^'])*?)'|\"((?:\\\\.|[^\"])*?)\")/\npp.strictDirective = function(start) {\n for (;;) {\n // Try to find string literal.\n skipWhiteSpace.lastIndex = start\n start += skipWhiteSpace.exec(this.input)[0].length\n let match = literal.exec(this.input.slice(start))\n if (!match) return false\n if ((match[1] || match[2]) === \"use strict\") return true\n start += match[0].length\n\n // Skip semicolon, if any.\n skipWhiteSpace.lastIndex = start\n start += skipWhiteSpace.exec(this.input)[0].length\n if (this.input[start] === \";\")\n start++\n }\n}\n\n// Predicate that tests whether the next token is of the given\n// type, and if yes, consumes it as a side effect.\n\npp.eat = function(type) {\n if (this.type === type) {\n this.next()\n return true\n } else {\n return false\n }\n}\n\n// Tests whether parsed token is a contextual keyword.\n\npp.isContextual = function(name) {\n return this.type === tt.name && this.value === name && !this.containsEsc\n}\n\n// Consumes contextual keyword if possible.\n\npp.eatContextual = function(name) {\n if (!this.isContextual(name)) return false\n this.next()\n return true\n}\n\n// Asserts that following token is given contextual keyword.\n\npp.expectContextual = function(name) {\n if (!this.eatContextual(name)) this.unexpected()\n}\n\n// Test whether a semicolon can be inserted at the current position.\n\npp.canInsertSemicolon = function() {\n return this.type === tt.eof ||\n this.type === tt.braceR ||\n lineBreak.test(this.input.slice(this.lastTokEnd, this.start))\n}\n\npp.insertSemicolon = function() {\n if (this.canInsertSemicolon()) {\n if (this.options.onInsertedSemicolon)\n this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc)\n return true\n }\n}\n\n// Consume a semicolon, or, failing that, see if we are allowed to\n// pretend that there is a semicolon at this position.\n\npp.semicolon = function() {\n if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected()\n}\n\npp.afterTrailingComma = function(tokType, notNext) {\n if (this.type === tokType) {\n if (this.options.onTrailingComma)\n this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc)\n if (!notNext)\n this.next()\n return true\n }\n}\n\n// Expect a token of a given type. If found, consume it, otherwise,\n// raise an unexpected token error.\n\npp.expect = function(type) {\n this.eat(type) || this.unexpected()\n}\n\n// Raise an unexpected token error.\n\npp.unexpected = function(pos) {\n this.raise(pos != null ? pos : this.start, \"Unexpected token\")\n}\n\nexport function DestructuringErrors() {\n this.shorthandAssign =\n this.trailingComma =\n this.parenthesizedAssign =\n this.parenthesizedBind =\n this.doubleProto =\n -1\n}\n\npp.checkPatternErrors = function(refDestructuringErrors, isAssign) {\n if (!refDestructuringErrors) return\n if (refDestructuringErrors.trailingComma > -1)\n this.raiseRecoverable(refDestructuringErrors.trailingComma, \"Comma is not permitted after the rest element\")\n let parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind\n if (parens > -1) this.raiseRecoverable(parens, \"Parenthesized pattern\")\n}\n\npp.checkExpressionErrors = function(refDestructuringErrors, andThrow) {\n if (!refDestructuringErrors) return false\n let {shorthandAssign, doubleProto} = refDestructuringErrors\n if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0\n if (shorthandAssign >= 0)\n this.raise(shorthandAssign, \"Shorthand property assignments are valid only in destructuring patterns\")\n if (doubleProto >= 0)\n this.raiseRecoverable(doubleProto, \"Redefinition of __proto__ property\")\n}\n\npp.checkYieldAwaitInDefaultParams = function() {\n if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos))\n this.raise(this.yieldPos, \"Yield expression cannot be a default value\")\n if (this.awaitPos)\n this.raise(this.awaitPos, \"Await expression cannot be a default value\")\n}\n\npp.isSimpleAssignTarget = function(expr) {\n if (expr.type === \"ParenthesizedExpression\")\n return this.isSimpleAssignTarget(expr.expression)\n return expr.type === \"Identifier\" || expr.type === \"MemberExpression\"\n}\n","import {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {lineBreak, skipWhiteSpace} from \"./whitespace\"\nimport {isIdentifierStart, isIdentifierChar, keywordRelationalOperator} from \"./identifier\"\nimport {has} from \"./util\"\nimport {DestructuringErrors} from \"./parseutil\"\nimport {functionFlags, SCOPE_SIMPLE_CATCH, BIND_SIMPLE_CATCH, BIND_LEXICAL, BIND_VAR, BIND_FUNCTION} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\n// ### Statement parsing\n\n// Parse a program. Initializes the parser, reads any number of\n// statements, and wraps them in a Program node. Optionally takes a\n// `program` argument. If present, the statements will be appended\n// to its body instead of creating a new node.\n\npp.parseTopLevel = function(node) {\n let exports = {}\n if (!node.body) node.body = []\n while (this.type !== tt.eof) {\n let stmt = this.parseStatement(null, true, exports)\n node.body.push(stmt)\n }\n if (this.inModule)\n for (let name of Object.keys(this.undefinedExports))\n this.raiseRecoverable(this.undefinedExports[name].start, `Export '${name}' is not defined`)\n this.adaptDirectivePrologue(node.body)\n this.next()\n if (this.options.ecmaVersion >= 6) {\n node.sourceType = this.options.sourceType\n }\n return this.finishNode(node, \"Program\")\n}\n\nconst loopLabel = {kind: \"loop\"}, switchLabel = {kind: \"switch\"}\n\npp.isLet = function(context) {\n if (this.options.ecmaVersion < 6 || !this.isContextual(\"let\")) return false\n skipWhiteSpace.lastIndex = this.pos\n let skip = skipWhiteSpace.exec(this.input)\n let next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next)\n // For ambiguous cases, determine if a LexicalDeclaration (or only a\n // Statement) is allowed here. If context is not empty then only a Statement\n // is allowed. However, `let [` is an explicit negative lookahead for\n // ExpressionStatement, so special-case it first.\n if (nextCh === 91) return true // '['\n if (context) return false\n\n if (nextCh === 123) return true // '{'\n if (isIdentifierStart(nextCh, true)) {\n let pos = next + 1\n while (isIdentifierChar(this.input.charCodeAt(pos), true)) ++pos\n let ident = this.input.slice(next, pos)\n if (!keywordRelationalOperator.test(ident)) return true\n }\n return false\n}\n\n// check 'async [no LineTerminator here] function'\n// - 'async /*foo*/ function' is OK.\n// - 'async /*\\n*/ function' is invalid.\npp.isAsyncFunction = function() {\n if (this.options.ecmaVersion < 8 || !this.isContextual(\"async\"))\n return false\n\n skipWhiteSpace.lastIndex = this.pos\n let skip = skipWhiteSpace.exec(this.input)\n let next = this.pos + skip[0].length\n return !lineBreak.test(this.input.slice(this.pos, next)) &&\n this.input.slice(next, next + 8) === \"function\" &&\n (next + 8 === this.input.length || !isIdentifierChar(this.input.charAt(next + 8)))\n}\n\n// Parse a single statement.\n//\n// If expecting a statement and finding a slash operator, parse a\n// regular expression literal. This is to handle cases like\n// `if (foo) /blah/.exec(foo)`, where looking at the previous token\n// does not help.\n\npp.parseStatement = function(context, topLevel, exports) {\n let starttype = this.type, node = this.startNode(), kind\n\n if (this.isLet(context)) {\n starttype = tt._var\n kind = \"let\"\n }\n\n // Most types of statements are recognized by the keyword they\n // start with. Many are trivial to parse, some require a bit of\n // complexity.\n\n switch (starttype) {\n case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword)\n case tt._debugger: return this.parseDebuggerStatement(node)\n case tt._do: return this.parseDoStatement(node)\n case tt._for: return this.parseForStatement(node)\n case tt._function:\n // Function as sole body of either an if statement or a labeled statement\n // works, but not when it is part of a labeled statement that is the sole\n // body of an if statement.\n if ((context && (this.strict || context !== \"if\" && context !== \"label\")) && this.options.ecmaVersion >= 6) this.unexpected()\n return this.parseFunctionStatement(node, false, !context)\n case tt._class:\n if (context) this.unexpected()\n return this.parseClass(node, true)\n case tt._if: return this.parseIfStatement(node)\n case tt._return: return this.parseReturnStatement(node)\n case tt._switch: return this.parseSwitchStatement(node)\n case tt._throw: return this.parseThrowStatement(node)\n case tt._try: return this.parseTryStatement(node)\n case tt._const: case tt._var:\n kind = kind || this.value\n if (context && kind !== \"var\") this.unexpected()\n return this.parseVarStatement(node, kind)\n case tt._while: return this.parseWhileStatement(node)\n case tt._with: return this.parseWithStatement(node)\n case tt.braceL: return this.parseBlock(true, node)\n case tt.semi: return this.parseEmptyStatement(node)\n case tt._export:\n case tt._import:\n if (!this.options.allowImportExportEverywhere) {\n if (!topLevel)\n this.raise(this.start, \"'import' and 'export' may only appear at the top level\")\n if (!this.inModule)\n this.raise(this.start, \"'import' and 'export' may appear only with 'sourceType: module'\")\n }\n return starttype === tt._import ? this.parseImport(node) : this.parseExport(node, exports)\n\n // If the statement does not start with a statement keyword or a\n // brace, it's an ExpressionStatement or LabeledStatement. We\n // simply start parsing an expression, and afterwards, if the\n // next token is a colon and the expression was a simple\n // Identifier node, we switch to interpreting it as a label.\n default:\n if (this.isAsyncFunction()) {\n if (context) this.unexpected()\n this.next()\n return this.parseFunctionStatement(node, true, !context)\n }\n\n let maybeName = this.value, expr = this.parseExpression()\n if (starttype === tt.name && expr.type === \"Identifier\" && this.eat(tt.colon))\n return this.parseLabeledStatement(node, maybeName, expr, context)\n else return this.parseExpressionStatement(node, expr)\n }\n}\n\npp.parseBreakContinueStatement = function(node, keyword) {\n let isBreak = keyword === \"break\"\n this.next()\n if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null\n else if (this.type !== tt.name) this.unexpected()\n else {\n node.label = this.parseIdent()\n this.semicolon()\n }\n\n // Verify that there is an actual destination to break or\n // continue to.\n let i = 0\n for (; i < this.labels.length; ++i) {\n let lab = this.labels[i]\n if (node.label == null || lab.name === node.label.name) {\n if (lab.kind != null && (isBreak || lab.kind === \"loop\")) break\n if (node.label && isBreak) break\n }\n }\n if (i === this.labels.length) this.raise(node.start, \"Unsyntactic \" + keyword)\n return this.finishNode(node, isBreak ? \"BreakStatement\" : \"ContinueStatement\")\n}\n\npp.parseDebuggerStatement = function(node) {\n this.next()\n this.semicolon()\n return this.finishNode(node, \"DebuggerStatement\")\n}\n\npp.parseDoStatement = function(node) {\n this.next()\n this.labels.push(loopLabel)\n node.body = this.parseStatement(\"do\")\n this.labels.pop()\n this.expect(tt._while)\n node.test = this.parseParenExpression()\n if (this.options.ecmaVersion >= 6)\n this.eat(tt.semi)\n else\n this.semicolon()\n return this.finishNode(node, \"DoWhileStatement\")\n}\n\n// Disambiguating between a `for` and a `for`/`in` or `for`/`of`\n// loop is non-trivial. Basically, we have to parse the init `var`\n// statement or expression, disallowing the `in` operator (see\n// the second parameter to `parseExpression`), and then check\n// whether the next token is `in` or `of`. When there is no init\n// part (semicolon immediately after the opening parenthesis), it\n// is a regular `for` loop.\n\npp.parseForStatement = function(node) {\n this.next()\n let awaitAt = (this.options.ecmaVersion >= 9 && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction)) && this.eatContextual(\"await\")) ? this.lastTokStart : -1\n this.labels.push(loopLabel)\n this.enterScope(0)\n this.expect(tt.parenL)\n if (this.type === tt.semi) {\n if (awaitAt > -1) this.unexpected(awaitAt)\n return this.parseFor(node, null)\n }\n let isLet = this.isLet()\n if (this.type === tt._var || this.type === tt._const || isLet) {\n let init = this.startNode(), kind = isLet ? \"let\" : this.value\n this.next()\n this.parseVar(init, true, kind)\n this.finishNode(init, \"VariableDeclaration\")\n if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual(\"of\"))) && init.declarations.length === 1 &&\n !(kind !== \"var\" && init.declarations[0].init)) {\n if (this.options.ecmaVersion >= 9) {\n if (this.type === tt._in) {\n if (awaitAt > -1) this.unexpected(awaitAt)\n } else node.await = awaitAt > -1\n }\n return this.parseForIn(node, init)\n }\n if (awaitAt > -1) this.unexpected(awaitAt)\n return this.parseFor(node, init)\n }\n let refDestructuringErrors = new DestructuringErrors\n let init = this.parseExpression(true, refDestructuringErrors)\n if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual(\"of\"))) {\n if (this.options.ecmaVersion >= 9) {\n if (this.type === tt._in) {\n if (awaitAt > -1) this.unexpected(awaitAt)\n } else node.await = awaitAt > -1\n }\n this.toAssignable(init, false, refDestructuringErrors)\n this.checkLVal(init)\n return this.parseForIn(node, init)\n } else {\n this.checkExpressionErrors(refDestructuringErrors, true)\n }\n if (awaitAt > -1) this.unexpected(awaitAt)\n return this.parseFor(node, init)\n}\n\npp.parseFunctionStatement = function(node, isAsync, declarationPosition) {\n this.next()\n return this.parseFunction(node, FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT), false, isAsync)\n}\n\npp.parseIfStatement = function(node) {\n this.next()\n node.test = this.parseParenExpression()\n // allow function declarations in branches, but only in non-strict mode\n node.consequent = this.parseStatement(\"if\")\n node.alternate = this.eat(tt._else) ? this.parseStatement(\"if\") : null\n return this.finishNode(node, \"IfStatement\")\n}\n\npp.parseReturnStatement = function(node) {\n if (!this.inFunction && !this.options.allowReturnOutsideFunction)\n this.raise(this.start, \"'return' outside of function\")\n this.next()\n\n // In `return` (and `break`/`continue`), the keywords with\n // optional arguments, we eagerly look for a semicolon or the\n // possibility to insert one.\n\n if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null\n else { node.argument = this.parseExpression(); this.semicolon() }\n return this.finishNode(node, \"ReturnStatement\")\n}\n\npp.parseSwitchStatement = function(node) {\n this.next()\n node.discriminant = this.parseParenExpression()\n node.cases = []\n this.expect(tt.braceL)\n this.labels.push(switchLabel)\n this.enterScope(0)\n\n // Statements under must be grouped (by label) in SwitchCase\n // nodes. `cur` is used to keep the node that we are currently\n // adding statements to.\n\n let cur\n for (let sawDefault = false; this.type !== tt.braceR;) {\n if (this.type === tt._case || this.type === tt._default) {\n let isCase = this.type === tt._case\n if (cur) this.finishNode(cur, \"SwitchCase\")\n node.cases.push(cur = this.startNode())\n cur.consequent = []\n this.next()\n if (isCase) {\n cur.test = this.parseExpression()\n } else {\n if (sawDefault) this.raiseRecoverable(this.lastTokStart, \"Multiple default clauses\")\n sawDefault = true\n cur.test = null\n }\n this.expect(tt.colon)\n } else {\n if (!cur) this.unexpected()\n cur.consequent.push(this.parseStatement(null))\n }\n }\n this.exitScope()\n if (cur) this.finishNode(cur, \"SwitchCase\")\n this.next() // Closing brace\n this.labels.pop()\n return this.finishNode(node, \"SwitchStatement\")\n}\n\npp.parseThrowStatement = function(node) {\n this.next()\n if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start)))\n this.raise(this.lastTokEnd, \"Illegal newline after throw\")\n node.argument = this.parseExpression()\n this.semicolon()\n return this.finishNode(node, \"ThrowStatement\")\n}\n\n// Reused empty array added for node fields that are always empty.\n\nconst empty = []\n\npp.parseTryStatement = function(node) {\n this.next()\n node.block = this.parseBlock()\n node.handler = null\n if (this.type === tt._catch) {\n let clause = this.startNode()\n this.next()\n if (this.eat(tt.parenL)) {\n clause.param = this.parseBindingAtom()\n let simple = clause.param.type === \"Identifier\"\n this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0)\n this.checkLVal(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL)\n this.expect(tt.parenR)\n } else {\n if (this.options.ecmaVersion < 10) this.unexpected()\n clause.param = null\n this.enterScope(0)\n }\n clause.body = this.parseBlock(false)\n this.exitScope()\n node.handler = this.finishNode(clause, \"CatchClause\")\n }\n node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null\n if (!node.handler && !node.finalizer)\n this.raise(node.start, \"Missing catch or finally clause\")\n return this.finishNode(node, \"TryStatement\")\n}\n\npp.parseVarStatement = function(node, kind) {\n this.next()\n this.parseVar(node, false, kind)\n this.semicolon()\n return this.finishNode(node, \"VariableDeclaration\")\n}\n\npp.parseWhileStatement = function(node) {\n this.next()\n node.test = this.parseParenExpression()\n this.labels.push(loopLabel)\n node.body = this.parseStatement(\"while\")\n this.labels.pop()\n return this.finishNode(node, \"WhileStatement\")\n}\n\npp.parseWithStatement = function(node) {\n if (this.strict) this.raise(this.start, \"'with' in strict mode\")\n this.next()\n node.object = this.parseParenExpression()\n node.body = this.parseStatement(\"with\")\n return this.finishNode(node, \"WithStatement\")\n}\n\npp.parseEmptyStatement = function(node) {\n this.next()\n return this.finishNode(node, \"EmptyStatement\")\n}\n\npp.parseLabeledStatement = function(node, maybeName, expr, context) {\n for (let label of this.labels)\n if (label.name === maybeName)\n this.raise(expr.start, \"Label '\" + maybeName + \"' is already declared\")\n let kind = this.type.isLoop ? \"loop\" : this.type === tt._switch ? \"switch\" : null\n for (let i = this.labels.length - 1; i >= 0; i--) {\n let label = this.labels[i]\n if (label.statementStart === node.start) {\n // Update information about previous labels on this node\n label.statementStart = this.start\n label.kind = kind\n } else break\n }\n this.labels.push({name: maybeName, kind, statementStart: this.start})\n node.body = this.parseStatement(context ? context.indexOf(\"label\") === -1 ? context + \"label\" : context : \"label\")\n this.labels.pop()\n node.label = expr\n return this.finishNode(node, \"LabeledStatement\")\n}\n\npp.parseExpressionStatement = function(node, expr) {\n node.expression = expr\n this.semicolon()\n return this.finishNode(node, \"ExpressionStatement\")\n}\n\n// Parse a semicolon-enclosed block of statements, handling `\"use\n// strict\"` declarations when `allowStrict` is true (used for\n// function bodies).\n\npp.parseBlock = function(createNewLexicalScope = true, node = this.startNode()) {\n node.body = []\n this.expect(tt.braceL)\n if (createNewLexicalScope) this.enterScope(0)\n while (!this.eat(tt.braceR)) {\n let stmt = this.parseStatement(null)\n node.body.push(stmt)\n }\n if (createNewLexicalScope) this.exitScope()\n return this.finishNode(node, \"BlockStatement\")\n}\n\n// Parse a regular `for` loop. The disambiguation code in\n// `parseStatement` will already have parsed the init statement or\n// expression.\n\npp.parseFor = function(node, init) {\n node.init = init\n this.expect(tt.semi)\n node.test = this.type === tt.semi ? null : this.parseExpression()\n this.expect(tt.semi)\n node.update = this.type === tt.parenR ? null : this.parseExpression()\n this.expect(tt.parenR)\n node.body = this.parseStatement(\"for\")\n this.exitScope()\n this.labels.pop()\n return this.finishNode(node, \"ForStatement\")\n}\n\n// Parse a `for`/`in` and `for`/`of` loop, which are almost\n// same from parser's perspective.\n\npp.parseForIn = function(node, init) {\n let type = this.type === tt._in ? \"ForInStatement\" : \"ForOfStatement\"\n this.next()\n if (type === \"ForInStatement\") {\n if (init.type === \"AssignmentPattern\" ||\n (init.type === \"VariableDeclaration\" && init.declarations[0].init != null &&\n (this.strict || init.declarations[0].id.type !== \"Identifier\")))\n this.raise(init.start, \"Invalid assignment in for-in loop head\")\n }\n node.left = init\n node.right = type === \"ForInStatement\" ? this.parseExpression() : this.parseMaybeAssign()\n this.expect(tt.parenR)\n node.body = this.parseStatement(\"for\")\n this.exitScope()\n this.labels.pop()\n return this.finishNode(node, type)\n}\n\n// Parse a list of variable declarations.\n\npp.parseVar = function(node, isFor, kind) {\n node.declarations = []\n node.kind = kind\n for (;;) {\n let decl = this.startNode()\n this.parseVarId(decl, kind)\n if (this.eat(tt.eq)) {\n decl.init = this.parseMaybeAssign(isFor)\n } else if (kind === \"const\" && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual(\"of\")))) {\n this.unexpected()\n } else if (decl.id.type !== \"Identifier\" && !(isFor && (this.type === tt._in || this.isContextual(\"of\")))) {\n this.raise(this.lastTokEnd, \"Complex binding patterns require an initialization value\")\n } else {\n decl.init = null\n }\n node.declarations.push(this.finishNode(decl, \"VariableDeclarator\"))\n if (!this.eat(tt.comma)) break\n }\n return node\n}\n\npp.parseVarId = function(decl, kind) {\n if ((kind === \"const\" || kind === \"let\") && this.isContextual(\"let\")) {\n this.raiseRecoverable(this.start, \"let is disallowed as a lexically bound name\")\n }\n decl.id = this.parseBindingAtom()\n this.checkLVal(decl.id, kind === \"var\" ? BIND_VAR : BIND_LEXICAL, false)\n}\n\nconst FUNC_STATEMENT = 1, FUNC_HANGING_STATEMENT = 2, FUNC_NULLABLE_ID = 4\n\n// Parse a function declaration or literal (depending on the\n// `statement & FUNC_STATEMENT`).\n\n// Remove `allowExpressionBody` for 7.0.0, as it is only called with false\npp.parseFunction = function(node, statement, allowExpressionBody, isAsync) {\n this.initFunction(node)\n if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync) {\n if (this.type === tt.star && (statement & FUNC_HANGING_STATEMENT))\n this.unexpected()\n node.generator = this.eat(tt.star)\n }\n if (this.options.ecmaVersion >= 8)\n node.async = !!isAsync\n\n if (statement & FUNC_STATEMENT) {\n node.id = (statement & FUNC_NULLABLE_ID) && this.type !== tt.name ? null : this.parseIdent()\n if (node.id && !(statement & FUNC_HANGING_STATEMENT))\n // If it is a regular function declaration in sloppy mode, then it is\n // subject to Annex B semantics (BIND_FUNCTION). Otherwise, the binding\n // mode depends on properties of the current scope (see\n // treatFunctionsAsVar).\n this.checkLVal(node.id, (this.strict || node.generator || node.async) ? this.treatFunctionsAsVar ? BIND_VAR : BIND_LEXICAL : BIND_FUNCTION)\n }\n\n let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos\n this.yieldPos = 0\n this.awaitPos = 0\n this.awaitIdentPos = 0\n this.enterScope(functionFlags(node.async, node.generator))\n\n if (!(statement & FUNC_STATEMENT))\n node.id = this.type === tt.name ? this.parseIdent() : null\n\n this.parseFunctionParams(node)\n this.parseFunctionBody(node, allowExpressionBody, false)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n this.awaitIdentPos = oldAwaitIdentPos\n return this.finishNode(node, (statement & FUNC_STATEMENT) ? \"FunctionDeclaration\" : \"FunctionExpression\")\n}\n\npp.parseFunctionParams = function(node) {\n this.expect(tt.parenL)\n node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8)\n this.checkYieldAwaitInDefaultParams()\n}\n\n// Parse a class declaration or literal (depending on the\n// `isStatement` parameter).\n\npp.parseClass = function(node, isStatement) {\n this.next()\n\n // ecma-262 14.6 Class Definitions\n // A class definition is always strict mode code.\n const oldStrict = this.strict\n this.strict = true\n\n this.parseClassId(node, isStatement)\n this.parseClassSuper(node)\n let classBody = this.startNode()\n let hadConstructor = false\n classBody.body = []\n this.expect(tt.braceL)\n while (!this.eat(tt.braceR)) {\n const element = this.parseClassElement(node.superClass !== null)\n if (element) {\n classBody.body.push(element)\n if (element.type === \"MethodDefinition\" && element.kind === \"constructor\") {\n if (hadConstructor) this.raise(element.start, \"Duplicate constructor in the same class\")\n hadConstructor = true\n }\n }\n }\n node.body = this.finishNode(classBody, \"ClassBody\")\n this.strict = oldStrict\n return this.finishNode(node, isStatement ? \"ClassDeclaration\" : \"ClassExpression\")\n}\n\npp.parseClassElement = function(constructorAllowsSuper) {\n if (this.eat(tt.semi)) return null\n\n let method = this.startNode()\n const tryContextual = (k, noLineBreak = false) => {\n const start = this.start, startLoc = this.startLoc\n if (!this.eatContextual(k)) return false\n if (this.type !== tt.parenL && (!noLineBreak || !this.canInsertSemicolon())) return true\n if (method.key) this.unexpected()\n method.computed = false\n method.key = this.startNodeAt(start, startLoc)\n method.key.name = k\n this.finishNode(method.key, \"Identifier\")\n return false\n }\n\n method.kind = \"method\"\n method.static = tryContextual(\"static\")\n let isGenerator = this.eat(tt.star)\n let isAsync = false\n if (!isGenerator) {\n if (this.options.ecmaVersion >= 8 && tryContextual(\"async\", true)) {\n isAsync = true\n isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star)\n } else if (tryContextual(\"get\")) {\n method.kind = \"get\"\n } else if (tryContextual(\"set\")) {\n method.kind = \"set\"\n }\n }\n if (!method.key) this.parsePropertyName(method)\n let {key} = method\n let allowsDirectSuper = false\n if (!method.computed && !method.static && (key.type === \"Identifier\" && key.name === \"constructor\" ||\n key.type === \"Literal\" && key.value === \"constructor\")) {\n if (method.kind !== \"method\") this.raise(key.start, \"Constructor can't have get/set modifier\")\n if (isGenerator) this.raise(key.start, \"Constructor can't be a generator\")\n if (isAsync) this.raise(key.start, \"Constructor can't be an async method\")\n method.kind = \"constructor\"\n allowsDirectSuper = constructorAllowsSuper\n } else if (method.static && key.type === \"Identifier\" && key.name === \"prototype\") {\n this.raise(key.start, \"Classes may not have a static property named prototype\")\n }\n this.parseClassMethod(method, isGenerator, isAsync, allowsDirectSuper)\n if (method.kind === \"get\" && method.value.params.length !== 0)\n this.raiseRecoverable(method.value.start, \"getter should have no params\")\n if (method.kind === \"set\" && method.value.params.length !== 1)\n this.raiseRecoverable(method.value.start, \"setter should have exactly one param\")\n if (method.kind === \"set\" && method.value.params[0].type === \"RestElement\")\n this.raiseRecoverable(method.value.params[0].start, \"Setter cannot use rest params\")\n return method\n}\n\npp.parseClassMethod = function(method, isGenerator, isAsync, allowsDirectSuper) {\n method.value = this.parseMethod(isGenerator, isAsync, allowsDirectSuper)\n return this.finishNode(method, \"MethodDefinition\")\n}\n\npp.parseClassId = function(node, isStatement) {\n if (this.type === tt.name) {\n node.id = this.parseIdent()\n if (isStatement === true)\n this.checkLVal(node.id, BIND_LEXICAL, false)\n } else {\n if (isStatement === true)\n this.unexpected()\n node.id = null\n }\n}\n\npp.parseClassSuper = function(node) {\n node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null\n}\n\n// Parses module export declaration.\n\npp.parseExport = function(node, exports) {\n this.next()\n // export * from '...'\n if (this.eat(tt.star)) {\n this.expectContextual(\"from\")\n if (this.type !== tt.string) this.unexpected()\n node.source = this.parseExprAtom()\n this.semicolon()\n return this.finishNode(node, \"ExportAllDeclaration\")\n }\n if (this.eat(tt._default)) { // export default ...\n this.checkExport(exports, \"default\", this.lastTokStart)\n let isAsync\n if (this.type === tt._function || (isAsync = this.isAsyncFunction())) {\n let fNode = this.startNode()\n this.next()\n if (isAsync) this.next()\n node.declaration = this.parseFunction(fNode, FUNC_STATEMENT | FUNC_NULLABLE_ID, false, isAsync)\n } else if (this.type === tt._class) {\n let cNode = this.startNode()\n node.declaration = this.parseClass(cNode, \"nullableID\")\n } else {\n node.declaration = this.parseMaybeAssign()\n this.semicolon()\n }\n return this.finishNode(node, \"ExportDefaultDeclaration\")\n }\n // export var|const|let|function|class ...\n if (this.shouldParseExportStatement()) {\n node.declaration = this.parseStatement(null)\n if (node.declaration.type === \"VariableDeclaration\")\n this.checkVariableExport(exports, node.declaration.declarations)\n else\n this.checkExport(exports, node.declaration.id.name, node.declaration.id.start)\n node.specifiers = []\n node.source = null\n } else { // export { x, y as z } [from '...']\n node.declaration = null\n node.specifiers = this.parseExportSpecifiers(exports)\n if (this.eatContextual(\"from\")) {\n if (this.type !== tt.string) this.unexpected()\n node.source = this.parseExprAtom()\n } else {\n for (let spec of node.specifiers) {\n // check for keywords used as local names\n this.checkUnreserved(spec.local)\n // check if export is defined\n this.checkLocalExport(spec.local)\n }\n\n node.source = null\n }\n this.semicolon()\n }\n return this.finishNode(node, \"ExportNamedDeclaration\")\n}\n\npp.checkExport = function(exports, name, pos) {\n if (!exports) return\n if (has(exports, name))\n this.raiseRecoverable(pos, \"Duplicate export '\" + name + \"'\")\n exports[name] = true\n}\n\npp.checkPatternExport = function(exports, pat) {\n let type = pat.type\n if (type === \"Identifier\")\n this.checkExport(exports, pat.name, pat.start)\n else if (type === \"ObjectPattern\")\n for (let prop of pat.properties)\n this.checkPatternExport(exports, prop)\n else if (type === \"ArrayPattern\")\n for (let elt of pat.elements) {\n if (elt) this.checkPatternExport(exports, elt)\n }\n else if (type === \"Property\")\n this.checkPatternExport(exports, pat.value)\n else if (type === \"AssignmentPattern\")\n this.checkPatternExport(exports, pat.left)\n else if (type === \"RestElement\")\n this.checkPatternExport(exports, pat.argument)\n else if (type === \"ParenthesizedExpression\")\n this.checkPatternExport(exports, pat.expression)\n}\n\npp.checkVariableExport = function(exports, decls) {\n if (!exports) return\n for (let decl of decls)\n this.checkPatternExport(exports, decl.id)\n}\n\npp.shouldParseExportStatement = function() {\n return this.type.keyword === \"var\" ||\n this.type.keyword === \"const\" ||\n this.type.keyword === \"class\" ||\n this.type.keyword === \"function\" ||\n this.isLet() ||\n this.isAsyncFunction()\n}\n\n// Parses a comma-separated list of module exports.\n\npp.parseExportSpecifiers = function(exports) {\n let nodes = [], first = true\n // export { x, y as z } [from '...']\n this.expect(tt.braceL)\n while (!this.eat(tt.braceR)) {\n if (!first) {\n this.expect(tt.comma)\n if (this.afterTrailingComma(tt.braceR)) break\n } else first = false\n\n let node = this.startNode()\n node.local = this.parseIdent(true)\n node.exported = this.eatContextual(\"as\") ? this.parseIdent(true) : node.local\n this.checkExport(exports, node.exported.name, node.exported.start)\n nodes.push(this.finishNode(node, \"ExportSpecifier\"))\n }\n return nodes\n}\n\n// Parses import declaration.\n\npp.parseImport = function(node) {\n this.next()\n // import '...'\n if (this.type === tt.string) {\n node.specifiers = empty\n node.source = this.parseExprAtom()\n } else {\n node.specifiers = this.parseImportSpecifiers()\n this.expectContextual(\"from\")\n node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected()\n }\n this.semicolon()\n return this.finishNode(node, \"ImportDeclaration\")\n}\n\n// Parses a comma-separated list of module imports.\n\npp.parseImportSpecifiers = function() {\n let nodes = [], first = true\n if (this.type === tt.name) {\n // import defaultObj, { x, y as z } from '...'\n let node = this.startNode()\n node.local = this.parseIdent()\n this.checkLVal(node.local, BIND_LEXICAL)\n nodes.push(this.finishNode(node, \"ImportDefaultSpecifier\"))\n if (!this.eat(tt.comma)) return nodes\n }\n if (this.type === tt.star) {\n let node = this.startNode()\n this.next()\n this.expectContextual(\"as\")\n node.local = this.parseIdent()\n this.checkLVal(node.local, BIND_LEXICAL)\n nodes.push(this.finishNode(node, \"ImportNamespaceSpecifier\"))\n return nodes\n }\n this.expect(tt.braceL)\n while (!this.eat(tt.braceR)) {\n if (!first) {\n this.expect(tt.comma)\n if (this.afterTrailingComma(tt.braceR)) break\n } else first = false\n\n let node = this.startNode()\n node.imported = this.parseIdent(true)\n if (this.eatContextual(\"as\")) {\n node.local = this.parseIdent()\n } else {\n this.checkUnreserved(node.imported)\n node.local = node.imported\n }\n this.checkLVal(node.local, BIND_LEXICAL)\n nodes.push(this.finishNode(node, \"ImportSpecifier\"))\n }\n return nodes\n}\n\n// Set `ExpressionStatement#directive` property for directive prologues.\npp.adaptDirectivePrologue = function(statements) {\n for (let i = 0; i < statements.length && this.isDirectiveCandidate(statements[i]); ++i) {\n statements[i].directive = statements[i].expression.raw.slice(1, -1)\n }\n}\npp.isDirectiveCandidate = function(statement) {\n return (\n statement.type === \"ExpressionStatement\" &&\n statement.expression.type === \"Literal\" &&\n typeof statement.expression.value === \"string\" &&\n // Reject parenthesized strings.\n (this.input[statement.start] === \"\\\"\" || this.input[statement.start] === \"'\")\n )\n}\n","import {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {has} from \"./util\"\nimport {BIND_NONE, BIND_OUTSIDE} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\n// Convert existing expression atom to assignable pattern\n// if possible.\n\npp.toAssignable = function(node, isBinding, refDestructuringErrors) {\n if (this.options.ecmaVersion >= 6 && node) {\n switch (node.type) {\n case \"Identifier\":\n if (this.inAsync && node.name === \"await\")\n this.raise(node.start, \"Cannot use 'await' as identifier inside an async function\")\n break\n\n case \"ObjectPattern\":\n case \"ArrayPattern\":\n case \"RestElement\":\n break\n\n case \"ObjectExpression\":\n node.type = \"ObjectPattern\"\n if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true)\n for (let prop of node.properties) {\n this.toAssignable(prop, isBinding)\n // Early error:\n // AssignmentRestProperty[Yield, Await] :\n // `...` DestructuringAssignmentTarget[Yield, Await]\n //\n // It is a Syntax Error if |DestructuringAssignmentTarget| is an |ArrayLiteral| or an |ObjectLiteral|.\n if (\n prop.type === \"RestElement\" &&\n (prop.argument.type === \"ArrayPattern\" || prop.argument.type === \"ObjectPattern\")\n ) {\n this.raise(prop.argument.start, \"Unexpected token\")\n }\n }\n break\n\n case \"Property\":\n // AssignmentProperty has type === \"Property\"\n if (node.kind !== \"init\") this.raise(node.key.start, \"Object pattern can't contain getter or setter\")\n this.toAssignable(node.value, isBinding)\n break\n\n case \"ArrayExpression\":\n node.type = \"ArrayPattern\"\n if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true)\n this.toAssignableList(node.elements, isBinding)\n break\n\n case \"SpreadElement\":\n node.type = \"RestElement\"\n this.toAssignable(node.argument, isBinding)\n if (node.argument.type === \"AssignmentPattern\")\n this.raise(node.argument.start, \"Rest elements cannot have a default value\")\n break\n\n case \"AssignmentExpression\":\n if (node.operator !== \"=\") this.raise(node.left.end, \"Only '=' operator can be used for specifying default value.\")\n node.type = \"AssignmentPattern\"\n delete node.operator\n this.toAssignable(node.left, isBinding)\n // falls through to AssignmentPattern\n\n case \"AssignmentPattern\":\n break\n\n case \"ParenthesizedExpression\":\n this.toAssignable(node.expression, isBinding, refDestructuringErrors)\n break\n\n case \"MemberExpression\":\n if (!isBinding) break\n\n default:\n this.raise(node.start, \"Assigning to rvalue\")\n }\n } else if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true)\n return node\n}\n\n// Convert list of expression atoms to binding list.\n\npp.toAssignableList = function(exprList, isBinding) {\n let end = exprList.length\n for (let i = 0; i < end; i++) {\n let elt = exprList[i]\n if (elt) this.toAssignable(elt, isBinding)\n }\n if (end) {\n let last = exprList[end - 1]\n if (this.options.ecmaVersion === 6 && isBinding && last && last.type === \"RestElement\" && last.argument.type !== \"Identifier\")\n this.unexpected(last.argument.start)\n }\n return exprList\n}\n\n// Parses spread element.\n\npp.parseSpread = function(refDestructuringErrors) {\n let node = this.startNode()\n this.next()\n node.argument = this.parseMaybeAssign(false, refDestructuringErrors)\n return this.finishNode(node, \"SpreadElement\")\n}\n\npp.parseRestBinding = function() {\n let node = this.startNode()\n this.next()\n\n // RestElement inside of a function parameter must be an identifier\n if (this.options.ecmaVersion === 6 && this.type !== tt.name)\n this.unexpected()\n\n node.argument = this.parseBindingAtom()\n\n return this.finishNode(node, \"RestElement\")\n}\n\n// Parses lvalue (assignable) atom.\n\npp.parseBindingAtom = function() {\n if (this.options.ecmaVersion >= 6) {\n switch (this.type) {\n case tt.bracketL:\n let node = this.startNode()\n this.next()\n node.elements = this.parseBindingList(tt.bracketR, true, true)\n return this.finishNode(node, \"ArrayPattern\")\n\n case tt.braceL:\n return this.parseObj(true)\n }\n }\n return this.parseIdent()\n}\n\npp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {\n let elts = [], first = true\n while (!this.eat(close)) {\n if (first) first = false\n else this.expect(tt.comma)\n if (allowEmpty && this.type === tt.comma) {\n elts.push(null)\n } else if (allowTrailingComma && this.afterTrailingComma(close)) {\n break\n } else if (this.type === tt.ellipsis) {\n let rest = this.parseRestBinding()\n this.parseBindingListItem(rest)\n elts.push(rest)\n if (this.type === tt.comma) this.raise(this.start, \"Comma is not permitted after the rest element\")\n this.expect(close)\n break\n } else {\n let elem = this.parseMaybeDefault(this.start, this.startLoc)\n this.parseBindingListItem(elem)\n elts.push(elem)\n }\n }\n return elts\n}\n\npp.parseBindingListItem = function(param) {\n return param\n}\n\n// Parses assignment pattern around given atom if possible.\n\npp.parseMaybeDefault = function(startPos, startLoc, left) {\n left = left || this.parseBindingAtom()\n if (this.options.ecmaVersion < 6 || !this.eat(tt.eq)) return left\n let node = this.startNodeAt(startPos, startLoc)\n node.left = left\n node.right = this.parseMaybeAssign()\n return this.finishNode(node, \"AssignmentPattern\")\n}\n\n// Verify that a node is an lval — something that can be assigned\n// to.\n// bindingType can be either:\n// 'var' indicating that the lval creates a 'var' binding\n// 'let' indicating that the lval creates a lexical ('let' or 'const') binding\n// 'none' indicating that the binding should be checked for illegal identifiers, but not for duplicate references\n\npp.checkLVal = function(expr, bindingType = BIND_NONE, checkClashes) {\n switch (expr.type) {\n case \"Identifier\":\n if (this.strict && this.reservedWordsStrictBind.test(expr.name))\n this.raiseRecoverable(expr.start, (bindingType ? \"Binding \" : \"Assigning to \") + expr.name + \" in strict mode\")\n if (checkClashes) {\n if (has(checkClashes, expr.name))\n this.raiseRecoverable(expr.start, \"Argument name clash\")\n checkClashes[expr.name] = true\n }\n if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) this.declareName(expr.name, bindingType, expr.start)\n break\n\n case \"MemberExpression\":\n if (bindingType) this.raiseRecoverable(expr.start, \"Binding member expression\")\n break\n\n case \"ObjectPattern\":\n for (let prop of expr.properties)\n this.checkLVal(prop, bindingType, checkClashes)\n break\n\n case \"Property\":\n // AssignmentProperty has type === \"Property\"\n this.checkLVal(expr.value, bindingType, checkClashes)\n break\n\n case \"ArrayPattern\":\n for (let elem of expr.elements) {\n if (elem) this.checkLVal(elem, bindingType, checkClashes)\n }\n break\n\n case \"AssignmentPattern\":\n this.checkLVal(expr.left, bindingType, checkClashes)\n break\n\n case \"RestElement\":\n this.checkLVal(expr.argument, bindingType, checkClashes)\n break\n\n case \"ParenthesizedExpression\":\n this.checkLVal(expr.expression, bindingType, checkClashes)\n break\n\n default:\n this.raise(expr.start, (bindingType ? \"Binding\" : \"Assigning to\") + \" rvalue\")\n }\n}\n","// A recursive descent parser operates by defining functions for all\n// syntactic elements, and recursively calling those, each function\n// advancing the input stream and returning an AST node. Precedence\n// of constructs (for example, the fact that `!x[1]` means `!(x[1])`\n// instead of `(!x)[1]` is handled by the fact that the parser\n// function that parses unary prefix operators is called first, and\n// in turn calls the function that parses `[]` subscripts — that\n// way, it'll receive the node for `x[1]` already parsed, and wraps\n// *that* in the unary operator node.\n//\n// Acorn uses an [operator precedence parser][opp] to handle binary\n// operator precedence, because it is much more compact than using\n// the technique outlined above, which uses different, nesting\n// functions to specify precedence, for all of the ten binary\n// precedence levels that JavaScript defines.\n//\n// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser\n\nimport {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {DestructuringErrors} from \"./parseutil\"\nimport {lineBreak} from \"./whitespace\"\nimport {functionFlags, SCOPE_ARROW, SCOPE_SUPER, SCOPE_DIRECT_SUPER, BIND_OUTSIDE, BIND_VAR} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\n// Check if property name clashes with already added.\n// Object/class getters and setters are not allowed to clash —\n// either with each other or with an init property — and in\n// strict mode, init properties are also not allowed to be repeated.\n\npp.checkPropClash = function(prop, propHash, refDestructuringErrors) {\n if (this.options.ecmaVersion >= 9 && prop.type === \"SpreadElement\")\n return\n if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand))\n return\n let {key} = prop, name\n switch (key.type) {\n case \"Identifier\": name = key.name; break\n case \"Literal\": name = String(key.value); break\n default: return\n }\n let {kind} = prop\n if (this.options.ecmaVersion >= 6) {\n if (name === \"__proto__\" && kind === \"init\") {\n if (propHash.proto) {\n if (refDestructuringErrors && refDestructuringErrors.doubleProto < 0) refDestructuringErrors.doubleProto = key.start\n // Backwards-compat kludge. Can be removed in version 6.0\n else this.raiseRecoverable(key.start, \"Redefinition of __proto__ property\")\n }\n propHash.proto = true\n }\n return\n }\n name = \"$\" + name\n let other = propHash[name]\n if (other) {\n let redefinition\n if (kind === \"init\") {\n redefinition = this.strict && other.init || other.get || other.set\n } else {\n redefinition = other.init || other[kind]\n }\n if (redefinition)\n this.raiseRecoverable(key.start, \"Redefinition of property\")\n } else {\n other = propHash[name] = {\n init: false,\n get: false,\n set: false\n }\n }\n other[kind] = true\n}\n\n// ### Expression parsing\n\n// These nest, from the most general expression type at the top to\n// 'atomic', nondivisible expression types at the bottom. Most of\n// the functions will simply let the function(s) below them parse,\n// and, *if* the syntactic construct they handle is present, wrap\n// the AST node that the inner parser gave them in another node.\n\n// Parse a full expression. The optional arguments are used to\n// forbid the `in` operator (in for loops initalization expressions)\n// and provide reference for storing '=' operator inside shorthand\n// property assignment in contexts where both object expression\n// and object pattern might appear (so it's possible to raise\n// delayed syntax error at correct position).\n\npp.parseExpression = function(noIn, refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseMaybeAssign(noIn, refDestructuringErrors)\n if (this.type === tt.comma) {\n let node = this.startNodeAt(startPos, startLoc)\n node.expressions = [expr]\n while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refDestructuringErrors))\n return this.finishNode(node, \"SequenceExpression\")\n }\n return expr\n}\n\n// Parse an assignment expression. This includes applications of\n// operators like `+=`.\n\npp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) {\n if (this.isContextual(\"yield\")) {\n if (this.inGenerator) return this.parseYield(noIn)\n // The tokenizer will assume an expression is allowed after\n // `yield`, but this isn't that kind of yield\n else this.exprAllowed = false\n }\n\n let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1, oldShorthandAssign = -1\n if (refDestructuringErrors) {\n oldParenAssign = refDestructuringErrors.parenthesizedAssign\n oldTrailingComma = refDestructuringErrors.trailingComma\n oldShorthandAssign = refDestructuringErrors.shorthandAssign\n refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.shorthandAssign = -1\n } else {\n refDestructuringErrors = new DestructuringErrors\n ownDestructuringErrors = true\n }\n\n let startPos = this.start, startLoc = this.startLoc\n if (this.type === tt.parenL || this.type === tt.name)\n this.potentialArrowAt = this.start\n let left = this.parseMaybeConditional(noIn, refDestructuringErrors)\n if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc)\n if (this.type.isAssign) {\n let node = this.startNodeAt(startPos, startLoc)\n node.operator = this.value\n node.left = this.type === tt.eq ? this.toAssignable(left, false, refDestructuringErrors) : left\n if (!ownDestructuringErrors) DestructuringErrors.call(refDestructuringErrors)\n refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly\n this.checkLVal(left)\n this.next()\n node.right = this.parseMaybeAssign(noIn)\n return this.finishNode(node, \"AssignmentExpression\")\n } else {\n if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true)\n }\n if (oldParenAssign > -1) refDestructuringErrors.parenthesizedAssign = oldParenAssign\n if (oldTrailingComma > -1) refDestructuringErrors.trailingComma = oldTrailingComma\n if (oldShorthandAssign > -1) refDestructuringErrors.shorthandAssign = oldShorthandAssign\n return left\n}\n\n// Parse a ternary conditional (`?:`) operator.\n\npp.parseMaybeConditional = function(noIn, refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseExprOps(noIn, refDestructuringErrors)\n if (this.checkExpressionErrors(refDestructuringErrors)) return expr\n if (this.eat(tt.question)) {\n let node = this.startNodeAt(startPos, startLoc)\n node.test = expr\n node.consequent = this.parseMaybeAssign()\n this.expect(tt.colon)\n node.alternate = this.parseMaybeAssign(noIn)\n return this.finishNode(node, \"ConditionalExpression\")\n }\n return expr\n}\n\n// Start the precedence parser.\n\npp.parseExprOps = function(noIn, refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseMaybeUnary(refDestructuringErrors, false)\n if (this.checkExpressionErrors(refDestructuringErrors)) return expr\n return expr.start === startPos && expr.type === \"ArrowFunctionExpression\" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn)\n}\n\n// Parse binary operators with the operator precedence parsing\n// algorithm. `left` is the left-hand side of the operator.\n// `minPrec` provides context that allows the function to stop and\n// defer further parser to one of its callers when it encounters an\n// operator that has a lower precedence than the set it is parsing.\n\npp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {\n let prec = this.type.binop\n if (prec != null && (!noIn || this.type !== tt._in)) {\n if (prec > minPrec) {\n let logical = this.type === tt.logicalOR || this.type === tt.logicalAND\n let op = this.value\n this.next()\n let startPos = this.start, startLoc = this.startLoc\n let right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn)\n let node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical)\n return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn)\n }\n }\n return left\n}\n\npp.buildBinary = function(startPos, startLoc, left, right, op, logical) {\n let node = this.startNodeAt(startPos, startLoc)\n node.left = left\n node.operator = op\n node.right = right\n return this.finishNode(node, logical ? \"LogicalExpression\" : \"BinaryExpression\")\n}\n\n// Parse unary operators, both prefix and postfix.\n\npp.parseMaybeUnary = function(refDestructuringErrors, sawUnary) {\n let startPos = this.start, startLoc = this.startLoc, expr\n if (this.isContextual(\"await\") && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))) {\n expr = this.parseAwait()\n sawUnary = true\n } else if (this.type.prefix) {\n let node = this.startNode(), update = this.type === tt.incDec\n node.operator = this.value\n node.prefix = true\n this.next()\n node.argument = this.parseMaybeUnary(null, true)\n this.checkExpressionErrors(refDestructuringErrors, true)\n if (update) this.checkLVal(node.argument)\n else if (this.strict && node.operator === \"delete\" &&\n node.argument.type === \"Identifier\")\n this.raiseRecoverable(node.start, \"Deleting local variable in strict mode\")\n else sawUnary = true\n expr = this.finishNode(node, update ? \"UpdateExpression\" : \"UnaryExpression\")\n } else {\n expr = this.parseExprSubscripts(refDestructuringErrors)\n if (this.checkExpressionErrors(refDestructuringErrors)) return expr\n while (this.type.postfix && !this.canInsertSemicolon()) {\n let node = this.startNodeAt(startPos, startLoc)\n node.operator = this.value\n node.prefix = false\n node.argument = expr\n this.checkLVal(expr)\n this.next()\n expr = this.finishNode(node, \"UpdateExpression\")\n }\n }\n\n if (!sawUnary && this.eat(tt.starstar))\n return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false), \"**\", false)\n else\n return expr\n}\n\n// Parse call, dot, and `[]`-subscript expressions.\n\npp.parseExprSubscripts = function(refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseExprAtom(refDestructuringErrors)\n let skipArrowSubscripts = expr.type === \"ArrowFunctionExpression\" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== \")\"\n if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr\n let result = this.parseSubscripts(expr, startPos, startLoc)\n if (refDestructuringErrors && result.type === \"MemberExpression\") {\n if (refDestructuringErrors.parenthesizedAssign >= result.start) refDestructuringErrors.parenthesizedAssign = -1\n if (refDestructuringErrors.parenthesizedBind >= result.start) refDestructuringErrors.parenthesizedBind = -1\n }\n return result\n}\n\npp.parseSubscripts = function(base, startPos, startLoc, noCalls) {\n let maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === \"Identifier\" && base.name === \"async\" &&\n this.lastTokEnd === base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === \"async\"\n while (true) {\n let element = this.parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow)\n if (element === base || element.type === \"ArrowFunctionExpression\") return element\n base = element\n }\n}\n\npp.parseSubscript = function(base, startPos, startLoc, noCalls, maybeAsyncArrow) {\n let computed = this.eat(tt.bracketL)\n if (computed || this.eat(tt.dot)) {\n let node = this.startNodeAt(startPos, startLoc)\n node.object = base\n node.property = computed ? this.parseExpression() : this.parseIdent(true)\n node.computed = !!computed\n if (computed) this.expect(tt.bracketR)\n base = this.finishNode(node, \"MemberExpression\")\n } else if (!noCalls && this.eat(tt.parenL)) {\n let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos\n this.yieldPos = 0\n this.awaitPos = 0\n this.awaitIdentPos = 0\n let exprList = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false, refDestructuringErrors)\n if (maybeAsyncArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {\n this.checkPatternErrors(refDestructuringErrors, false)\n this.checkYieldAwaitInDefaultParams()\n if (this.awaitIdentPos > 0)\n this.raise(this.awaitIdentPos, \"Cannot use 'await' as identifier inside an async function\")\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n this.awaitIdentPos = oldAwaitIdentPos\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true)\n }\n this.checkExpressionErrors(refDestructuringErrors, true)\n this.yieldPos = oldYieldPos || this.yieldPos\n this.awaitPos = oldAwaitPos || this.awaitPos\n this.awaitIdentPos = oldAwaitIdentPos || this.awaitIdentPos\n let node = this.startNodeAt(startPos, startLoc)\n node.callee = base\n node.arguments = exprList\n base = this.finishNode(node, \"CallExpression\")\n } else if (this.type === tt.backQuote) {\n let node = this.startNodeAt(startPos, startLoc)\n node.tag = base\n node.quasi = this.parseTemplate({isTagged: true})\n base = this.finishNode(node, \"TaggedTemplateExpression\")\n }\n return base\n}\n\n// Parse an atomic expression — either a single token that is an\n// expression, an expression started by a keyword like `function` or\n// `new`, or an expression wrapped in punctuation like `()`, `[]`,\n// or `{}`.\n\npp.parseExprAtom = function(refDestructuringErrors) {\n // If a division operator appears in an expression position, the\n // tokenizer got confused, and we force it to read a regexp instead.\n if (this.type === tt.slash) this.readRegexp()\n\n let node, canBeArrow = this.potentialArrowAt === this.start\n switch (this.type) {\n case tt._super:\n if (!this.allowSuper)\n this.raise(this.start, \"'super' keyword outside a method\")\n node = this.startNode()\n this.next()\n if (this.type === tt.parenL && !this.allowDirectSuper)\n this.raise(node.start, \"super() call outside constructor of a subclass\")\n // The `super` keyword can appear at below:\n // SuperProperty:\n // super [ Expression ]\n // super . IdentifierName\n // SuperCall:\n // super Arguments\n if (this.type !== tt.dot && this.type !== tt.bracketL && this.type !== tt.parenL)\n this.unexpected()\n return this.finishNode(node, \"Super\")\n\n case tt._this:\n node = this.startNode()\n this.next()\n return this.finishNode(node, \"ThisExpression\")\n\n case tt.name:\n let startPos = this.start, startLoc = this.startLoc, containsEsc = this.containsEsc\n let id = this.parseIdent(false)\n if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === \"async\" && !this.canInsertSemicolon() && this.eat(tt._function))\n return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true)\n if (canBeArrow && !this.canInsertSemicolon()) {\n if (this.eat(tt.arrow))\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false)\n if (this.options.ecmaVersion >= 8 && id.name === \"async\" && this.type === tt.name && !containsEsc) {\n id = this.parseIdent(false)\n if (this.canInsertSemicolon() || !this.eat(tt.arrow))\n this.unexpected()\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], true)\n }\n }\n return id\n\n case tt.regexp:\n let value = this.value\n node = this.parseLiteral(value.value)\n node.regex = {pattern: value.pattern, flags: value.flags}\n return node\n\n case tt.num: case tt.string:\n return this.parseLiteral(this.value)\n\n case tt._null: case tt._true: case tt._false:\n node = this.startNode()\n node.value = this.type === tt._null ? null : this.type === tt._true\n node.raw = this.type.keyword\n this.next()\n return this.finishNode(node, \"Literal\")\n\n case tt.parenL:\n let start = this.start, expr = this.parseParenAndDistinguishExpression(canBeArrow)\n if (refDestructuringErrors) {\n if (refDestructuringErrors.parenthesizedAssign < 0 && !this.isSimpleAssignTarget(expr))\n refDestructuringErrors.parenthesizedAssign = start\n if (refDestructuringErrors.parenthesizedBind < 0)\n refDestructuringErrors.parenthesizedBind = start\n }\n return expr\n\n case tt.bracketL:\n node = this.startNode()\n this.next()\n node.elements = this.parseExprList(tt.bracketR, true, true, refDestructuringErrors)\n return this.finishNode(node, \"ArrayExpression\")\n\n case tt.braceL:\n return this.parseObj(false, refDestructuringErrors)\n\n case tt._function:\n node = this.startNode()\n this.next()\n return this.parseFunction(node, 0)\n\n case tt._class:\n return this.parseClass(this.startNode(), false)\n\n case tt._new:\n return this.parseNew()\n\n case tt.backQuote:\n return this.parseTemplate()\n\n default:\n this.unexpected()\n }\n}\n\npp.parseLiteral = function(value) {\n let node = this.startNode()\n node.value = value\n node.raw = this.input.slice(this.start, this.end)\n this.next()\n return this.finishNode(node, \"Literal\")\n}\n\npp.parseParenExpression = function() {\n this.expect(tt.parenL)\n let val = this.parseExpression()\n this.expect(tt.parenR)\n return val\n}\n\npp.parseParenAndDistinguishExpression = function(canBeArrow) {\n let startPos = this.start, startLoc = this.startLoc, val, allowTrailingComma = this.options.ecmaVersion >= 8\n if (this.options.ecmaVersion >= 6) {\n this.next()\n\n let innerStartPos = this.start, innerStartLoc = this.startLoc\n let exprList = [], first = true, lastIsComma = false\n let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, spreadStart\n this.yieldPos = 0\n this.awaitPos = 0\n // Do not save awaitIdentPos to allow checking awaits nested in parameters\n while (this.type !== tt.parenR) {\n first ? first = false : this.expect(tt.comma)\n if (allowTrailingComma && this.afterTrailingComma(tt.parenR, true)) {\n lastIsComma = true\n break\n } else if (this.type === tt.ellipsis) {\n spreadStart = this.start\n exprList.push(this.parseParenItem(this.parseRestBinding()))\n if (this.type === tt.comma) this.raise(this.start, \"Comma is not permitted after the rest element\")\n break\n } else {\n exprList.push(this.parseMaybeAssign(false, refDestructuringErrors, this.parseParenItem))\n }\n }\n let innerEndPos = this.start, innerEndLoc = this.startLoc\n this.expect(tt.parenR)\n\n if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {\n this.checkPatternErrors(refDestructuringErrors, false)\n this.checkYieldAwaitInDefaultParams()\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n return this.parseParenArrowList(startPos, startLoc, exprList)\n }\n\n if (!exprList.length || lastIsComma) this.unexpected(this.lastTokStart)\n if (spreadStart) this.unexpected(spreadStart)\n this.checkExpressionErrors(refDestructuringErrors, true)\n this.yieldPos = oldYieldPos || this.yieldPos\n this.awaitPos = oldAwaitPos || this.awaitPos\n\n if (exprList.length > 1) {\n val = this.startNodeAt(innerStartPos, innerStartLoc)\n val.expressions = exprList\n this.finishNodeAt(val, \"SequenceExpression\", innerEndPos, innerEndLoc)\n } else {\n val = exprList[0]\n }\n } else {\n val = this.parseParenExpression()\n }\n\n if (this.options.preserveParens) {\n let par = this.startNodeAt(startPos, startLoc)\n par.expression = val\n return this.finishNode(par, \"ParenthesizedExpression\")\n } else {\n return val\n }\n}\n\npp.parseParenItem = function(item) {\n return item\n}\n\npp.parseParenArrowList = function(startPos, startLoc, exprList) {\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList)\n}\n\n// New's precedence is slightly tricky. It must allow its argument to\n// be a `[]` or dot subscript expression, but not a call — at least,\n// not without wrapping it in parentheses. Thus, it uses the noCalls\n// argument to parseSubscripts to prevent it from consuming the\n// argument list.\n\nconst empty = []\n\npp.parseNew = function() {\n let node = this.startNode()\n let meta = this.parseIdent(true)\n if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {\n node.meta = meta\n let containsEsc = this.containsEsc\n node.property = this.parseIdent(true)\n if (node.property.name !== \"target\" || containsEsc)\n this.raiseRecoverable(node.property.start, \"The only valid meta property for new is new.target\")\n if (!this.inNonArrowFunction())\n this.raiseRecoverable(node.start, \"new.target can only be used in functions\")\n return this.finishNode(node, \"MetaProperty\")\n }\n let startPos = this.start, startLoc = this.startLoc\n node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true)\n if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false)\n else node.arguments = empty\n return this.finishNode(node, \"NewExpression\")\n}\n\n// Parse template expression.\n\npp.parseTemplateElement = function({isTagged}) {\n let elem = this.startNode()\n if (this.type === tt.invalidTemplate) {\n if (!isTagged) {\n this.raiseRecoverable(this.start, \"Bad escape sequence in untagged template literal\")\n }\n elem.value = {\n raw: this.value,\n cooked: null\n }\n } else {\n elem.value = {\n raw: this.input.slice(this.start, this.end).replace(/\\r\\n?/g, \"\\n\"),\n cooked: this.value\n }\n }\n this.next()\n elem.tail = this.type === tt.backQuote\n return this.finishNode(elem, \"TemplateElement\")\n}\n\npp.parseTemplate = function({isTagged = false} = {}) {\n let node = this.startNode()\n this.next()\n node.expressions = []\n let curElt = this.parseTemplateElement({isTagged})\n node.quasis = [curElt]\n while (!curElt.tail) {\n if (this.type === tt.eof) this.raise(this.pos, \"Unterminated template literal\")\n this.expect(tt.dollarBraceL)\n node.expressions.push(this.parseExpression())\n this.expect(tt.braceR)\n node.quasis.push(curElt = this.parseTemplateElement({isTagged}))\n }\n this.next()\n return this.finishNode(node, \"TemplateLiteral\")\n}\n\npp.isAsyncProp = function(prop) {\n return !prop.computed && prop.key.type === \"Identifier\" && prop.key.name === \"async\" &&\n (this.type === tt.name || this.type === tt.num || this.type === tt.string || this.type === tt.bracketL || this.type.keyword || (this.options.ecmaVersion >= 9 && this.type === tt.star)) &&\n !lineBreak.test(this.input.slice(this.lastTokEnd, this.start))\n}\n\n// Parse an object literal or binding pattern.\n\npp.parseObj = function(isPattern, refDestructuringErrors) {\n let node = this.startNode(), first = true, propHash = {}\n node.properties = []\n this.next()\n while (!this.eat(tt.braceR)) {\n if (!first) {\n this.expect(tt.comma)\n if (this.afterTrailingComma(tt.braceR)) break\n } else first = false\n\n const prop = this.parseProperty(isPattern, refDestructuringErrors)\n if (!isPattern) this.checkPropClash(prop, propHash, refDestructuringErrors)\n node.properties.push(prop)\n }\n return this.finishNode(node, isPattern ? \"ObjectPattern\" : \"ObjectExpression\")\n}\n\npp.parseProperty = function(isPattern, refDestructuringErrors) {\n let prop = this.startNode(), isGenerator, isAsync, startPos, startLoc\n if (this.options.ecmaVersion >= 9 && this.eat(tt.ellipsis)) {\n if (isPattern) {\n prop.argument = this.parseIdent(false)\n if (this.type === tt.comma) {\n this.raise(this.start, \"Comma is not permitted after the rest element\")\n }\n return this.finishNode(prop, \"RestElement\")\n }\n // To disallow parenthesized identifier via `this.toAssignable()`.\n if (this.type === tt.parenL && refDestructuringErrors) {\n if (refDestructuringErrors.parenthesizedAssign < 0) {\n refDestructuringErrors.parenthesizedAssign = this.start\n }\n if (refDestructuringErrors.parenthesizedBind < 0) {\n refDestructuringErrors.parenthesizedBind = this.start\n }\n }\n // Parse argument.\n prop.argument = this.parseMaybeAssign(false, refDestructuringErrors)\n // To disallow trailing comma via `this.toAssignable()`.\n if (this.type === tt.comma && refDestructuringErrors && refDestructuringErrors.trailingComma < 0) {\n refDestructuringErrors.trailingComma = this.start\n }\n // Finish\n return this.finishNode(prop, \"SpreadElement\")\n }\n if (this.options.ecmaVersion >= 6) {\n prop.method = false\n prop.shorthand = false\n if (isPattern || refDestructuringErrors) {\n startPos = this.start\n startLoc = this.startLoc\n }\n if (!isPattern)\n isGenerator = this.eat(tt.star)\n }\n let containsEsc = this.containsEsc\n this.parsePropertyName(prop)\n if (!isPattern && !containsEsc && this.options.ecmaVersion >= 8 && !isGenerator && this.isAsyncProp(prop)) {\n isAsync = true\n isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star)\n this.parsePropertyName(prop, refDestructuringErrors)\n } else {\n isAsync = false\n }\n this.parsePropertyValue(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors, containsEsc)\n return this.finishNode(prop, \"Property\")\n}\n\npp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors, containsEsc) {\n if ((isGenerator || isAsync) && this.type === tt.colon)\n this.unexpected()\n\n if (this.eat(tt.colon)) {\n prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refDestructuringErrors)\n prop.kind = \"init\"\n } else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {\n if (isPattern) this.unexpected()\n prop.kind = \"init\"\n prop.method = true\n prop.value = this.parseMethod(isGenerator, isAsync)\n } else if (!isPattern && !containsEsc &&\n this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === \"Identifier\" &&\n (prop.key.name === \"get\" || prop.key.name === \"set\") &&\n (this.type !== tt.comma && this.type !== tt.braceR)) {\n if (isGenerator || isAsync) this.unexpected()\n prop.kind = prop.key.name\n this.parsePropertyName(prop)\n prop.value = this.parseMethod(false)\n let paramCount = prop.kind === \"get\" ? 0 : 1\n if (prop.value.params.length !== paramCount) {\n let start = prop.value.start\n if (prop.kind === \"get\")\n this.raiseRecoverable(start, \"getter should have no params\")\n else\n this.raiseRecoverable(start, \"setter should have exactly one param\")\n } else {\n if (prop.kind === \"set\" && prop.value.params[0].type === \"RestElement\")\n this.raiseRecoverable(prop.value.params[0].start, \"Setter cannot use rest params\")\n }\n } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === \"Identifier\") {\n if (isGenerator || isAsync) this.unexpected()\n this.checkUnreserved(prop.key)\n if (prop.key.name === \"await\" && !this.awaitIdentPos)\n this.awaitIdentPos = startPos\n prop.kind = \"init\"\n if (isPattern) {\n prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)\n } else if (this.type === tt.eq && refDestructuringErrors) {\n if (refDestructuringErrors.shorthandAssign < 0)\n refDestructuringErrors.shorthandAssign = this.start\n prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)\n } else {\n prop.value = prop.key\n }\n prop.shorthand = true\n } else this.unexpected()\n}\n\npp.parsePropertyName = function(prop) {\n if (this.options.ecmaVersion >= 6) {\n if (this.eat(tt.bracketL)) {\n prop.computed = true\n prop.key = this.parseMaybeAssign()\n this.expect(tt.bracketR)\n return prop.key\n } else {\n prop.computed = false\n }\n }\n return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true)\n}\n\n// Initialize empty function node.\n\npp.initFunction = function(node) {\n node.id = null\n if (this.options.ecmaVersion >= 6) node.generator = node.expression = false\n if (this.options.ecmaVersion >= 8) node.async = false\n}\n\n// Parse object or class method.\n\npp.parseMethod = function(isGenerator, isAsync, allowDirectSuper) {\n let node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos\n\n this.initFunction(node)\n if (this.options.ecmaVersion >= 6)\n node.generator = isGenerator\n if (this.options.ecmaVersion >= 8)\n node.async = !!isAsync\n\n this.yieldPos = 0\n this.awaitPos = 0\n this.awaitIdentPos = 0\n this.enterScope(functionFlags(isAsync, node.generator) | SCOPE_SUPER | (allowDirectSuper ? SCOPE_DIRECT_SUPER : 0))\n\n this.expect(tt.parenL)\n node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8)\n this.checkYieldAwaitInDefaultParams()\n this.parseFunctionBody(node, false, true)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n this.awaitIdentPos = oldAwaitIdentPos\n return this.finishNode(node, \"FunctionExpression\")\n}\n\n// Parse arrow function expression with given parameters.\n\npp.parseArrowExpression = function(node, params, isAsync) {\n let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos\n\n this.enterScope(functionFlags(isAsync, false) | SCOPE_ARROW)\n this.initFunction(node)\n if (this.options.ecmaVersion >= 8) node.async = !!isAsync\n\n this.yieldPos = 0\n this.awaitPos = 0\n this.awaitIdentPos = 0\n\n node.params = this.toAssignableList(params, true)\n this.parseFunctionBody(node, true, false)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n this.awaitIdentPos = oldAwaitIdentPos\n return this.finishNode(node, \"ArrowFunctionExpression\")\n}\n\n// Parse function body and check parameters.\n\npp.parseFunctionBody = function(node, isArrowFunction, isMethod) {\n let isExpression = isArrowFunction && this.type !== tt.braceL\n let oldStrict = this.strict, useStrict = false\n\n if (isExpression) {\n node.body = this.parseMaybeAssign()\n node.expression = true\n this.checkParams(node, false)\n } else {\n let nonSimple = this.options.ecmaVersion >= 7 && !this.isSimpleParamList(node.params)\n if (!oldStrict || nonSimple) {\n useStrict = this.strictDirective(this.end)\n // If this is a strict mode function, verify that argument names\n // are not repeated, and it does not try to bind the words `eval`\n // or `arguments`.\n if (useStrict && nonSimple)\n this.raiseRecoverable(node.start, \"Illegal 'use strict' directive in function with non-simple parameter list\")\n }\n // Start a new scope with regard to labels and the `inFunction`\n // flag (restore them to their old value afterwards).\n let oldLabels = this.labels\n this.labels = []\n if (useStrict) this.strict = true\n\n // Add the params to varDeclaredNames to ensure that an error is thrown\n // if a let/const declaration in the function clashes with one of the params.\n this.checkParams(node, !oldStrict && !useStrict && !isArrowFunction && !isMethod && this.isSimpleParamList(node.params))\n node.body = this.parseBlock(false)\n node.expression = false\n this.adaptDirectivePrologue(node.body.body)\n this.labels = oldLabels\n }\n this.exitScope()\n\n // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'\n if (this.strict && node.id) this.checkLVal(node.id, BIND_OUTSIDE)\n this.strict = oldStrict\n}\n\npp.isSimpleParamList = function(params) {\n for (let param of params)\n if (param.type !== \"Identifier\") return false\n return true\n}\n\n// Checks function params for various disallowed patterns such as using \"eval\"\n// or \"arguments\" and duplicate parameters.\n\npp.checkParams = function(node, allowDuplicates) {\n let nameHash = {}\n for (let param of node.params)\n this.checkLVal(param, BIND_VAR, allowDuplicates ? null : nameHash)\n}\n\n// Parses a comma-separated list of expressions, and returns them as\n// an array. `close` is the token type that ends the list, and\n// `allowEmpty` can be turned on to allow subsequent commas with\n// nothing in between them to be parsed as `null` (which is needed\n// for array literals).\n\npp.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructuringErrors) {\n let elts = [], first = true\n while (!this.eat(close)) {\n if (!first) {\n this.expect(tt.comma)\n if (allowTrailingComma && this.afterTrailingComma(close)) break\n } else first = false\n\n let elt\n if (allowEmpty && this.type === tt.comma)\n elt = null\n else if (this.type === tt.ellipsis) {\n elt = this.parseSpread(refDestructuringErrors)\n if (refDestructuringErrors && this.type === tt.comma && refDestructuringErrors.trailingComma < 0)\n refDestructuringErrors.trailingComma = this.start\n } else {\n elt = this.parseMaybeAssign(false, refDestructuringErrors)\n }\n elts.push(elt)\n }\n return elts\n}\n\npp.checkUnreserved = function({start, end, name}) {\n if (this.inGenerator && name === \"yield\")\n this.raiseRecoverable(start, \"Cannot use 'yield' as identifier inside a generator\")\n if (this.inAsync && name === \"await\")\n this.raiseRecoverable(start, \"Cannot use 'await' as identifier inside an async function\")\n if (this.keywords.test(name))\n this.raise(start, `Unexpected keyword '${name}'`)\n if (this.options.ecmaVersion < 6 &&\n this.input.slice(start, end).indexOf(\"\\\\\") !== -1) return\n const re = this.strict ? this.reservedWordsStrict : this.reservedWords\n if (re.test(name)) {\n if (!this.inAsync && name === \"await\")\n this.raiseRecoverable(start, \"Cannot use keyword 'await' outside an async function\")\n this.raiseRecoverable(start, `The keyword '${name}' is reserved`)\n }\n}\n\n// Parse the next token as an identifier. If `liberal` is true (used\n// when parsing properties), it will also convert keywords into\n// identifiers.\n\npp.parseIdent = function(liberal, isBinding) {\n let node = this.startNode()\n if (liberal && this.options.allowReserved === \"never\") liberal = false\n if (this.type === tt.name) {\n node.name = this.value\n } else if (this.type.keyword) {\n node.name = this.type.keyword\n\n // To fix https://github.com/acornjs/acorn/issues/575\n // `class` and `function` keywords push new context into this.context.\n // But there is no chance to pop the context if the keyword is consumed as an identifier such as a property name.\n // If the previous token is a dot, this does not apply because the context-managing code already ignored the keyword\n if ((node.name === \"class\" || node.name === \"function\") &&\n (this.lastTokEnd !== this.lastTokStart + 1 || this.input.charCodeAt(this.lastTokStart) !== 46)) {\n this.context.pop()\n }\n } else {\n this.unexpected()\n }\n this.next()\n this.finishNode(node, \"Identifier\")\n if (!liberal) {\n this.checkUnreserved(node)\n if (node.name === \"await\" && !this.awaitIdentPos)\n this.awaitIdentPos = node.start\n }\n return node\n}\n\n// Parses yield expression inside generator.\n\npp.parseYield = function(noIn) {\n if (!this.yieldPos) this.yieldPos = this.start\n\n let node = this.startNode()\n this.next()\n if (this.type === tt.semi || this.canInsertSemicolon() || (this.type !== tt.star && !this.type.startsExpr)) {\n node.delegate = false\n node.argument = null\n } else {\n node.delegate = this.eat(tt.star)\n node.argument = this.parseMaybeAssign(noIn)\n }\n return this.finishNode(node, \"YieldExpression\")\n}\n\npp.parseAwait = function() {\n if (!this.awaitPos) this.awaitPos = this.start\n\n let node = this.startNode()\n this.next()\n node.argument = this.parseMaybeUnary(null, true)\n return this.finishNode(node, \"AwaitExpression\")\n}\n","import {Parser} from \"./state\"\nimport {Position, getLineInfo} from \"./locutil\"\n\nconst pp = Parser.prototype\n\n// This function is used to raise exceptions on parse errors. It\n// takes an offset integer (into the current `input`) to indicate\n// the location of the error, attaches the position to the end\n// of the error message, and then raises a `SyntaxError` with that\n// message.\n\npp.raise = function(pos, message) {\n let loc = getLineInfo(this.input, pos)\n message += \" (\" + loc.line + \":\" + loc.column + \")\"\n let err = new SyntaxError(message)\n err.pos = pos; err.loc = loc; err.raisedAt = this.pos\n throw err\n}\n\npp.raiseRecoverable = pp.raise\n\npp.curPosition = function() {\n if (this.options.locations) {\n return new Position(this.curLine, this.pos - this.lineStart)\n }\n}\n","import {Parser} from \"./state\"\nimport {SCOPE_VAR, SCOPE_FUNCTION, SCOPE_TOP, SCOPE_ARROW, SCOPE_SIMPLE_CATCH, BIND_LEXICAL, BIND_SIMPLE_CATCH, BIND_FUNCTION} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\nclass Scope {\n constructor(flags) {\n this.flags = flags\n // A list of var-declared names in the current lexical scope\n this.var = []\n // A list of lexically-declared names in the current lexical scope\n this.lexical = []\n // A list of lexically-declared FunctionDeclaration names in the current lexical scope\n this.functions = []\n }\n}\n\n// The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names.\n\npp.enterScope = function(flags) {\n this.scopeStack.push(new Scope(flags))\n}\n\npp.exitScope = function() {\n this.scopeStack.pop()\n}\n\n// The spec says:\n// > At the top level of a function, or script, function declarations are\n// > treated like var declarations rather than like lexical declarations.\npp.treatFunctionsAsVarInScope = function(scope) {\n return (scope.flags & SCOPE_FUNCTION) || !this.inModule && (scope.flags & SCOPE_TOP)\n}\n\npp.declareName = function(name, bindingType, pos) {\n let redeclared = false\n if (bindingType === BIND_LEXICAL) {\n const scope = this.currentScope()\n redeclared = scope.lexical.indexOf(name) > -1 || scope.functions.indexOf(name) > -1 || scope.var.indexOf(name) > -1\n scope.lexical.push(name)\n if (this.inModule && (scope.flags & SCOPE_TOP))\n delete this.undefinedExports[name]\n } else if (bindingType === BIND_SIMPLE_CATCH) {\n const scope = this.currentScope()\n scope.lexical.push(name)\n } else if (bindingType === BIND_FUNCTION) {\n const scope = this.currentScope()\n if (this.treatFunctionsAsVar)\n redeclared = scope.lexical.indexOf(name) > -1\n else\n redeclared = scope.lexical.indexOf(name) > -1 || scope.var.indexOf(name) > -1\n scope.functions.push(name)\n } else {\n for (let i = this.scopeStack.length - 1; i >= 0; --i) {\n const scope = this.scopeStack[i]\n if (scope.lexical.indexOf(name) > -1 && !((scope.flags & SCOPE_SIMPLE_CATCH) && scope.lexical[0] === name) ||\n !this.treatFunctionsAsVarInScope(scope) && scope.functions.indexOf(name) > -1) {\n redeclared = true\n break\n }\n scope.var.push(name)\n if (this.inModule && (scope.flags & SCOPE_TOP))\n delete this.undefinedExports[name]\n if (scope.flags & SCOPE_VAR) break\n }\n }\n if (redeclared) this.raiseRecoverable(pos, `Identifier '${name}' has already been declared`)\n}\n\npp.checkLocalExport = function(id) {\n // scope.functions must be empty as Module code is always strict.\n if (this.scopeStack[0].lexical.indexOf(id.name) === -1 &&\n this.scopeStack[0].var.indexOf(id.name) === -1) {\n this.undefinedExports[id.name] = id\n }\n}\n\npp.currentScope = function() {\n return this.scopeStack[this.scopeStack.length - 1]\n}\n\npp.currentVarScope = function() {\n for (let i = this.scopeStack.length - 1;; i--) {\n let scope = this.scopeStack[i]\n if (scope.flags & SCOPE_VAR) return scope\n }\n}\n\n// Could be useful for `this`, `new.target`, `super()`, `super.property`, and `super[property]`.\npp.currentThisScope = function() {\n for (let i = this.scopeStack.length - 1;; i--) {\n let scope = this.scopeStack[i]\n if (scope.flags & SCOPE_VAR && !(scope.flags & SCOPE_ARROW)) return scope\n }\n}\n","import {Parser} from \"./state\"\nimport {SourceLocation} from \"./locutil\"\n\nexport class Node {\n constructor(parser, pos, loc) {\n this.type = \"\"\n this.start = pos\n this.end = 0\n if (parser.options.locations)\n this.loc = new SourceLocation(parser, loc)\n if (parser.options.directSourceFile)\n this.sourceFile = parser.options.directSourceFile\n if (parser.options.ranges)\n this.range = [pos, 0]\n }\n}\n\n// Start an AST node, attaching a start offset.\n\nconst pp = Parser.prototype\n\npp.startNode = function() {\n return new Node(this, this.start, this.startLoc)\n}\n\npp.startNodeAt = function(pos, loc) {\n return new Node(this, pos, loc)\n}\n\n// Finish an AST node, adding `type` and `end` properties.\n\nfunction finishNodeAt(node, type, pos, loc) {\n node.type = type\n node.end = pos\n if (this.options.locations)\n node.loc.end = loc\n if (this.options.ranges)\n node.range[1] = pos\n return node\n}\n\npp.finishNode = function(node, type) {\n return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc)\n}\n\n// Finish node at given position\n\npp.finishNodeAt = function(node, type, pos, loc) {\n return finishNodeAt.call(this, node, type, pos, loc)\n}\n","// The algorithm used to determine whether a regexp can appear at a\n// given point in the program is loosely based on sweet.js' approach.\n// See https://github.com/mozilla/sweet.js/wiki/design\n\nimport {Parser} from \"./state\"\nimport {types as tt} from \"./tokentype\"\nimport {lineBreak} from \"./whitespace\"\n\nexport class TokContext {\n constructor(token, isExpr, preserveSpace, override, generator) {\n this.token = token\n this.isExpr = !!isExpr\n this.preserveSpace = !!preserveSpace\n this.override = override\n this.generator = !!generator\n }\n}\n\nexport const types = {\n b_stat: new TokContext(\"{\", false),\n b_expr: new TokContext(\"{\", true),\n b_tmpl: new TokContext(\"${\", false),\n p_stat: new TokContext(\"(\", false),\n p_expr: new TokContext(\"(\", true),\n q_tmpl: new TokContext(\"`\", true, true, p => p.tryReadTemplateToken()),\n f_stat: new TokContext(\"function\", false),\n f_expr: new TokContext(\"function\", true),\n f_expr_gen: new TokContext(\"function\", true, false, null, true),\n f_gen: new TokContext(\"function\", false, false, null, true)\n}\n\nconst pp = Parser.prototype\n\npp.initialContext = function() {\n return [types.b_stat]\n}\n\npp.braceIsBlock = function(prevType) {\n let parent = this.curContext()\n if (parent === types.f_expr || parent === types.f_stat)\n return true\n if (prevType === tt.colon && (parent === types.b_stat || parent === types.b_expr))\n return !parent.isExpr\n\n // The check for `tt.name && exprAllowed` detects whether we are\n // after a `yield` or `of` construct. See the `updateContext` for\n // `tt.name`.\n if (prevType === tt._return || prevType === tt.name && this.exprAllowed)\n return lineBreak.test(this.input.slice(this.lastTokEnd, this.start))\n if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType === tt.arrow)\n return true\n if (prevType === tt.braceL)\n return parent === types.b_stat\n if (prevType === tt._var || prevType === tt._const || prevType === tt.name)\n return false\n return !this.exprAllowed\n}\n\npp.inGeneratorContext = function() {\n for (let i = this.context.length - 1; i >= 1; i--) {\n let context = this.context[i]\n if (context.token === \"function\")\n return context.generator\n }\n return false\n}\n\npp.updateContext = function(prevType) {\n let update, type = this.type\n if (type.keyword && prevType === tt.dot)\n this.exprAllowed = false\n else if (update = type.updateContext)\n update.call(this, prevType)\n else\n this.exprAllowed = type.beforeExpr\n}\n\n// Token-specific context update code\n\ntt.parenR.updateContext = tt.braceR.updateContext = function() {\n if (this.context.length === 1) {\n this.exprAllowed = true\n return\n }\n let out = this.context.pop()\n if (out === types.b_stat && this.curContext().token === \"function\") {\n out = this.context.pop()\n }\n this.exprAllowed = !out.isExpr\n}\n\ntt.braceL.updateContext = function(prevType) {\n this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr)\n this.exprAllowed = true\n}\n\ntt.dollarBraceL.updateContext = function() {\n this.context.push(types.b_tmpl)\n this.exprAllowed = true\n}\n\ntt.parenL.updateContext = function(prevType) {\n let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while\n this.context.push(statementParens ? types.p_stat : types.p_expr)\n this.exprAllowed = true\n}\n\ntt.incDec.updateContext = function() {\n // tokExprAllowed stays unchanged\n}\n\ntt._function.updateContext = tt._class.updateContext = function(prevType) {\n if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else &&\n !(prevType === tt._return && lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) &&\n !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat))\n this.context.push(types.f_expr)\n else\n this.context.push(types.f_stat)\n this.exprAllowed = false\n}\n\ntt.backQuote.updateContext = function() {\n if (this.curContext() === types.q_tmpl)\n this.context.pop()\n else\n this.context.push(types.q_tmpl)\n this.exprAllowed = false\n}\n\ntt.star.updateContext = function(prevType) {\n if (prevType === tt._function) {\n let index = this.context.length - 1\n if (this.context[index] === types.f_expr)\n this.context[index] = types.f_expr_gen\n else\n this.context[index] = types.f_gen\n }\n this.exprAllowed = true\n}\n\ntt.name.updateContext = function(prevType) {\n let allowed = false\n if (this.options.ecmaVersion >= 6 && prevType !== tt.dot) {\n if (this.value === \"of\" && !this.exprAllowed ||\n this.value === \"yield\" && this.inGeneratorContext())\n allowed = true\n }\n this.exprAllowed = allowed\n}\n","import {wordsRegexp} from \"./util.js\"\n\n// This file contains Unicode properties extracted from the ECMAScript\n// specification. The lists are extracted like so:\n// $$('#table-binary-unicode-properties > figure > table > tbody > tr > td:nth-child(1) code').map(el => el.innerText)\n\n// #table-binary-unicode-properties\nconst ecma9BinaryProperties = \"ASCII ASCII_Hex_Digit AHex Alphabetic Alpha Any Assigned Bidi_Control Bidi_C Bidi_Mirrored Bidi_M Case_Ignorable CI Cased Changes_When_Casefolded CWCF Changes_When_Casemapped CWCM Changes_When_Lowercased CWL Changes_When_NFKC_Casefolded CWKCF Changes_When_Titlecased CWT Changes_When_Uppercased CWU Dash Default_Ignorable_Code_Point DI Deprecated Dep Diacritic Dia Emoji Emoji_Component Emoji_Modifier Emoji_Modifier_Base Emoji_Presentation Extender Ext Grapheme_Base Gr_Base Grapheme_Extend Gr_Ext Hex_Digit Hex IDS_Binary_Operator IDSB IDS_Trinary_Operator IDST ID_Continue IDC ID_Start IDS Ideographic Ideo Join_Control Join_C Logical_Order_Exception LOE Lowercase Lower Math Noncharacter_Code_Point NChar Pattern_Syntax Pat_Syn Pattern_White_Space Pat_WS Quotation_Mark QMark Radical Regional_Indicator RI Sentence_Terminal STerm Soft_Dotted SD Terminal_Punctuation Term Unified_Ideograph UIdeo Uppercase Upper Variation_Selector VS White_Space space XID_Continue XIDC XID_Start XIDS\"\nconst unicodeBinaryProperties = {\n 9: ecma9BinaryProperties,\n 10: ecma9BinaryProperties + \" Extended_Pictographic\"\n}\n\n// #table-unicode-general-category-values\nconst unicodeGeneralCategoryValues = \"Cased_Letter LC Close_Punctuation Pe Connector_Punctuation Pc Control Cc cntrl Currency_Symbol Sc Dash_Punctuation Pd Decimal_Number Nd digit Enclosing_Mark Me Final_Punctuation Pf Format Cf Initial_Punctuation Pi Letter L Letter_Number Nl Line_Separator Zl Lowercase_Letter Ll Mark M Combining_Mark Math_Symbol Sm Modifier_Letter Lm Modifier_Symbol Sk Nonspacing_Mark Mn Number N Open_Punctuation Ps Other C Other_Letter Lo Other_Number No Other_Punctuation Po Other_Symbol So Paragraph_Separator Zp Private_Use Co Punctuation P punct Separator Z Space_Separator Zs Spacing_Mark Mc Surrogate Cs Symbol S Titlecase_Letter Lt Unassigned Cn Uppercase_Letter Lu\"\n\n// #table-unicode-script-values\nconst ecma9ScriptValues = \"Adlam Adlm Ahom Ahom Anatolian_Hieroglyphs Hluw Arabic Arab Armenian Armn Avestan Avst Balinese Bali Bamum Bamu Bassa_Vah Bass Batak Batk Bengali Beng Bhaiksuki Bhks Bopomofo Bopo Brahmi Brah Braille Brai Buginese Bugi Buhid Buhd Canadian_Aboriginal Cans Carian Cari Caucasian_Albanian Aghb Chakma Cakm Cham Cham Cherokee Cher Common Zyyy Coptic Copt Qaac Cuneiform Xsux Cypriot Cprt Cyrillic Cyrl Deseret Dsrt Devanagari Deva Duployan Dupl Egyptian_Hieroglyphs Egyp Elbasan Elba Ethiopic Ethi Georgian Geor Glagolitic Glag Gothic Goth Grantha Gran Greek Grek Gujarati Gujr Gurmukhi Guru Han Hani Hangul Hang Hanunoo Hano Hatran Hatr Hebrew Hebr Hiragana Hira Imperial_Aramaic Armi Inherited Zinh Qaai Inscriptional_Pahlavi Phli Inscriptional_Parthian Prti Javanese Java Kaithi Kthi Kannada Knda Katakana Kana Kayah_Li Kali Kharoshthi Khar Khmer Khmr Khojki Khoj Khudawadi Sind Lao Laoo Latin Latn Lepcha Lepc Limbu Limb Linear_A Lina Linear_B Linb Lisu Lisu Lycian Lyci Lydian Lydi Mahajani Mahj Malayalam Mlym Mandaic Mand Manichaean Mani Marchen Marc Masaram_Gondi Gonm Meetei_Mayek Mtei Mende_Kikakui Mend Meroitic_Cursive Merc Meroitic_Hieroglyphs Mero Miao Plrd Modi Modi Mongolian Mong Mro Mroo Multani Mult Myanmar Mymr Nabataean Nbat New_Tai_Lue Talu Newa Newa Nko Nkoo Nushu Nshu Ogham Ogam Ol_Chiki Olck Old_Hungarian Hung Old_Italic Ital Old_North_Arabian Narb Old_Permic Perm Old_Persian Xpeo Old_South_Arabian Sarb Old_Turkic Orkh Oriya Orya Osage Osge Osmanya Osma Pahawh_Hmong Hmng Palmyrene Palm Pau_Cin_Hau Pauc Phags_Pa Phag Phoenician Phnx Psalter_Pahlavi Phlp Rejang Rjng Runic Runr Samaritan Samr Saurashtra Saur Sharada Shrd Shavian Shaw Siddham Sidd SignWriting Sgnw Sinhala Sinh Sora_Sompeng Sora Soyombo Soyo Sundanese Sund Syloti_Nagri Sylo Syriac Syrc Tagalog Tglg Tagbanwa Tagb Tai_Le Tale Tai_Tham Lana Tai_Viet Tavt Takri Takr Tamil Taml Tangut Tang Telugu Telu Thaana Thaa Thai Thai Tibetan Tibt Tifinagh Tfng Tirhuta Tirh Ugaritic Ugar Vai Vaii Warang_Citi Wara Yi Yiii Zanabazar_Square Zanb\"\nconst unicodeScriptValues = {\n 9: ecma9ScriptValues,\n 10: ecma9ScriptValues + \" Dogra Dogr Gunjala_Gondi Gong Hanifi_Rohingya Rohg Makasar Maka Medefaidrin Medf Old_Sogdian Sogo Sogdian Sogd\"\n}\n\nconst data = {}\nfunction buildUnicodeData(ecmaVersion) {\n let d = data[ecmaVersion] = {\n binary: wordsRegexp(unicodeBinaryProperties[ecmaVersion] + \" \" + unicodeGeneralCategoryValues),\n nonBinary: {\n General_Category: wordsRegexp(unicodeGeneralCategoryValues),\n Script: wordsRegexp(unicodeScriptValues[ecmaVersion])\n }\n }\n d.nonBinary.Script_Extensions = d.nonBinary.Script\n\n d.nonBinary.gc = d.nonBinary.General_Category\n d.nonBinary.sc = d.nonBinary.Script\n d.nonBinary.scx = d.nonBinary.Script_Extensions\n}\nbuildUnicodeData(9)\nbuildUnicodeData(10)\n\nexport default data\n","import {isIdentifierStart, isIdentifierChar} from \"./identifier.js\"\nimport {Parser} from \"./state.js\"\nimport UNICODE_PROPERTY_VALUES from \"./unicode-property-data.js\"\nimport {has} from \"./util.js\"\n\nconst pp = Parser.prototype\n\nexport class RegExpValidationState {\n constructor(parser) {\n this.parser = parser\n this.validFlags = `gim${parser.options.ecmaVersion >= 6 ? \"uy\" : \"\"}${parser.options.ecmaVersion >= 9 ? \"s\" : \"\"}`\n this.unicodeProperties = UNICODE_PROPERTY_VALUES[parser.options.ecmaVersion >= 10 ? 10 : parser.options.ecmaVersion]\n this.source = \"\"\n this.flags = \"\"\n this.start = 0\n this.switchU = false\n this.switchN = false\n this.pos = 0\n this.lastIntValue = 0\n this.lastStringValue = \"\"\n this.lastAssertionIsQuantifiable = false\n this.numCapturingParens = 0\n this.maxBackReference = 0\n this.groupNames = []\n this.backReferenceNames = []\n }\n\n reset(start, pattern, flags) {\n const unicode = flags.indexOf(\"u\") !== -1\n this.start = start | 0\n this.source = pattern + \"\"\n this.flags = flags\n this.switchU = unicode && this.parser.options.ecmaVersion >= 6\n this.switchN = unicode && this.parser.options.ecmaVersion >= 9\n }\n\n raise(message) {\n this.parser.raiseRecoverable(this.start, `Invalid regular expression: /${this.source}/: ${message}`)\n }\n\n // If u flag is given, this returns the code point at the index (it combines a surrogate pair).\n // Otherwise, this returns the code unit of the index (can be a part of a surrogate pair).\n at(i) {\n const s = this.source\n const l = s.length\n if (i >= l) {\n return -1\n }\n const c = s.charCodeAt(i)\n if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) {\n return c\n }\n return (c << 10) + s.charCodeAt(i + 1) - 0x35FDC00\n }\n\n nextIndex(i) {\n const s = this.source\n const l = s.length\n if (i >= l) {\n return l\n }\n const c = s.charCodeAt(i)\n if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) {\n return i + 1\n }\n return i + 2\n }\n\n current() {\n return this.at(this.pos)\n }\n\n lookahead() {\n return this.at(this.nextIndex(this.pos))\n }\n\n advance() {\n this.pos = this.nextIndex(this.pos)\n }\n\n eat(ch) {\n if (this.current() === ch) {\n this.advance()\n return true\n }\n return false\n }\n}\n\nfunction codePointToString(ch) {\n if (ch <= 0xFFFF) return String.fromCharCode(ch)\n ch -= 0x10000\n return String.fromCharCode((ch >> 10) + 0xD800, (ch & 0x03FF) + 0xDC00)\n}\n\n/**\n * Validate the flags part of a given RegExpLiteral.\n *\n * @param {RegExpValidationState} state The state to validate RegExp.\n * @returns {void}\n */\npp.validateRegExpFlags = function(state) {\n const validFlags = state.validFlags\n const flags = state.flags\n\n for (let i = 0; i < flags.length; i++) {\n const flag = flags.charAt(i)\n if (validFlags.indexOf(flag) === -1) {\n this.raise(state.start, \"Invalid regular expression flag\")\n }\n if (flags.indexOf(flag, i + 1) > -1) {\n this.raise(state.start, \"Duplicate regular expression flag\")\n }\n }\n}\n\n/**\n * Validate the pattern part of a given RegExpLiteral.\n *\n * @param {RegExpValidationState} state The state to validate RegExp.\n * @returns {void}\n */\npp.validateRegExpPattern = function(state) {\n this.regexp_pattern(state)\n\n // The goal symbol for the parse is |Pattern[~U, ~N]|. If the result of\n // parsing contains a |GroupName|, reparse with the goal symbol\n // |Pattern[~U, +N]| and use this result instead. Throw a *SyntaxError*\n // exception if _P_ did not conform to the grammar, if any elements of _P_\n // were not matched by the parse, or if any Early Error conditions exist.\n if (!state.switchN && this.options.ecmaVersion >= 9 && state.groupNames.length > 0) {\n state.switchN = true\n this.regexp_pattern(state)\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Pattern\npp.regexp_pattern = function(state) {\n state.pos = 0\n state.lastIntValue = 0\n state.lastStringValue = \"\"\n state.lastAssertionIsQuantifiable = false\n state.numCapturingParens = 0\n state.maxBackReference = 0\n state.groupNames.length = 0\n state.backReferenceNames.length = 0\n\n this.regexp_disjunction(state)\n\n if (state.pos !== state.source.length) {\n // Make the same messages as V8.\n if (state.eat(0x29 /* ) */)) {\n state.raise(\"Unmatched ')'\")\n }\n if (state.eat(0x5D /* [ */) || state.eat(0x7D /* } */)) {\n state.raise(\"Lone quantifier brackets\")\n }\n }\n if (state.maxBackReference > state.numCapturingParens) {\n state.raise(\"Invalid escape\")\n }\n for (const name of state.backReferenceNames) {\n if (state.groupNames.indexOf(name) === -1) {\n state.raise(\"Invalid named capture referenced\")\n }\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Disjunction\npp.regexp_disjunction = function(state) {\n this.regexp_alternative(state)\n while (state.eat(0x7C /* | */)) {\n this.regexp_alternative(state)\n }\n\n // Make the same message as V8.\n if (this.regexp_eatQuantifier(state, true)) {\n state.raise(\"Nothing to repeat\")\n }\n if (state.eat(0x7B /* { */)) {\n state.raise(\"Lone quantifier brackets\")\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Alternative\npp.regexp_alternative = function(state) {\n while (state.pos < state.source.length && this.regexp_eatTerm(state))\n ;\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-Term\npp.regexp_eatTerm = function(state) {\n if (this.regexp_eatAssertion(state)) {\n // Handle `QuantifiableAssertion Quantifier` alternative.\n // `state.lastAssertionIsQuantifiable` is true if the last eaten Assertion\n // is a QuantifiableAssertion.\n if (state.lastAssertionIsQuantifiable && this.regexp_eatQuantifier(state)) {\n // Make the same message as V8.\n if (state.switchU) {\n state.raise(\"Invalid quantifier\")\n }\n }\n return true\n }\n\n if (state.switchU ? this.regexp_eatAtom(state) : this.regexp_eatExtendedAtom(state)) {\n this.regexp_eatQuantifier(state)\n return true\n }\n\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-Assertion\npp.regexp_eatAssertion = function(state) {\n const start = state.pos\n state.lastAssertionIsQuantifiable = false\n\n // ^, $\n if (state.eat(0x5E /* ^ */) || state.eat(0x24 /* $ */)) {\n return true\n }\n\n // \\b \\B\n if (state.eat(0x5C /* \\ */)) {\n if (state.eat(0x42 /* B */) || state.eat(0x62 /* b */)) {\n return true\n }\n state.pos = start\n }\n\n // Lookahead / Lookbehind\n if (state.eat(0x28 /* ( */) && state.eat(0x3F /* ? */)) {\n let lookbehind = false\n if (this.options.ecmaVersion >= 9) {\n lookbehind = state.eat(0x3C /* < */)\n }\n if (state.eat(0x3D /* = */) || state.eat(0x21 /* ! */)) {\n this.regexp_disjunction(state)\n if (!state.eat(0x29 /* ) */)) {\n state.raise(\"Unterminated group\")\n }\n state.lastAssertionIsQuantifiable = !lookbehind\n return true\n }\n }\n\n state.pos = start\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Quantifier\npp.regexp_eatQuantifier = function(state, noError = false) {\n if (this.regexp_eatQuantifierPrefix(state, noError)) {\n state.eat(0x3F /* ? */)\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-QuantifierPrefix\npp.regexp_eatQuantifierPrefix = function(state, noError) {\n return (\n state.eat(0x2A /* * */) ||\n state.eat(0x2B /* + */) ||\n state.eat(0x3F /* ? */) ||\n this.regexp_eatBracedQuantifier(state, noError)\n )\n}\npp.regexp_eatBracedQuantifier = function(state, noError) {\n const start = state.pos\n if (state.eat(0x7B /* { */)) {\n let min = 0, max = -1\n if (this.regexp_eatDecimalDigits(state)) {\n min = state.lastIntValue\n if (state.eat(0x2C /* , */) && this.regexp_eatDecimalDigits(state)) {\n max = state.lastIntValue\n }\n if (state.eat(0x7D /* } */)) {\n // SyntaxError in https://www.ecma-international.org/ecma-262/8.0/#sec-term\n if (max !== -1 && max < min && !noError) {\n state.raise(\"numbers out of order in {} quantifier\")\n }\n return true\n }\n }\n if (state.switchU && !noError) {\n state.raise(\"Incomplete quantifier\")\n }\n state.pos = start\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Atom\npp.regexp_eatAtom = function(state) {\n return (\n this.regexp_eatPatternCharacters(state) ||\n state.eat(0x2E /* . */) ||\n this.regexp_eatReverseSolidusAtomEscape(state) ||\n this.regexp_eatCharacterClass(state) ||\n this.regexp_eatUncapturingGroup(state) ||\n this.regexp_eatCapturingGroup(state)\n )\n}\npp.regexp_eatReverseSolidusAtomEscape = function(state) {\n const start = state.pos\n if (state.eat(0x5C /* \\ */)) {\n if (this.regexp_eatAtomEscape(state)) {\n return true\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatUncapturingGroup = function(state) {\n const start = state.pos\n if (state.eat(0x28 /* ( */)) {\n if (state.eat(0x3F /* ? */) && state.eat(0x3A /* : */)) {\n this.regexp_disjunction(state)\n if (state.eat(0x29 /* ) */)) {\n return true\n }\n state.raise(\"Unterminated group\")\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatCapturingGroup = function(state) {\n if (state.eat(0x28 /* ( */)) {\n if (this.options.ecmaVersion >= 9) {\n this.regexp_groupSpecifier(state)\n } else if (state.current() === 0x3F /* ? */) {\n state.raise(\"Invalid group\")\n }\n this.regexp_disjunction(state)\n if (state.eat(0x29 /* ) */)) {\n state.numCapturingParens += 1\n return true\n }\n state.raise(\"Unterminated group\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ExtendedAtom\npp.regexp_eatExtendedAtom = function(state) {\n return (\n state.eat(0x2E /* . */) ||\n this.regexp_eatReverseSolidusAtomEscape(state) ||\n this.regexp_eatCharacterClass(state) ||\n this.regexp_eatUncapturingGroup(state) ||\n this.regexp_eatCapturingGroup(state) ||\n this.regexp_eatInvalidBracedQuantifier(state) ||\n this.regexp_eatExtendedPatternCharacter(state)\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-InvalidBracedQuantifier\npp.regexp_eatInvalidBracedQuantifier = function(state) {\n if (this.regexp_eatBracedQuantifier(state, true)) {\n state.raise(\"Nothing to repeat\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-SyntaxCharacter\npp.regexp_eatSyntaxCharacter = function(state) {\n const ch = state.current()\n if (isSyntaxCharacter(ch)) {\n state.lastIntValue = ch\n state.advance()\n return true\n }\n return false\n}\nfunction isSyntaxCharacter(ch) {\n return (\n ch === 0x24 /* $ */ ||\n ch >= 0x28 /* ( */ && ch <= 0x2B /* + */ ||\n ch === 0x2E /* . */ ||\n ch === 0x3F /* ? */ ||\n ch >= 0x5B /* [ */ && ch <= 0x5E /* ^ */ ||\n ch >= 0x7B /* { */ && ch <= 0x7D /* } */\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-PatternCharacter\n// But eat eager.\npp.regexp_eatPatternCharacters = function(state) {\n const start = state.pos\n let ch = 0\n while ((ch = state.current()) !== -1 && !isSyntaxCharacter(ch)) {\n state.advance()\n }\n return state.pos !== start\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ExtendedPatternCharacter\npp.regexp_eatExtendedPatternCharacter = function(state) {\n const ch = state.current()\n if (\n ch !== -1 &&\n ch !== 0x24 /* $ */ &&\n !(ch >= 0x28 /* ( */ && ch <= 0x2B /* + */) &&\n ch !== 0x2E /* . */ &&\n ch !== 0x3F /* ? */ &&\n ch !== 0x5B /* [ */ &&\n ch !== 0x5E /* ^ */ &&\n ch !== 0x7C /* | */\n ) {\n state.advance()\n return true\n }\n return false\n}\n\n// GroupSpecifier[U] ::\n// [empty]\n// `?` GroupName[?U]\npp.regexp_groupSpecifier = function(state) {\n if (state.eat(0x3F /* ? */)) {\n if (this.regexp_eatGroupName(state)) {\n if (state.groupNames.indexOf(state.lastStringValue) !== -1) {\n state.raise(\"Duplicate capture group name\")\n }\n state.groupNames.push(state.lastStringValue)\n return\n }\n state.raise(\"Invalid group\")\n }\n}\n\n// GroupName[U] ::\n// `<` RegExpIdentifierName[?U] `>`\n// Note: this updates `state.lastStringValue` property with the eaten name.\npp.regexp_eatGroupName = function(state) {\n state.lastStringValue = \"\"\n if (state.eat(0x3C /* < */)) {\n if (this.regexp_eatRegExpIdentifierName(state) && state.eat(0x3E /* > */)) {\n return true\n }\n state.raise(\"Invalid capture group name\")\n }\n return false\n}\n\n// RegExpIdentifierName[U] ::\n// RegExpIdentifierStart[?U]\n// RegExpIdentifierName[?U] RegExpIdentifierPart[?U]\n// Note: this updates `state.lastStringValue` property with the eaten name.\npp.regexp_eatRegExpIdentifierName = function(state) {\n state.lastStringValue = \"\"\n if (this.regexp_eatRegExpIdentifierStart(state)) {\n state.lastStringValue += codePointToString(state.lastIntValue)\n while (this.regexp_eatRegExpIdentifierPart(state)) {\n state.lastStringValue += codePointToString(state.lastIntValue)\n }\n return true\n }\n return false\n}\n\n// RegExpIdentifierStart[U] ::\n// UnicodeIDStart\n// `$`\n// `_`\n// `\\` RegExpUnicodeEscapeSequence[?U]\npp.regexp_eatRegExpIdentifierStart = function(state) {\n const start = state.pos\n let ch = state.current()\n state.advance()\n\n if (ch === 0x5C /* \\ */ && this.regexp_eatRegExpUnicodeEscapeSequence(state)) {\n ch = state.lastIntValue\n }\n if (isRegExpIdentifierStart(ch)) {\n state.lastIntValue = ch\n return true\n }\n\n state.pos = start\n return false\n}\nfunction isRegExpIdentifierStart(ch) {\n return isIdentifierStart(ch, true) || ch === 0x24 /* $ */ || ch === 0x5F /* _ */\n}\n\n// RegExpIdentifierPart[U] ::\n// UnicodeIDContinue\n// `$`\n// `_`\n// `\\` RegExpUnicodeEscapeSequence[?U]\n// \n// \npp.regexp_eatRegExpIdentifierPart = function(state) {\n const start = state.pos\n let ch = state.current()\n state.advance()\n\n if (ch === 0x5C /* \\ */ && this.regexp_eatRegExpUnicodeEscapeSequence(state)) {\n ch = state.lastIntValue\n }\n if (isRegExpIdentifierPart(ch)) {\n state.lastIntValue = ch\n return true\n }\n\n state.pos = start\n return false\n}\nfunction isRegExpIdentifierPart(ch) {\n return isIdentifierChar(ch, true) || ch === 0x24 /* $ */ || ch === 0x5F /* _ */ || ch === 0x200C /* */ || ch === 0x200D /* */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-AtomEscape\npp.regexp_eatAtomEscape = function(state) {\n if (\n this.regexp_eatBackReference(state) ||\n this.regexp_eatCharacterClassEscape(state) ||\n this.regexp_eatCharacterEscape(state) ||\n (state.switchN && this.regexp_eatKGroupName(state))\n ) {\n return true\n }\n if (state.switchU) {\n // Make the same message as V8.\n if (state.current() === 0x63 /* c */) {\n state.raise(\"Invalid unicode escape\")\n }\n state.raise(\"Invalid escape\")\n }\n return false\n}\npp.regexp_eatBackReference = function(state) {\n const start = state.pos\n if (this.regexp_eatDecimalEscape(state)) {\n const n = state.lastIntValue\n if (state.switchU) {\n // For SyntaxError in https://www.ecma-international.org/ecma-262/8.0/#sec-atomescape\n if (n > state.maxBackReference) {\n state.maxBackReference = n\n }\n return true\n }\n if (n <= state.numCapturingParens) {\n return true\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatKGroupName = function(state) {\n if (state.eat(0x6B /* k */)) {\n if (this.regexp_eatGroupName(state)) {\n state.backReferenceNames.push(state.lastStringValue)\n return true\n }\n state.raise(\"Invalid named reference\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-CharacterEscape\npp.regexp_eatCharacterEscape = function(state) {\n return (\n this.regexp_eatControlEscape(state) ||\n this.regexp_eatCControlLetter(state) ||\n this.regexp_eatZero(state) ||\n this.regexp_eatHexEscapeSequence(state) ||\n this.regexp_eatRegExpUnicodeEscapeSequence(state) ||\n (!state.switchU && this.regexp_eatLegacyOctalEscapeSequence(state)) ||\n this.regexp_eatIdentityEscape(state)\n )\n}\npp.regexp_eatCControlLetter = function(state) {\n const start = state.pos\n if (state.eat(0x63 /* c */)) {\n if (this.regexp_eatControlLetter(state)) {\n return true\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatZero = function(state) {\n if (state.current() === 0x30 /* 0 */ && !isDecimalDigit(state.lookahead())) {\n state.lastIntValue = 0\n state.advance()\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ControlEscape\npp.regexp_eatControlEscape = function(state) {\n const ch = state.current()\n if (ch === 0x74 /* t */) {\n state.lastIntValue = 0x09 /* \\t */\n state.advance()\n return true\n }\n if (ch === 0x6E /* n */) {\n state.lastIntValue = 0x0A /* \\n */\n state.advance()\n return true\n }\n if (ch === 0x76 /* v */) {\n state.lastIntValue = 0x0B /* \\v */\n state.advance()\n return true\n }\n if (ch === 0x66 /* f */) {\n state.lastIntValue = 0x0C /* \\f */\n state.advance()\n return true\n }\n if (ch === 0x72 /* r */) {\n state.lastIntValue = 0x0D /* \\r */\n state.advance()\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ControlLetter\npp.regexp_eatControlLetter = function(state) {\n const ch = state.current()\n if (isControlLetter(ch)) {\n state.lastIntValue = ch % 0x20\n state.advance()\n return true\n }\n return false\n}\nfunction isControlLetter(ch) {\n return (\n (ch >= 0x41 /* A */ && ch <= 0x5A /* Z */) ||\n (ch >= 0x61 /* a */ && ch <= 0x7A /* z */)\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-RegExpUnicodeEscapeSequence\npp.regexp_eatRegExpUnicodeEscapeSequence = function(state) {\n const start = state.pos\n\n if (state.eat(0x75 /* u */)) {\n if (this.regexp_eatFixedHexDigits(state, 4)) {\n const lead = state.lastIntValue\n if (state.switchU && lead >= 0xD800 && lead <= 0xDBFF) {\n const leadSurrogateEnd = state.pos\n if (state.eat(0x5C /* \\ */) && state.eat(0x75 /* u */) && this.regexp_eatFixedHexDigits(state, 4)) {\n const trail = state.lastIntValue\n if (trail >= 0xDC00 && trail <= 0xDFFF) {\n state.lastIntValue = (lead - 0xD800) * 0x400 + (trail - 0xDC00) + 0x10000\n return true\n }\n }\n state.pos = leadSurrogateEnd\n state.lastIntValue = lead\n }\n return true\n }\n if (\n state.switchU &&\n state.eat(0x7B /* { */) &&\n this.regexp_eatHexDigits(state) &&\n state.eat(0x7D /* } */) &&\n isValidUnicode(state.lastIntValue)\n ) {\n return true\n }\n if (state.switchU) {\n state.raise(\"Invalid unicode escape\")\n }\n state.pos = start\n }\n\n return false\n}\nfunction isValidUnicode(ch) {\n return ch >= 0 && ch <= 0x10FFFF\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-IdentityEscape\npp.regexp_eatIdentityEscape = function(state) {\n if (state.switchU) {\n if (this.regexp_eatSyntaxCharacter(state)) {\n return true\n }\n if (state.eat(0x2F /* / */)) {\n state.lastIntValue = 0x2F /* / */\n return true\n }\n return false\n }\n\n const ch = state.current()\n if (ch !== 0x63 /* c */ && (!state.switchN || ch !== 0x6B /* k */)) {\n state.lastIntValue = ch\n state.advance()\n return true\n }\n\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-DecimalEscape\npp.regexp_eatDecimalEscape = function(state) {\n state.lastIntValue = 0\n let ch = state.current()\n if (ch >= 0x31 /* 1 */ && ch <= 0x39 /* 9 */) {\n do {\n state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30 /* 0 */)\n state.advance()\n } while ((ch = state.current()) >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */)\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-CharacterClassEscape\npp.regexp_eatCharacterClassEscape = function(state) {\n const ch = state.current()\n\n if (isCharacterClassEscape(ch)) {\n state.lastIntValue = -1\n state.advance()\n return true\n }\n\n if (\n state.switchU &&\n this.options.ecmaVersion >= 9 &&\n (ch === 0x50 /* P */ || ch === 0x70 /* p */)\n ) {\n state.lastIntValue = -1\n state.advance()\n if (\n state.eat(0x7B /* { */) &&\n this.regexp_eatUnicodePropertyValueExpression(state) &&\n state.eat(0x7D /* } */)\n ) {\n return true\n }\n state.raise(\"Invalid property name\")\n }\n\n return false\n}\nfunction isCharacterClassEscape(ch) {\n return (\n ch === 0x64 /* d */ ||\n ch === 0x44 /* D */ ||\n ch === 0x73 /* s */ ||\n ch === 0x53 /* S */ ||\n ch === 0x77 /* w */ ||\n ch === 0x57 /* W */\n )\n}\n\n// UnicodePropertyValueExpression ::\n// UnicodePropertyName `=` UnicodePropertyValue\n// LoneUnicodePropertyNameOrValue\npp.regexp_eatUnicodePropertyValueExpression = function(state) {\n const start = state.pos\n\n // UnicodePropertyName `=` UnicodePropertyValue\n if (this.regexp_eatUnicodePropertyName(state) && state.eat(0x3D /* = */)) {\n const name = state.lastStringValue\n if (this.regexp_eatUnicodePropertyValue(state)) {\n const value = state.lastStringValue\n this.regexp_validateUnicodePropertyNameAndValue(state, name, value)\n return true\n }\n }\n state.pos = start\n\n // LoneUnicodePropertyNameOrValue\n if (this.regexp_eatLoneUnicodePropertyNameOrValue(state)) {\n const nameOrValue = state.lastStringValue\n this.regexp_validateUnicodePropertyNameOrValue(state, nameOrValue)\n return true\n }\n return false\n}\npp.regexp_validateUnicodePropertyNameAndValue = function(state, name, value) {\n if (!has(state.unicodeProperties.nonBinary, name))\n state.raise(\"Invalid property name\")\n if (!state.unicodeProperties.nonBinary[name].test(value))\n state.raise(\"Invalid property value\")\n}\npp.regexp_validateUnicodePropertyNameOrValue = function(state, nameOrValue) {\n if (!state.unicodeProperties.binary.test(nameOrValue))\n state.raise(\"Invalid property name\")\n}\n\n// UnicodePropertyName ::\n// UnicodePropertyNameCharacters\npp.regexp_eatUnicodePropertyName = function(state) {\n let ch = 0\n state.lastStringValue = \"\"\n while (isUnicodePropertyNameCharacter(ch = state.current())) {\n state.lastStringValue += codePointToString(ch)\n state.advance()\n }\n return state.lastStringValue !== \"\"\n}\nfunction isUnicodePropertyNameCharacter(ch) {\n return isControlLetter(ch) || ch === 0x5F /* _ */\n}\n\n// UnicodePropertyValue ::\n// UnicodePropertyValueCharacters\npp.regexp_eatUnicodePropertyValue = function(state) {\n let ch = 0\n state.lastStringValue = \"\"\n while (isUnicodePropertyValueCharacter(ch = state.current())) {\n state.lastStringValue += codePointToString(ch)\n state.advance()\n }\n return state.lastStringValue !== \"\"\n}\nfunction isUnicodePropertyValueCharacter(ch) {\n return isUnicodePropertyNameCharacter(ch) || isDecimalDigit(ch)\n}\n\n// LoneUnicodePropertyNameOrValue ::\n// UnicodePropertyValueCharacters\npp.regexp_eatLoneUnicodePropertyNameOrValue = function(state) {\n return this.regexp_eatUnicodePropertyValue(state)\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-CharacterClass\npp.regexp_eatCharacterClass = function(state) {\n if (state.eat(0x5B /* [ */)) {\n state.eat(0x5E /* ^ */)\n this.regexp_classRanges(state)\n if (state.eat(0x5D /* [ */)) {\n return true\n }\n // Unreachable since it threw \"unterminated regular expression\" error before.\n state.raise(\"Unterminated character class\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ClassRanges\n// https://www.ecma-international.org/ecma-262/8.0/#prod-NonemptyClassRanges\n// https://www.ecma-international.org/ecma-262/8.0/#prod-NonemptyClassRangesNoDash\npp.regexp_classRanges = function(state) {\n while (this.regexp_eatClassAtom(state)) {\n const left = state.lastIntValue\n if (state.eat(0x2D /* - */) && this.regexp_eatClassAtom(state)) {\n const right = state.lastIntValue\n if (state.switchU && (left === -1 || right === -1)) {\n state.raise(\"Invalid character class\")\n }\n if (left !== -1 && right !== -1 && left > right) {\n state.raise(\"Range out of order in character class\")\n }\n }\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ClassAtom\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ClassAtomNoDash\npp.regexp_eatClassAtom = function(state) {\n const start = state.pos\n\n if (state.eat(0x5C /* \\ */)) {\n if (this.regexp_eatClassEscape(state)) {\n return true\n }\n if (state.switchU) {\n // Make the same message as V8.\n const ch = state.current()\n if (ch === 0x63 /* c */ || isOctalDigit(ch)) {\n state.raise(\"Invalid class escape\")\n }\n state.raise(\"Invalid escape\")\n }\n state.pos = start\n }\n\n const ch = state.current()\n if (ch !== 0x5D /* [ */) {\n state.lastIntValue = ch\n state.advance()\n return true\n }\n\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ClassEscape\npp.regexp_eatClassEscape = function(state) {\n const start = state.pos\n\n if (state.eat(0x62 /* b */)) {\n state.lastIntValue = 0x08 /* */\n return true\n }\n\n if (state.switchU && state.eat(0x2D /* - */)) {\n state.lastIntValue = 0x2D /* - */\n return true\n }\n\n if (!state.switchU && state.eat(0x63 /* c */)) {\n if (this.regexp_eatClassControlLetter(state)) {\n return true\n }\n state.pos = start\n }\n\n return (\n this.regexp_eatCharacterClassEscape(state) ||\n this.regexp_eatCharacterEscape(state)\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ClassControlLetter\npp.regexp_eatClassControlLetter = function(state) {\n const ch = state.current()\n if (isDecimalDigit(ch) || ch === 0x5F /* _ */) {\n state.lastIntValue = ch % 0x20\n state.advance()\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-HexEscapeSequence\npp.regexp_eatHexEscapeSequence = function(state) {\n const start = state.pos\n if (state.eat(0x78 /* x */)) {\n if (this.regexp_eatFixedHexDigits(state, 2)) {\n return true\n }\n if (state.switchU) {\n state.raise(\"Invalid escape\")\n }\n state.pos = start\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-DecimalDigits\npp.regexp_eatDecimalDigits = function(state) {\n const start = state.pos\n let ch = 0\n state.lastIntValue = 0\n while (isDecimalDigit(ch = state.current())) {\n state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30 /* 0 */)\n state.advance()\n }\n return state.pos !== start\n}\nfunction isDecimalDigit(ch) {\n return ch >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-HexDigits\npp.regexp_eatHexDigits = function(state) {\n const start = state.pos\n let ch = 0\n state.lastIntValue = 0\n while (isHexDigit(ch = state.current())) {\n state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch)\n state.advance()\n }\n return state.pos !== start\n}\nfunction isHexDigit(ch) {\n return (\n (ch >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */) ||\n (ch >= 0x41 /* A */ && ch <= 0x46 /* F */) ||\n (ch >= 0x61 /* a */ && ch <= 0x66 /* f */)\n )\n}\nfunction hexToInt(ch) {\n if (ch >= 0x41 /* A */ && ch <= 0x46 /* F */) {\n return 10 + (ch - 0x41 /* A */)\n }\n if (ch >= 0x61 /* a */ && ch <= 0x66 /* f */) {\n return 10 + (ch - 0x61 /* a */)\n }\n return ch - 0x30 /* 0 */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-LegacyOctalEscapeSequence\n// Allows only 0-377(octal) i.e. 0-255(decimal).\npp.regexp_eatLegacyOctalEscapeSequence = function(state) {\n if (this.regexp_eatOctalDigit(state)) {\n const n1 = state.lastIntValue\n if (this.regexp_eatOctalDigit(state)) {\n const n2 = state.lastIntValue\n if (n1 <= 3 && this.regexp_eatOctalDigit(state)) {\n state.lastIntValue = n1 * 64 + n2 * 8 + state.lastIntValue\n } else {\n state.lastIntValue = n1 * 8 + n2\n }\n } else {\n state.lastIntValue = n1\n }\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-OctalDigit\npp.regexp_eatOctalDigit = function(state) {\n const ch = state.current()\n if (isOctalDigit(ch)) {\n state.lastIntValue = ch - 0x30 /* 0 */\n state.advance()\n return true\n }\n state.lastIntValue = 0\n return false\n}\nfunction isOctalDigit(ch) {\n return ch >= 0x30 /* 0 */ && ch <= 0x37 /* 7 */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Hex4Digits\n// https://www.ecma-international.org/ecma-262/8.0/#prod-HexDigit\n// And HexDigit HexDigit in https://www.ecma-international.org/ecma-262/8.0/#prod-HexEscapeSequence\npp.regexp_eatFixedHexDigits = function(state, length) {\n const start = state.pos\n state.lastIntValue = 0\n for (let i = 0; i < length; ++i) {\n const ch = state.current()\n if (!isHexDigit(ch)) {\n state.pos = start\n return false\n }\n state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch)\n state.advance()\n }\n return true\n}\n","import {isIdentifierStart, isIdentifierChar} from \"./identifier\"\nimport {types as tt, keywords as keywordTypes} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {SourceLocation} from \"./locutil\"\nimport {RegExpValidationState} from \"./regexp\"\nimport {lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace} from \"./whitespace\"\n\n// Object type used to represent tokens. Note that normally, tokens\n// simply exist as properties on the parser object. This is only\n// used for the onToken callback and the external tokenizer.\n\nexport class Token {\n constructor(p) {\n this.type = p.type\n this.value = p.value\n this.start = p.start\n this.end = p.end\n if (p.options.locations)\n this.loc = new SourceLocation(p, p.startLoc, p.endLoc)\n if (p.options.ranges)\n this.range = [p.start, p.end]\n }\n}\n\n// ## Tokenizer\n\nconst pp = Parser.prototype\n\n// Move to the next token\n\npp.next = function() {\n if (this.options.onToken)\n this.options.onToken(new Token(this))\n\n this.lastTokEnd = this.end\n this.lastTokStart = this.start\n this.lastTokEndLoc = this.endLoc\n this.lastTokStartLoc = this.startLoc\n this.nextToken()\n}\n\npp.getToken = function() {\n this.next()\n return new Token(this)\n}\n\n// If we're in an ES6 environment, make parsers iterable\nif (typeof Symbol !== \"undefined\")\n pp[Symbol.iterator] = function() {\n return {\n next: () => {\n let token = this.getToken()\n return {\n done: token.type === tt.eof,\n value: token\n }\n }\n }\n }\n\n// Toggle strict mode. Re-reads the next number or string to please\n// pedantic tests (`\"use strict\"; 010;` should fail).\n\npp.curContext = function() {\n return this.context[this.context.length - 1]\n}\n\n// Read a single token, updating the parser object's token-related\n// properties.\n\npp.nextToken = function() {\n let curContext = this.curContext()\n if (!curContext || !curContext.preserveSpace) this.skipSpace()\n\n this.start = this.pos\n if (this.options.locations) this.startLoc = this.curPosition()\n if (this.pos >= this.input.length) return this.finishToken(tt.eof)\n\n if (curContext.override) return curContext.override(this)\n else this.readToken(this.fullCharCodeAtPos())\n}\n\npp.readToken = function(code) {\n // Identifier or keyword. '\\uXXXX' sequences are allowed in\n // identifiers, so '\\' also dispatches to that.\n if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\\' */)\n return this.readWord()\n\n return this.getTokenFromCode(code)\n}\n\npp.fullCharCodeAtPos = function() {\n let code = this.input.charCodeAt(this.pos)\n if (code <= 0xd7ff || code >= 0xe000) return code\n let next = this.input.charCodeAt(this.pos + 1)\n return (code << 10) + next - 0x35fdc00\n}\n\npp.skipBlockComment = function() {\n let startLoc = this.options.onComment && this.curPosition()\n let start = this.pos, end = this.input.indexOf(\"*/\", this.pos += 2)\n if (end === -1) this.raise(this.pos - 2, \"Unterminated comment\")\n this.pos = end + 2\n if (this.options.locations) {\n lineBreakG.lastIndex = start\n let match\n while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) {\n ++this.curLine\n this.lineStart = match.index + match[0].length\n }\n }\n if (this.options.onComment)\n this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos,\n startLoc, this.curPosition())\n}\n\npp.skipLineComment = function(startSkip) {\n let start = this.pos\n let startLoc = this.options.onComment && this.curPosition()\n let ch = this.input.charCodeAt(this.pos += startSkip)\n while (this.pos < this.input.length && !isNewLine(ch)) {\n ch = this.input.charCodeAt(++this.pos)\n }\n if (this.options.onComment)\n this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos,\n startLoc, this.curPosition())\n}\n\n// Called at the start of the parse and after every token. Skips\n// whitespace and comments, and.\n\npp.skipSpace = function() {\n loop: while (this.pos < this.input.length) {\n let ch = this.input.charCodeAt(this.pos)\n switch (ch) {\n case 32: case 160: // ' '\n ++this.pos\n break\n case 13:\n if (this.input.charCodeAt(this.pos + 1) === 10) {\n ++this.pos\n }\n case 10: case 8232: case 8233:\n ++this.pos\n if (this.options.locations) {\n ++this.curLine\n this.lineStart = this.pos\n }\n break\n case 47: // '/'\n switch (this.input.charCodeAt(this.pos + 1)) {\n case 42: // '*'\n this.skipBlockComment()\n break\n case 47:\n this.skipLineComment(2)\n break\n default:\n break loop\n }\n break\n default:\n if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) {\n ++this.pos\n } else {\n break loop\n }\n }\n }\n}\n\n// Called at the end of every token. Sets `end`, `val`, and\n// maintains `context` and `exprAllowed`, and skips the space after\n// the token, so that the next one's `start` will point at the\n// right position.\n\npp.finishToken = function(type, val) {\n this.end = this.pos\n if (this.options.locations) this.endLoc = this.curPosition()\n let prevType = this.type\n this.type = type\n this.value = val\n\n this.updateContext(prevType)\n}\n\n// ### Token reading\n\n// This is the function that is called to fetch the next token. It\n// is somewhat obscure, because it works in character codes rather\n// than characters, and because operator parsing has been inlined\n// into it.\n//\n// All in the name of speed.\n//\npp.readToken_dot = function() {\n let next = this.input.charCodeAt(this.pos + 1)\n if (next >= 48 && next <= 57) return this.readNumber(true)\n let next2 = this.input.charCodeAt(this.pos + 2)\n if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.'\n this.pos += 3\n return this.finishToken(tt.ellipsis)\n } else {\n ++this.pos\n return this.finishToken(tt.dot)\n }\n}\n\npp.readToken_slash = function() { // '/'\n let next = this.input.charCodeAt(this.pos + 1)\n if (this.exprAllowed) { ++this.pos; return this.readRegexp() }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.slash, 1)\n}\n\npp.readToken_mult_modulo_exp = function(code) { // '%*'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n let tokentype = code === 42 ? tt.star : tt.modulo\n\n // exponentiation operator ** and **=\n if (this.options.ecmaVersion >= 7 && code === 42 && next === 42) {\n ++size\n tokentype = tt.starstar\n next = this.input.charCodeAt(this.pos + 2)\n }\n\n if (next === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tokentype, size)\n}\n\npp.readToken_pipe_amp = function(code) { // '|&'\n let next = this.input.charCodeAt(this.pos + 1)\n if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2)\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1)\n}\n\npp.readToken_caret = function() { // '^'\n let next = this.input.charCodeAt(this.pos + 1)\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.bitwiseXOR, 1)\n}\n\npp.readToken_plus_min = function(code) { // '+-'\n let next = this.input.charCodeAt(this.pos + 1)\n if (next === code) {\n if (next === 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 62 &&\n (this.lastTokEnd === 0 || lineBreak.test(this.input.slice(this.lastTokEnd, this.pos)))) {\n // A `-->` line comment\n this.skipLineComment(3)\n this.skipSpace()\n return this.nextToken()\n }\n return this.finishOp(tt.incDec, 2)\n }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.plusMin, 1)\n}\n\npp.readToken_lt_gt = function(code) { // '<>'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n if (next === code) {\n size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2\n if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tt.bitShift, size)\n }\n if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 &&\n this.input.charCodeAt(this.pos + 3) === 45) {\n // `` line comment - this.skipLineComment(3); - this.skipSpace(); - return this.nextToken() - } - return this.finishOp(types.incDec, 2) - } - if (next === 61) { return this.finishOp(types.assign, 2) } - return this.finishOp(types.plusMin, 1) -}; - -pp$8.readToken_lt_gt = function(code) { // '<>' - var next = this.input.charCodeAt(this.pos + 1); - var size = 1; - if (next === code) { - size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; - if (this.input.charCodeAt(this.pos + size) === 61) { return this.finishOp(types.assign, size + 1) } - return this.finishOp(types.bitShift, size) - } - if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 && - this.input.charCodeAt(this.pos + 3) === 45) { - // `` line comment\n this.skipLineComment(3)\n this.skipSpace()\n return this.nextToken()\n }\n return this.finishOp(tt.incDec, 2)\n }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.plusMin, 1)\n}\n\npp.readToken_lt_gt = function(code) { // '<>'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n if (next === code) {\n size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2\n if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tt.bitShift, size)\n }\n if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 &&\n this.input.charCodeAt(this.pos + 3) === 45) {\n // ` ```js (async () => { await assert.doesNotReject( @@ -465,6 +466,7 @@ Besides the async nature to await the completion behaves identically to })(); ``` + ```js assert.doesNotReject(Promise.reject(new TypeError('Wrong value'))) .then(() => { diff --git a/doc/api/cli.md b/doc/api/cli.md index c0682d864c9d0a..a8a18620fb3152 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -107,6 +107,16 @@ added: v12.0.0 Specify the directory where the CPU profiles generated by `--cpu-prof` will be placed. +### `--cpu-prof-interval` + + +> Stability: 1 - Experimental + +Specify the sampling interval in microseconds for the CPU profiles generated +by `--cpu-prof`. The default is 1000 microseconds. + ### `--cpu-prof-name` + +Set default [`tls.DEFAULT_MIN_VERSION`][] to 'TLSv1.2'. This is the default for +12.x and later, but the option is supported for compatibility with older Node.js +versions. + ### `--tls-min-v1.3` + +Prints TLS packet trace information to `stderr`. This can be used to debug TLS +connection problems. + ### `--trace-warnings` + +Type: Documentation-only + +Module.createRequireFromPath() is deprecated. Please use [`module.createRequire()`][] instead. + [`--pending-deprecation`]: cli.html#cli_pending_deprecation [`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size [`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array @@ -2486,6 +2499,7 @@ instead. [`http.request()`]: http.html#http_http_request_options_callback [`https.get()`]: https.html#https_https_get_options_callback [`https.request()`]: https.html#https_https_request_options_callback +[`module.createRequire()`]: modules.html#modules_module_createrequire_filename [`os.networkInterfaces()`]: os.html#os_os_networkinterfaces [`os.tmpdir()`]: os.html#os_os_tmpdir [`process.env`]: process.html#process_process_env diff --git a/doc/api/errors.md b/doc/api/errors.md index 79570ffb510ea9..2cb4bc067e24b8 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1305,7 +1305,7 @@ invalid. ### ERR_INVALID_PROTOCOL -An invalid `options.protocol` was passed. +An invalid `options.protocol` was passed to `http.request()`. ### ERR_INVALID_REPL_EVAL_CONFIG diff --git a/doc/api/https.md b/doc/api/https.md index 95e7e715c32ca5..9b6ec83a6e7796 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -29,6 +29,10 @@ An [`Agent`][] object for HTTPS similar to [`http.Agent`][]. See Can have the same fields as for [`http.Agent(options)`][], and * `maxCachedSessions` {number} maximum number of TLS cached sessions. Use `0` to disable TLS session caching. **Default:** `100`. + * `servername` {string} the value of + [Server Name Indication extension][sni wiki] to be sent to the server. Use + empty string `''` to disable sending the extension. + **Default:** hostname or IP address of the target server. See [`Session Resumption`][] for infomation about TLS session reuse. @@ -406,3 +410,4 @@ headers: max-age=0; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; p [`tls.createSecureContext()`]: tls.html#tls_tls_createsecurecontext_options [`tls.createServer()`]: tls.html#tls_tls_createserver_options_secureconnectionlistener [`Session Resumption`]: tls.html#tls_session_resumption +[sni wiki]: https://en.wikipedia.org/wiki/Server_Name_Indication diff --git a/doc/api/modules.md b/doc/api/modules.md index d52d4ddac5f32e..9266d43f49abcd 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -132,6 +132,13 @@ variable. Since the module lookups using `node_modules` folders are all relative, and based on the real path of the files making the calls to `require()`, the packages themselves can be anywhere. +## Addenda: The .mjs extension + +It is not possible to `require()` files that have the `.mjs` extension. +Attempting to do so will throw [an error][]. The `.mjs` extension is +reserved for [ECMAScript Modules][] which cannot be loaded via `require()`. +See [ECMAScript Modules][] for more details. + ## All Together... @@ -905,18 +912,39 @@ by the [module wrapper][]. To access it, require the `Module` module: const builtin = require('module').builtinModules; ``` +### module.createRequire(filename) + + +* `filename` {string|URL} Filename to be used to construct the require + function. Must be a file URL object, file URL string, or absolute path + string. +* Returns: {require} Require function + +```js +const { createRequire } = require('module'); +const requireUtil = createRequire(require.resolve('../src/utils/')); + +// Require `../src/utils/some-tool` +requireUtil('./some-tool'); +``` + ### module.createRequireFromPath(filename) * `filename` {string} Filename to be used to construct the relative require function. * Returns: {require} Require function +> Stability: 0 - Deprecated: Please use [`createRequire()`][] instead. + ```js const { createRequireFromPath } = require('module'); -const requireUtil = createRequireFromPath('../src/utils'); +const requireUtil = createRequireFromPath('../src/utils/'); // Require `../src/utils/some-tool` requireUtil('./some-tool'); @@ -926,8 +954,11 @@ requireUtil('./some-tool'); [`Error`]: errors.html#errors_class_error [`__dirname`]: #modules_dirname [`__filename`]: #modules_filename +[`createRequire()`]: #modules_module_createrequire_filename [`module` object]: #modules_the_module_object [`path.dirname()`]: path.html#path_path_dirname_path +[ECMAScript Modules]: esm.html +[an error]: errors.html#errors_err_require_esm [exports shortcut]: #modules_exports_shortcut [module resolution]: #modules_all_together [module wrapper]: #modules_the_module_wrapper diff --git a/doc/api/tls.md b/doc/api/tls.md index 6a834c65ff3012..2c433fd50d3fec 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -586,6 +586,9 @@ connection is open. + +When enabled, TLS packet trace information is written to `stderr`. This can be +used to debug TLS connection problems. + +Note: The format of the output is identical to the output of `openssl s_client +-trace` or `openssl s_server -trace`. While it is produced by OpenSSL's +`SSL_trace()` function, the format is undocumented, can change without notice, +and should not be relied on. + ### tlsSocket.encrypted * `options` {Object} + * `enableTrace`: See [`tls.createServer()`][] * `host` {string} Host the client should connect to. **Default:** `'localhost'`. * `port` {number} Port the client should connect to. @@ -1438,6 +1459,10 @@ changes: `['hello', 'world']`. (Protocols should be ordered by their priority.) * `clientCertEngine` {string} Name of an OpenSSL engine which can provide the client certificate. + * `enableTrace` {boolean} If `true`, [`tls.TLSSocket.enableTrace()`][] will be + called on new connections. Tracing can be enabled after the secure + connection is established, but this option must be used to trace the secure + connection setup. **Default:** `false`. * `handshakeTimeout` {number} Abort the connection if the SSL/TLS handshake does not finish in the specified number of milliseconds. A `'tlsClientError'` is emitted on the `tls.Server` object whenever @@ -1630,6 +1655,7 @@ changes: * `rejectUnauthorized` {boolean} If not `false` a server automatically reject clients with invalid certificates. Only applies when `isServer` is `true`. * `options` + * `enableTrace`: See [`tls.createServer()`][] * `secureContext`: A TLS context object from [`tls.createSecureContext()`][] * `isServer`: If `true` the TLS socket will be instantiated in server-mode. **Default:** `false`. @@ -1693,6 +1719,7 @@ where `secureSocket` has the same API as `pair.cleartext`. [`tls.DEFAULT_MAX_VERSION`]: #tls_tls_default_max_version [`tls.DEFAULT_MIN_VERSION`]: #tls_tls_default_min_version [`tls.Server`]: #tls_class_tls_server +[`tls.TLSSocket.enableTrace()`]: #tls_tlssocket_enabletrace [`tls.TLSSocket.getPeerCertificate()`]: #tls_tlssocket_getpeercertificate_detailed [`tls.TLSSocket.getSession()`]: #tls_tlssocket_getsession [`tls.TLSSocket.getTLSTicket()`]: #tls_tlssocket_gettlsticket diff --git a/doc/changelogs/CHANGELOG_V12.md b/doc/changelogs/CHANGELOG_V12.md index 7ad04db5bcbafa..fae9305913b37a 100644 --- a/doc/changelogs/CHANGELOG_V12.md +++ b/doc/changelogs/CHANGELOG_V12.md @@ -9,6 +9,7 @@ +12.2.0
12.1.0
12.0.0
@@ -29,6 +30,146 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + +## 2019-05-07, Version 12.2.0 (Current), @targos + +### Notable changes + +* **deps**: + * Updated llhttp to 1.1.3. This fixes a bug that made Node.js' HTTP parser + refuse any request URL that contained the "|" (vertical bar) character (Fedor Indutny) [#27595](https://github.com/nodejs/node/pull/27595). +* **tls**: + * Added an `enableTrace()` method to `TLSSocket` and an `enableTrace` option + to `tls.createServer()`. When enabled, TSL packet trace information is + written to `stderr`. This can be used to debug TLS connection problems (cjihrig) [#27497](https://github.com/nodejs/node/pull/27497), (Sam Roberts) [#27376](https://github.com/nodejs/node/pull/27376). +* **cli**: + * Added a `--trace-tls` command-line flag that enables tracing of TLS + connections without the need to modify existing application code (cjihrig) [#27497](https://github.com/nodejs/node/pull/27497). + * Added a `--cpu-prof-interval` command-line flag. It can be used to specify + the sampling interval for the CPU profiles generated by `--cpu-prof` (Joyee Cheung) [#27535](https://github.com/nodejs/node/pull/27535). +* **module**: + * Added the `createRequire()` method. It allows to create a require function + from a file URL object, a file URL string or an absolute path string. The + existing `createRequireFromPath()` method is now deprecated (Myles Borins) [#27405](https://github.com/nodejs/node/pull/27405). + * Throw on `require('./path.mjs')`. This is technically a breaking change that + should have landed with Node.js 12.0.0. It is necessary to have this to keep + the possibility for a future minor version to load ES Modules with the + require function (Myles Borins) [#27417](https://github.com/nodejs/node/pull/27417). +* **repl**: + * The REPL now supports multi-line statements using `BigInt` literals as well + as public and private class fields and methods (Ruben Bridgewater) [#27400](https://github.com/nodejs/node/pull/27400). + * The REPL now supports tab autocompletion of file paths with `fs` methods (Anto Aravinth) [#26648](https://github.com/nodejs/node/pull/26648). +* **meta**: + * Added [Christian Clauss](https://github.com/cclauss) to collaborators [#27554](https://github.com/nodejs/node/pull/27554). + +### Commits + +* [[`c0ab2a141b`](https://github.com/nodejs/node/commit/c0ab2a141b)] - **assert**: use new language features (Ruben Bridgewater) [#27400](https://github.com/nodejs/node/pull/27400) +* [[`4b3d0d1953`](https://github.com/nodejs/node/commit/4b3d0d1953)] - **async_hooks**: fixup do not reuse HTTPParser (Gerhard Stoebich) [#27477](https://github.com/nodejs/node/pull/27477) +* [[`cfc7bdd303`](https://github.com/nodejs/node/commit/cfc7bdd303)] - **benchmark**: add benchmark for node -p (Joyee Cheung) [#27320](https://github.com/nodejs/node/pull/27320) +* [[`53eefeb73e`](https://github.com/nodejs/node/commit/53eefeb73e)] - **buffer**: remove unreachable code (Rich Trott) [#27445](https://github.com/nodejs/node/pull/27445) +* [[`cac584d260`](https://github.com/nodejs/node/commit/cac584d260)] - **buffer,errors**: improve bigint, big numbers and more (Ruben Bridgewater) [#27228](https://github.com/nodejs/node/pull/27228) +* [[`22a5a05785`](https://github.com/nodejs/node/commit/22a5a05785)] - **build**: delegate building from Makefile to ninja (Refael Ackermann) [#27504](https://github.com/nodejs/node/pull/27504) +* [[`67205f5941`](https://github.com/nodejs/node/commit/67205f5941)] - **build**: remove unsupported Python 2.6 from configure (cclauss) [#27381](https://github.com/nodejs/node/pull/27381) +* [[`615d386390`](https://github.com/nodejs/node/commit/615d386390)] - **child_process**: only stop readable side of stream passed to proc (Anna Henningsen) [#27373](https://github.com/nodejs/node/pull/27373) +* [[`8e876e60aa`](https://github.com/nodejs/node/commit/8e876e60aa)] - **console**: use consolePropAttributes for k-bind properties (reland) (Ruben Bridgewater) [#27352](https://github.com/nodejs/node/pull/27352) +* [[`55804e1726`](https://github.com/nodejs/node/commit/55804e1726)] - **deps**: update llhttp to 1.1.2 (Fedor Indutny) [#27513](https://github.com/nodejs/node/pull/27513) +* [[`f142363cfa`](https://github.com/nodejs/node/commit/f142363cfa)] - **deps**: update llhttp to 1.1.3 (Fedor Indutny) [#27595](https://github.com/nodejs/node/pull/27595) +* [[`5f72246499`](https://github.com/nodejs/node/commit/5f72246499)] - **deps**: add acorn stage-3 plugins (Ruben Bridgewater) [#27400](https://github.com/nodejs/node/pull/27400) +* [[`230a773e32`](https://github.com/nodejs/node/commit/230a773e32)] - **(SEMVER-MINOR)** **deps**: update archs files for OpenSSL-1.1.1b (Sam Roberts) [#27376](https://github.com/nodejs/node/pull/27376) +* [[`b68132e01a`](https://github.com/nodejs/node/commit/b68132e01a)] - **(SEMVER-MINOR)** **deps**: configure OpenSSL's SSL\_trace to be built (Sam Roberts) [#27376](https://github.com/nodejs/node/pull/27376) +* [[`7c25dce7ba`](https://github.com/nodejs/node/commit/7c25dce7ba)] - **deps**: V8: cherry-pick 5d0cf6b (Joyee Cheung) [#27423](https://github.com/nodejs/node/pull/27423) +* [[`2c3c0d7d3e`](https://github.com/nodejs/node/commit/2c3c0d7d3e)] - **doc**: add cclauss to collaborators (cclauss) [#27554](https://github.com/nodejs/node/pull/27554) +* [[`b51dcf62b8`](https://github.com/nodejs/node/commit/b51dcf62b8)] - **doc**: add Electron 6 to abi\_version\_registry (Jeremy Apthorp) [#27288](https://github.com/nodejs/node/pull/27288) +* [[`cb97de7a9b`](https://github.com/nodejs/node/commit/cb97de7a9b)] - **doc**: move James back onto TSC (Michael Dawson) [#27411](https://github.com/nodejs/node/pull/27411) +* [[`a9748bc124`](https://github.com/nodejs/node/commit/a9748bc124)] - **doc**: describe API ERR\_INVALID\_PROTOCOL context (Sam Roberts) [#27393](https://github.com/nodejs/node/pull/27393) +* [[`a0353fdbe2`](https://github.com/nodejs/node/commit/a0353fdbe2)] - **fs**: align fs.ReadStream buffer pool writes to 8-byte boundary (ptaylor) [#24838](https://github.com/nodejs/node/pull/24838) +* [[`7be1e0af44`](https://github.com/nodejs/node/commit/7be1e0af44)] - **fs**: added tests for util file preprocessSymlinkDestination (Ruwan Geeganage) [#27468](https://github.com/nodejs/node/pull/27468) +* [[`f882c9b09b`](https://github.com/nodejs/node/commit/f882c9b09b)] - **(SEMVER-MINOR)** **http**: `servername === false` should disable SNI (Fedor Indutny) [#27316](https://github.com/nodejs/node/pull/27316) +* [[`de337bb37c`](https://github.com/nodejs/node/commit/de337bb37c)] - **(SEMVER-MINOR)** **inspector**: implement --cpu-prof-interval (Joyee Cheung) [#27535](https://github.com/nodejs/node/pull/27535) +* [[`9c842f4119`](https://github.com/nodejs/node/commit/9c842f4119)] - **lib**: remove Reflect.apply where appropriate (Anatoli Papirovski) [#27349](https://github.com/nodejs/node/pull/27349) +* [[`47d311b3f0`](https://github.com/nodejs/node/commit/47d311b3f0)] - **lib**: remove outdated optimizations (Weijia Wang) [#27380](https://github.com/nodejs/node/pull/27380) +* [[`c2a03d58c3`](https://github.com/nodejs/node/commit/c2a03d58c3)] - **lib**: print to stdout/stderr directly instead of using console (Joyee Cheung) [#27320](https://github.com/nodejs/node/pull/27320) +* [[`b68ecf3e17`](https://github.com/nodejs/node/commit/b68ecf3e17)] - **meta**: move andrasq to Collaborator Emeriti list (Rich Trott) [#27546](https://github.com/nodejs/node/pull/27546) +* [[`fd17f37a83`](https://github.com/nodejs/node/commit/fd17f37a83)] - **meta**: move stefanmb to Collaborator Emeriti list (Rich Trott) [#27502](https://github.com/nodejs/node/pull/27502) +* [[`8495e8bceb`](https://github.com/nodejs/node/commit/8495e8bceb)] - **meta**: move Forrest Norvell to Collaborator Emeriti list (Rich Trott) [#27437](https://github.com/nodejs/node/pull/27437) +* [[`7d1c90b614`](https://github.com/nodejs/node/commit/7d1c90b614)] - **meta**: move @vsemozhetbyt to collaborator emeriti (Vse Mozhet Byt) [#27412](https://github.com/nodejs/node/pull/27412) +* [[`014a9fd46f`](https://github.com/nodejs/node/commit/014a9fd46f)] - **module**: throw on require('./path.mjs'); (Myles Borins) [#27417](https://github.com/nodejs/node/pull/27417) +* [[`5bcd7700ca`](https://github.com/nodejs/node/commit/5bcd7700ca)] - **(SEMVER-MINOR)** **module**: add createRequire method (Myles Borins) [#27405](https://github.com/nodejs/node/pull/27405) +* [[`be9a1ec1d1`](https://github.com/nodejs/node/commit/be9a1ec1d1)] - **module**: allow passing a directory to createRequireFromPath (Gilles De Mey) [#23818](https://github.com/nodejs/node/pull/23818) +* [[`e5fdc30bd1`](https://github.com/nodejs/node/commit/e5fdc30bd1)] - **n-api**: make napi\_get\_property\_names return strings (Anna Henningsen) [#27524](https://github.com/nodejs/node/pull/27524) +* [[`826fb66729`](https://github.com/nodejs/node/commit/826fb66729)] - **process**: compatibility patch to backport 1d022e8 (Ruben Bridgewater) [#27483](https://github.com/nodejs/node/pull/27483) +* [[`91b7f5e103`](https://github.com/nodejs/node/commit/91b7f5e103)] - **process**: improve cwd performance (Ruben Bridgewater) [#27224](https://github.com/nodejs/node/pull/27224) +* [[`05cea679a3`](https://github.com/nodejs/node/commit/05cea679a3)] - **repl**: handle stage-3 language features properly (Ruben Bridgewater) [#27400](https://github.com/nodejs/node/pull/27400) +* [[`01d632d7e8`](https://github.com/nodejs/node/commit/01d632d7e8)] - **repl**: add new language features to top level await statements (Ruben Bridgewater) [#27400](https://github.com/nodejs/node/pull/27400) +* [[`149412ca02`](https://github.com/nodejs/node/commit/149412ca02)] - **repl**: add autocomplete for filesystem modules (Anto Aravinth) [#26648](https://github.com/nodejs/node/pull/26648) +* [[`a55457c713`](https://github.com/nodejs/node/commit/a55457c713)] - **report**: use const reference in node\_report.cc (gengjiawen) [#27479](https://github.com/nodejs/node/pull/27479) +* [[`8724229155`](https://github.com/nodejs/node/commit/8724229155)] - **src**: make deleted function public in node\_native\_module.h (gengjiawen) [#27509](https://github.com/nodejs/node/pull/27509) +* [[`1489d12735`](https://github.com/nodejs/node/commit/1489d12735)] - **src**: make deleted function public in node\_main\_instance.h (gengjiawen) [#27509](https://github.com/nodejs/node/pull/27509) +* [[`294d2ea71d`](https://github.com/nodejs/node/commit/294d2ea71d)] - **(SEMVER-MINOR)** **src**: refactor V8ProfilerConnection::DispatchMessage() (Joyee Cheung) [#27535](https://github.com/nodejs/node/pull/27535) +* [[`a758f9bdf5`](https://github.com/nodejs/node/commit/a758f9bdf5)] - **src**: remove node\_options-inl.h from header files (Sam Roberts) [#27538](https://github.com/nodejs/node/pull/27538) +* [[`bb373d0def`](https://github.com/nodejs/node/commit/bb373d0def)] - **src**: remove unnecessary semicolons after macros (Yang Guo) [#27529](https://github.com/nodejs/node/pull/27529) +* [[`0c9bc02b96`](https://github.com/nodejs/node/commit/0c9bc02b96)] - **src**: refactor V8ProfilerConnection to be more reusable (Joyee Cheung) [#27475](https://github.com/nodejs/node/pull/27475) +* [[`c787bb85cd`](https://github.com/nodejs/node/commit/c787bb85cd)] - **src**: refactor profile initialization (Joyee Cheung) [#27475](https://github.com/nodejs/node/pull/27475) +* [[`600048b1b7`](https://github.com/nodejs/node/commit/600048b1b7)] - **src**: move Environment::context out of strong properties (Joyee Cheung) [#27430](https://github.com/nodejs/node/pull/27430) +* [[`33702913b1`](https://github.com/nodejs/node/commit/33702913b1)] - **src**: prefer v8::Global over node::Persistent (Anna Henningsen) [#27287](https://github.com/nodejs/node/pull/27287) +* [[`9d6d45e7d2`](https://github.com/nodejs/node/commit/9d6d45e7d2)] - **stream**: remove TODO and add a description instead (Ruben Bridgewater) [#27086](https://github.com/nodejs/node/pull/27086) +* [[`bb1eaeec75`](https://github.com/nodejs/node/commit/bb1eaeec75)] - **test**: mark test-tls-enable-trace-cli flaky (cjihrig) [#27559](https://github.com/nodejs/node/pull/27559) +* [[`d648ecc488`](https://github.com/nodejs/node/commit/d648ecc488)] - **test**: improve test-async-hooks-http-parser-destroy (Rich Trott) [#27319](https://github.com/nodejs/node/pull/27319) +* [[`ca720b3a55`](https://github.com/nodejs/node/commit/ca720b3a55)] - **test**: converting NghttpError to string in HTTP2 module (Ruwan Geeganage) [#27506](https://github.com/nodejs/node/pull/27506) +* [[`99e4a576eb`](https://github.com/nodejs/node/commit/99e4a576eb)] - **test**: add mustCall to openssl-client-cert-engine (Boxuan Li) [#27474](https://github.com/nodejs/node/pull/27474) +* [[`e1d88aa880`](https://github.com/nodejs/node/commit/e1d88aa880)] - **test**: document NODE\_COMMON\_PORT env var (cjihrig) [#27507](https://github.com/nodejs/node/pull/27507) +* [[`66cf706521`](https://github.com/nodejs/node/commit/66cf706521)] - **test**: allow EAI\_FAIL in test-http-dns-error.js (cjihrig) [#27500](https://github.com/nodejs/node/pull/27500) +* [[`df4246e3b6`](https://github.com/nodejs/node/commit/df4246e3b6)] - **test**: refactor and deflake test-tls-sni-server-client (Luigi Pinca) [#27426](https://github.com/nodejs/node/pull/27426) +* [[`a278814818`](https://github.com/nodejs/node/commit/a278814818)] - **test**: make sure weak references are not GCed too early (Ruben Bridgewater) [#27482](https://github.com/nodejs/node/pull/27482) +* [[`aa281d284a`](https://github.com/nodejs/node/commit/aa281d284a)] - **test**: better output for test-report-uv-handles.js (gengjiawen) [#27479](https://github.com/nodejs/node/pull/27479) +* [[`86c27c6005`](https://github.com/nodejs/node/commit/86c27c6005)] - **test**: add mustcall in test-net-bytes-read.js (imhype) [#27471](https://github.com/nodejs/node/pull/27471) +* [[`33fead3f5e`](https://github.com/nodejs/node/commit/33fead3f5e)] - ***Revert*** "**test**: skip test-cpu-prof in debug builds with code cache" (Anna Henningsen) [#27469](https://github.com/nodejs/node/pull/27469) +* [[`a9a85d6271`](https://github.com/nodejs/node/commit/a9a85d6271)] - **test**: check `napi\_get\_reference\_value()` during finalization (Anna Henningsen) [#27470](https://github.com/nodejs/node/pull/27470) +* [[`16af9435a0`](https://github.com/nodejs/node/commit/16af9435a0)] - **test**: remove flaky designation for test-tls-sni-option (Luigi Pinca) [#27425](https://github.com/nodejs/node/pull/27425) +* [[`1b94d025bc`](https://github.com/nodejs/node/commit/1b94d025bc)] - **test**: add missing line breaks to keep-alive header of slow headers test (Shuhei Kagawa) [#27442](https://github.com/nodejs/node/pull/27442) +* [[`fefbbd90af`](https://github.com/nodejs/node/commit/fefbbd90af)] - **test**: add tests for new language features (Ruben Bridgewater) [#27400](https://github.com/nodejs/node/pull/27400) +* [[`3711684ccf`](https://github.com/nodejs/node/commit/3711684ccf)] - **test**: add mustCall for parallel/test-net-connect-paused-connection (sujunfei) [#27463](https://github.com/nodejs/node/pull/27463) +* [[`0e4f8788eb`](https://github.com/nodejs/node/commit/0e4f8788eb)] - **test**: add mustCallAtLeast to test-fs-read-stream-resume.js (heben) [#27456](https://github.com/nodejs/node/pull/27456) +* [[`e89b6fee3a`](https://github.com/nodejs/node/commit/e89b6fee3a)] - **test**: adding mustCall in test-fs-readfile-empty.js (陈健) [#27455](https://github.com/nodejs/node/pull/27455) +* [[`457549b67d`](https://github.com/nodejs/node/commit/457549b67d)] - **test**: add common.mustCall in test-http-abort-client.js (OneNail) [#27449](https://github.com/nodejs/node/pull/27449) +* [[`f4124d5ba5`](https://github.com/nodejs/node/commit/f4124d5ba5)] - **test**: add mustCall to http-abort-queued test (Yaphet Ye) [#27447](https://github.com/nodejs/node/pull/27447) +* [[`e21f035666`](https://github.com/nodejs/node/commit/e21f035666)] - **test**: add mustCall in test-fs-readfilesync-pipe-large.js (sinoon) [#27458](https://github.com/nodejs/node/pull/27458) +* [[`1dd0205f10`](https://github.com/nodejs/node/commit/1dd0205f10)] - **test**: add mustCall to test-dgram-connect-send-multi-buffer-copy.js (XGHeaven) [#27465](https://github.com/nodejs/node/pull/27465) +* [[`0dfe5bebb2`](https://github.com/nodejs/node/commit/0dfe5bebb2)] - **test**: add test of policy about parse error (Daiki Ihara) [#26873](https://github.com/nodejs/node/pull/26873) +* [[`eeab007b25`](https://github.com/nodejs/node/commit/eeab007b25)] - **test**: add mustCall to test-net-after-close test (xuqinggang) [#27459](https://github.com/nodejs/node/pull/27459) +* [[`c1b04652f5`](https://github.com/nodejs/node/commit/c1b04652f5)] - **test**: add "mustCall" to test-fs-readfile-unlink (wuchenkai) [#27453](https://github.com/nodejs/node/pull/27453) +* [[`b6c65c1351`](https://github.com/nodejs/node/commit/b6c65c1351)] - **test**: add missing ToC entries (cjihrig) [#27434](https://github.com/nodejs/node/pull/27434) +* [[`66bff5071f`](https://github.com/nodejs/node/commit/66bff5071f)] - **test**: document report helper module (cjihrig) [#27434](https://github.com/nodejs/node/pull/27434) +* [[`2c335928cd`](https://github.com/nodejs/node/commit/2c335928cd)] - **test**: document NODE\_SKIP\_FLAG\_CHECK (cjihrig) [#27434](https://github.com/nodejs/node/pull/27434) +* [[`115d06cdbb`](https://github.com/nodejs/node/commit/115d06cdbb)] - **test**: document NODE\_TEST\_KNOWN\_GLOBALS (cjihrig) [#27434](https://github.com/nodejs/node/pull/27434) +* [[`51fc672da9`](https://github.com/nodejs/node/commit/51fc672da9)] - **test**: add mustCallAtLeast to test-fs-read-stream-inherit (nilianzhu) [#27457](https://github.com/nodejs/node/pull/27457) +* [[`4b9d109518`](https://github.com/nodejs/node/commit/4b9d109518)] - **test**: add mustCall to test-dgram-implicit-bind.js (Chenxi Yuan) [#27452](https://github.com/nodejs/node/pull/27452) +* [[`c4d67f2af5`](https://github.com/nodejs/node/commit/c4d67f2af5)] - **test**: add common.mustCall test-dgram-listen-after-bind (zhoujiamin) [#27454](https://github.com/nodejs/node/pull/27454) +* [[`23fb430e03`](https://github.com/nodejs/node/commit/23fb430e03)] - **test**: add mustCall to test-dgram-connect-send-callback-buffer (shenchen) [#27466](https://github.com/nodejs/node/pull/27466) +* [[`a37ca245ff`](https://github.com/nodejs/node/commit/a37ca245ff)] - **test**: add mustCallAtLeast to test-fs-read-stream-fd test (hardfist) [#27461](https://github.com/nodejs/node/pull/27461) +* [[`cf84f20453`](https://github.com/nodejs/node/commit/cf84f20453)] - **test**: skip fs-copyfile-respect-permission if root (Daniel Bevenius) [#27378](https://github.com/nodejs/node/pull/27378) +* [[`7d80999454`](https://github.com/nodejs/node/commit/7d80999454)] - **test**: add mustCall to net-can-reset-timeout (xinyulee) [#27462](https://github.com/nodejs/node/pull/27462) +* [[`9fa5ba8b3c`](https://github.com/nodejs/node/commit/9fa5ba8b3c)] - **test**: add mustCall to test-fs-readfile-pipe-large (luoyu) [#27460](https://github.com/nodejs/node/pull/27460) +* [[`e8d5b6226a`](https://github.com/nodejs/node/commit/e8d5b6226a)] - **test**: add "mustCall" for test-net-buffersize (lixin.atom) [#27451](https://github.com/nodejs/node/pull/27451) +* [[`d784ecb1ad`](https://github.com/nodejs/node/commit/d784ecb1ad)] - **test**: add mustCall to test-net-eaddrinuse test (tongshouyu) [#27448](https://github.com/nodejs/node/pull/27448) +* [[`6fd1384a43`](https://github.com/nodejs/node/commit/6fd1384a43)] - **test**: add mustcall in test-dgram-connect-send-callback-buffer-length (jyjunyz) [#27464](https://github.com/nodejs/node/pull/27464) +* [[`7a35077197`](https://github.com/nodejs/node/commit/7a35077197)] - **test**: add mustCall to test-fs-readfile-pipe (tonyhty) [#27450](https://github.com/nodejs/node/pull/27450) +* [[`af29ae0344`](https://github.com/nodejs/node/commit/af29ae0344)] - **test**: add mustCall to net-connect-buffer test (Rongjian Zhang) [#27446](https://github.com/nodejs/node/pull/27446) +* [[`bdabf699eb`](https://github.com/nodejs/node/commit/bdabf699eb)] - **(SEMVER-MINOR)** **tls**: add --tls-min-v1.2 CLI switch (Sam Roberts) [#27520](https://github.com/nodejs/node/pull/27520) +* [[`7bbf951095`](https://github.com/nodejs/node/commit/7bbf951095)] - **tls**: disallow conflicting TLS protocol options (Sam Roberts) [#27521](https://github.com/nodejs/node/pull/27521) +* [[`84a2768c25`](https://github.com/nodejs/node/commit/84a2768c25)] - **(SEMVER-MINOR)** **tls**: support enableTrace in TLSSocket() (cjihrig) [#27497](https://github.com/nodejs/node/pull/27497) +* [[`576fe339a1`](https://github.com/nodejs/node/commit/576fe339a1)] - **(SEMVER-MINOR)** **tls**: simplify enableTrace logic (cjihrig) [#27497](https://github.com/nodejs/node/pull/27497) +* [[`30a72e8c7b`](https://github.com/nodejs/node/commit/30a72e8c7b)] - **(SEMVER-MINOR)** **tls**: allow enabling the TLS debug trace (Sam Roberts) [#27376](https://github.com/nodejs/node/pull/27376) +* [[`f1efe6dae0`](https://github.com/nodejs/node/commit/f1efe6dae0)] - **(SEMVER-MINOR)** **tls,cli**: add --trace-tls command-line flag (cjihrig) [#27497](https://github.com/nodejs/node/pull/27497) +* [[`3d37414002`](https://github.com/nodejs/node/commit/3d37414002)] - **tools**: fix node-core/required-modules eslint rule (Ben Noordhuis) [#27545](https://github.com/nodejs/node/pull/27545) +* [[`29e2793a87`](https://github.com/nodejs/node/commit/29e2793a87)] - **tools**: add Release and Debug symlinks to .gitignore (Gerhard Stoebich) [#27484](https://github.com/nodejs/node/pull/27484) +* [[`76af4f0d05`](https://github.com/nodejs/node/commit/76af4f0d05)] - **tools**: prohibit `assert.doesNotReject()` in Node.js core (Ruben Bridgewater) [#27402](https://github.com/nodejs/node/pull/27402) +* [[`95498df1cf`](https://github.com/nodejs/node/commit/95498df1cf)] - **util**: inspect constructor closer (Ruben Bridgewater) [#27522](https://github.com/nodejs/node/pull/27522) +* [[`7b5bd93ced`](https://github.com/nodejs/node/commit/7b5bd93ced)] - **util**: compatibility patch to backport d0667e8 (Ruben Bridgewater) [#27570](https://github.com/nodejs/node/pull/27570) +* [[`52d4f1febf`](https://github.com/nodejs/node/commit/52d4f1febf)] - **util**: improve function inspection (Ruben Bridgewater) [#27227](https://github.com/nodejs/node/pull/27227) +* [[`caab7d4664`](https://github.com/nodejs/node/commit/caab7d4664)] - **util**: better number formatters (Ruben Bridgewater) [#27499](https://github.com/nodejs/node/pull/27499) + ## 2019-04-29, Version 12.1.0 (Current), @targos diff --git a/doc/node.1 b/doc/node.1 index 1fa5ce7f650e99..ab715c0c1bfca2 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -90,6 +90,12 @@ The directory where the CPU profiles generated by .Fl -cpu-prof will be placed. . +.It Fl -cpu-prof-interval +The sampling interval in microseconds for the CPU profiles generated by +.Fl -cpu-prof . +The default is +.Sy 1000 . +. .It Fl -cpu-prof-name File name of the V8 CPU profile generated with .Fl -cpu-prof @@ -278,6 +284,10 @@ or servers. Set default minVersion to 'TLSv1.1'. Use for compatibility with old TLS clients or servers. . +.It Fl -tls-min-v1.2 +Set default minVersion to 'TLSv1.2'. This is the default for 12.x and later, +but the option is supported for compatibility with older Node.js versions. +. .It Fl -tls-min-v1.3 Set default minVersion to 'TLSv1.3'. Use to disable support for TLSv1.2 in favour of TLSv1.3, which is more secure. @@ -302,6 +312,9 @@ Enable the collection of trace event tracing information. .It Fl -trace-sync-io Print a stack trace whenever synchronous I/O is detected after the first turn of the event loop. . +.It Fl -trace-tls +Prints TLS packet trace information to stderr. +. .It Fl -trace-warnings Print stack traces for process warnings (including deprecations). . diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 32dbf27abc0dff..eb98f2b0bd1ca4 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -151,7 +151,7 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */, if (options.socketPath) options.path = options.socketPath; - if (!options.servername) + if (!options.servername && options.servername !== '') options.servername = calculateServerName(options, req); const name = this.getName(options); @@ -198,7 +198,7 @@ Agent.prototype.createSocket = function createSocket(req, options, cb) { if (options.socketPath) options.path = options.socketPath; - if (!options.servername) + if (!options.servername && options.servername !== '') options.servername = calculateServerName(options, req); const name = this.getName(options); diff --git a/lib/_http_client.js b/lib/_http_client.js index 895e0bd6009dae..75c86acf2c510c 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -64,6 +64,13 @@ function validateHost(host, name) { return host; } +class HTTPClientAsyncResource { + constructor(type, req) { + this.type = type; + this.req = req; + } +} + let urlWarningEmitted = false; function ClientRequest(input, options, cb) { OutgoingMessage.call(this); @@ -635,7 +642,8 @@ function tickOnSocket(req, socket) { const parser = parsers.alloc(); req.socket = socket; req.connection = socket; - parser.initialize(HTTPParser.RESPONSE, req); + parser.initialize(HTTPParser.RESPONSE, + new HTTPClientAsyncResource('HTTPINCOMINGMESSAGE', req)); parser.socket = socket; parser.outgoing = req; req.parser = parser; diff --git a/lib/_http_common.js b/lib/_http_common.js index 7772ec69314ada..75995260128862 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -156,7 +156,7 @@ function parserOnMessageComplete() { const parsers = new FreeList('parsers', 1000, function parsersCb() { - const parser = new HTTPParser(HTTPParser.REQUEST); + const parser = new HTTPParser(); cleanParser(parser); diff --git a/lib/_stream_transform.js b/lib/_stream_transform.js index ab6ada8dec0a4f..b4fffaa98891cd 100644 --- a/lib/_stream_transform.js +++ b/lib/_stream_transform.js @@ -209,9 +209,7 @@ function done(stream, er, data) { if (data != null) // Single equals check for both `null` and `undefined` stream.push(data); - // TODO(BridgeAR): Write a test for these two error cases - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided + // These two error cases are coherence checks that can likely not be tested. if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0(); diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 0b844e6a827432..a04f0014c76b90 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -56,17 +56,21 @@ const { ERR_TLS_SESSION_ATTACK, ERR_TLS_SNI_FROM_SERVER } = require('internal/errors').codes; +const { getOptionValue } = require('internal/options'); const { validateString } = require('internal/validators'); +const traceTls = getOptionValue('--trace-tls'); const kConnectOptions = Symbol('connect-options'); const kDisableRenegotiation = Symbol('disable-renegotiation'); const kErrorEmitted = Symbol('error-emitted'); const kHandshakeTimeout = Symbol('handshake-timeout'); const kRes = Symbol('res'); const kSNICallback = Symbol('snicallback'); +const kEnableTrace = Symbol('enableTrace'); const noop = () => {}; let ipServernameWarned = false; +let tlsTracingWarned = false; // Server side times how long a handshake is taking to protect against slow // handshakes being used for DoS. @@ -342,6 +346,20 @@ function initRead(tlsSocket, socket) { function TLSSocket(socket, opts) { const tlsOptions = { ...opts }; + let enableTrace = tlsOptions.enableTrace; + + if (enableTrace == null) { + enableTrace = traceTls; + + if (enableTrace && !tlsTracingWarned) { + tlsTracingWarned = true; + process.emitWarning('Enabling --trace-tls can expose sensitive data in ' + + 'the resulting log.'); + } + } else if (typeof enableTrace !== 'boolean') { + throw new ERR_INVALID_ARG_TYPE( + 'options.enableTrace', 'boolean', enableTrace); + } if (tlsOptions.ALPNProtocols) tls.convertALPNProtocols(tlsOptions.ALPNProtocols, tlsOptions); @@ -396,6 +414,9 @@ function TLSSocket(socket, opts) { this.readable = true; this.writable = true; + if (enableTrace && this._handle) + this._handle.enableTrace(); + // Read on next tick so the caller has a chance to setup listeners process.nextTick(initRead, this, socket); } @@ -811,6 +832,7 @@ function makeSocketMethodProxy(name) { 'getSession', 'getTLSTicket', 'isSessionReused', + 'enableTrace', ].forEach((method) => { TLSSocket.prototype[method] = makeSocketMethodProxy(method); }); @@ -870,7 +892,8 @@ function tlsConnectionListener(rawSocket) { rejectUnauthorized: this.rejectUnauthorized, handshakeTimeout: this[kHandshakeTimeout], ALPNProtocols: this.ALPNProtocols, - SNICallback: this[kSNICallback] || SNICallback + SNICallback: this[kSNICallback] || SNICallback, + enableTrace: this[kEnableTrace] }); socket.on('secure', onServerSocketSecure); @@ -992,6 +1015,8 @@ function Server(options, listener) { if (listener) { this.on('secureConnection', listener); } + + this[kEnableTrace] = options.enableTrace; } Object.setPrototypeOf(Server.prototype, net.Server.prototype); @@ -1352,7 +1377,8 @@ exports.connect = function connect(...args) { rejectUnauthorized: options.rejectUnauthorized !== false, session: options.session, ALPNProtocols: options.ALPNProtocols, - requestOCSP: options.requestOCSP + requestOCSP: options.requestOCSP, + enableTrace: options.enableTrace }); tlssock[kConnectOptions] = options; diff --git a/lib/assert.js b/lib/assert.js index 376f4b732001bc..ffa71bfad8d412 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -203,8 +203,27 @@ function getCode(fd, line, column) { function parseCode(code, offset) { // Lazy load acorn. if (parseExpressionAt === undefined) { - ({ parseExpressionAt } = require('internal/deps/acorn/acorn/dist/acorn')); + const acorn = require('internal/deps/acorn/acorn/dist/acorn'); + const privateMethods = + require('internal/deps/acorn-plugins/acorn-private-methods/index'); + const bigInt = require('internal/deps/acorn-plugins/acorn-bigint/index'); + const classFields = + require('internal/deps/acorn-plugins/acorn-class-fields/index'); + const numericSeparator = + require('internal/deps/acorn-plugins/acorn-numeric-separator/index'); + const staticClassFeatures = + require('internal/deps/acorn-plugins/acorn-static-class-features/index'); + ({ findNodeAround } = require('internal/deps/acorn/acorn-walk/dist/walk')); + + const Parser = acorn.Parser.extend( + privateMethods, + bigInt, + classFields, + numericSeparator, + staticClassFeatures + ); + parseExpressionAt = Parser.parseExpressionAt.bind(Parser); } let node; let start = 0; diff --git a/lib/buffer.js b/lib/buffer.js index 1fac94d568ffae..8c16f07acebc5b 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -894,11 +894,7 @@ Buffer.prototype.write = function write(string, offset, length, encoding) { // Buffer#write(string, offset[, length][, encoding]) } else { - if (offset === undefined) { - offset = 0; - } else { - validateInt32(offset, 'offset', 0, this.length); - } + validateInt32(offset, 'offset', 0, this.length); const remaining = this.length - offset; diff --git a/lib/fs.js b/lib/fs.js index 38c13613cb352a..1b8ad7636edc4a 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -24,7 +24,7 @@ 'use strict'; -const { Math, Object, Reflect } = primordials; +const { Math, Object } = primordials; const { fs: constants } = internalBinding('constants'); const { @@ -74,7 +74,8 @@ const { validateOffsetLengthRead, validateOffsetLengthWrite, validatePath, - warnOnNonPortableTemplate + warnOnNonPortableTemplate, + handleErrorFromBinding } = require('internal/fs/utils'); const { CHAR_FORWARD_SLASH, @@ -117,23 +118,6 @@ function showTruncateDeprecation() { } } -function handleErrorFromBinding(ctx) { - if (ctx.errno !== undefined) { // libuv error numbers - const err = uvException(ctx); - // eslint-disable-next-line no-restricted-syntax - Error.captureStackTrace(err, handleErrorFromBinding); - throw err; - } - if (ctx.error !== undefined) { // Errors created in C++ land. - // TODO(joyeecheung): currently, ctx.error are encoding errors - // usually caused by memory problems. We need to figure out proper error - // code(s) for this. - // eslint-disable-next-line no-restricted-syntax - Error.captureStackTrace(ctx.error, handleErrorFromBinding); - throw ctx.error; - } -} - function maybeCallback(cb) { if (typeof cb === 'function') return cb; @@ -149,9 +133,7 @@ function makeCallback(cb) { throw new ERR_INVALID_CALLBACK(cb); } - return (...args) => { - return Reflect.apply(cb, undefined, args); - }; + return (...args) => cb(...args); } // Special case of `makeCallback()` that is specific to async `*stat()` calls as diff --git a/lib/internal/async_hooks.js b/lib/internal/async_hooks.js index cba8d15a6cb06a..64f5cb2462f6ba 100644 --- a/lib/internal/async_hooks.js +++ b/lib/internal/async_hooks.js @@ -1,6 +1,6 @@ 'use strict'; -const { FunctionPrototype, Object, Reflect } = primordials; +const { FunctionPrototype, Object } = primordials; const { ERR_ASYNC_TYPE, @@ -278,14 +278,14 @@ function clearDefaultTriggerAsyncId() { function defaultTriggerAsyncIdScope(triggerAsyncId, block, ...args) { if (triggerAsyncId === undefined) - return Reflect.apply(block, null, args); + return block(...args); // CHECK(Number.isSafeInteger(triggerAsyncId)) // CHECK(triggerAsyncId > 0) const oldDefaultTriggerAsyncId = async_id_fields[kDefaultTriggerAsyncId]; async_id_fields[kDefaultTriggerAsyncId] = triggerAsyncId; try { - return Reflect.apply(block, null, args); + return block(...args); } finally { async_id_fields[kDefaultTriggerAsyncId] = oldDefaultTriggerAsyncId; } diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index f00e1c2fbd400c..321bfabe027d65 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -73,6 +73,7 @@ if (isMainThread) { const wrapped = mainThreadSetup.wrapProcessMethods(rawMethods); process.umask = wrapped.umask; process.chdir = wrapped.chdir; + process.cwd = wrapped.cwd; // TODO(joyeecheung): deprecate and remove these underscore methods process._debugProcess = rawMethods._debugProcess; @@ -86,11 +87,11 @@ if (isMainThread) { process.abort = workerThreadSetup.unavailable('process.abort()'); process.chdir = workerThreadSetup.unavailable('process.chdir()'); process.umask = wrapped.umask; + process.cwd = rawMethods.cwd; } // Set up methods on the process object for all threads { - process.cwd = rawMethods.cwd; process.dlopen = rawMethods.dlopen; process.uptime = rawMethods.uptime; diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index 9a70dd4c89e26d..aaaf2ca25f7c14 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -43,7 +43,20 @@ function checkBounds(buf, offset, byteLength) { function checkInt(value, min, max, buf, offset, byteLength) { if (value > max || value < min) { - throw new ERR_OUT_OF_RANGE('value', `>= ${min} and <= ${max}`, value); + // eslint-disable-next-line valid-typeof + const n = typeof min === 'bigint' ? 'n' : ''; + let range; + if (byteLength > 3) { + if (min === 0 || min === 0n) { + range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`; + } else { + range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and < 2 ** ` + + `${(byteLength + 1) * 8 - 1}${n}`; + } + } else { + range = `>= ${min}${n} and <= ${max}${n}`; + } + throw new ERR_OUT_OF_RANGE('value', range, value); } checkBounds(buf, offset, byteLength); } diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 8e6a303a2e27a5..03c0ed9159f64a 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -63,6 +63,7 @@ let freeParser; let HTTPParser; const MAX_HANDLE_RETRANSMISSIONS = 3; +const kIsUsedAsStdio = Symbol('kIsUsedAsStdio'); // This object contain function to convert TCP objects to native handle objects // and back again. @@ -278,8 +279,14 @@ function flushStdio(subprocess) { for (var i = 0; i < stdio.length; i++) { const stream = stdio[i]; - if (!stream || !stream.readable || stream._readableState.readableListening) + // TODO(addaleax): This doesn't necessarily account for all the ways in + // which data can be read from a stream, e.g. being consumed on the + // native layer directly as a StreamBase. + if (!stream || !stream.readable || + stream._readableState.readableListening || + stream[kIsUsedAsStdio]) { continue; + } stream.resume(); } } @@ -384,12 +391,16 @@ ChildProcess.prototype.spawn = function(options) { continue; } - // The stream is already cloned and piped, thus close it. + // The stream is already cloned and piped, thus stop its readable side, + // otherwise we might attempt to read from the stream when at the same time + // the child process does. if (stream.type === 'wrap') { - stream.handle.close(); - if (stream._stdio && stream._stdio instanceof EventEmitter) { - stream._stdio.emit('close'); - } + stream.handle.reading = false; + stream.handle.readStop(); + stream._stdio.pause(); + stream._stdio.readableFlowing = false; + stream._stdio._readableState.reading = false; + stream._stdio[kIsUsedAsStdio] = true; continue; } diff --git a/lib/internal/console/constructor.js b/lib/internal/console/constructor.js index f1f3c725eca25a..04b6087b77f780 100644 --- a/lib/internal/console/constructor.js +++ b/lib/internal/console/constructor.js @@ -177,15 +177,13 @@ Console.prototype[kBindProperties] = function(ignoreErrors, colorMode) { ...consolePropAttributes, value: Boolean(ignoreErrors) }, - '_times': { ...consolePropAttributes, value: new Map() } + '_times': { ...consolePropAttributes, value: new Map() }, + // Corresponds to https://console.spec.whatwg.org/#count-map + [kCounts]: { ...consolePropAttributes, value: new Map() }, + [kColorMode]: { ...consolePropAttributes, value: colorMode }, + [kIsConsole]: { ...consolePropAttributes, value: true }, + [kGroupIndent]: { ...consolePropAttributes, value: '' } }); - - // TODO(joyeecheung): use consolePropAttributes for these - // Corresponds to https://console.spec.whatwg.org/#count-map - this[kCounts] = new Map(); - this[kColorMode] = colorMode; - this[kIsConsole] = true; - this[kGroupIndent] = ''; }; // Make a function that can serve as the callback passed to `stream.write()`. diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 2cdf40e2092933..51e9fcba400ce8 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -10,7 +10,7 @@ // value statically and permanently identifies the error. While the error // message may change, the code should not. -const { Object } = primordials; +const { Object, Math } = primordials; const kCode = Symbol('code'); const kInfo = Symbol('info'); @@ -574,6 +574,17 @@ function oneOf(expected, thing) { } } +// Only use this for integers! Decimal numbers do not work with this function. +function addNumericalSeparator(val) { + let res = ''; + let i = val.length; + const start = val[0] === '-' ? 1 : 0; + for (; i >= start + 4; i -= 3) { + res = `_${val.slice(i - 3, i)}${res}`; + } + return `${val.slice(0, i)}${res}`; +} + module.exports = { addCodeToName, // Exported for NghttpError codes, @@ -990,7 +1001,20 @@ E('ERR_OUT_OF_RANGE', assert(range, 'Missing "range" argument'); let msg = replaceDefaultBoolean ? str : `The value of "${str}" is out of range.`; - msg += ` It must be ${range}. Received ${input}`; + let received; + if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) { + received = addNumericalSeparator(String(input)); + // eslint-disable-next-line valid-typeof + } else if (typeof input === 'bigint') { + received = String(input); + if (input > 2n ** 32n || input < -(2n ** 32n)) { + received = addNumericalSeparator(received); + } + received += 'n'; + } else { + received = lazyInternalUtilInspect().inspect(input); + } + msg += ` It must be ${range}. Received ${received}`; return msg; }, RangeError); E('ERR_REQUIRE_ESM', 'Must use import to load ES Module: %s', Error); diff --git a/lib/internal/fs/streams.js b/lib/internal/fs/streams.js index 97a8856797ac52..dfff08dbbd1d2a 100644 --- a/lib/internal/fs/streams.js +++ b/lib/internal/fs/streams.js @@ -51,6 +51,10 @@ function checkPosition(pos, name) { } } +function roundUpToMultipleOf8(n) { + return (n + 7) & ~7; // Align to 8 byte boundary. +} + function ReadStream(path, options) { if (!(this instanceof ReadStream)) return new ReadStream(path, options); @@ -172,10 +176,18 @@ ReadStream.prototype._read = function(n) { // Now that we know how much data we have actually read, re-wind the // 'used' field if we can, and otherwise allow the remainder of our // reservation to be used as a new pool later. - if (start + toRead === thisPool.used && thisPool === pool) - thisPool.used += bytesRead - toRead; - else if (toRead - bytesRead > kMinPoolSpace) - poolFragments.push(thisPool.slice(start + bytesRead, start + toRead)); + if (start + toRead === thisPool.used && thisPool === pool) { + const newUsed = thisPool.used + bytesRead - toRead; + thisPool.used = roundUpToMultipleOf8(newUsed); + } else { + // Round down to the next lowest multiple of 8 to ensure the new pool + // fragment start and end positions are aligned to an 8 byte boundary. + const alignedEnd = (start + toRead) & ~7; + const alignedStart = roundUpToMultipleOf8(start + bytesRead); + if (alignedEnd - alignedStart >= kMinPoolSpace) { + poolFragments.push(thisPool.slice(alignedStart, alignedEnd)); + } + } if (bytesRead > 0) { this.bytesRead += bytesRead; @@ -189,7 +201,8 @@ ReadStream.prototype._read = function(n) { // Move the pool positions, and internal position for reading. if (this.pos !== undefined) this.pos += toRead; - pool.used += toRead; + + pool.used = roundUpToMultipleOf8(pool.used + toRead); }; ReadStream.prototype._destroy = function(err, cb) { diff --git a/lib/internal/fs/utils.js b/lib/internal/fs/utils.js index ca8328f553d283..dde78654e0f992 100644 --- a/lib/internal/fs/utils.js +++ b/lib/internal/fs/utils.js @@ -12,7 +12,8 @@ const { ERR_INVALID_OPT_VALUE_ENCODING, ERR_OUT_OF_RANGE }, - hideStackFrames + hideStackFrames, + uvException } = require('internal/errors'); const { isUint8Array, @@ -444,7 +445,26 @@ function warnOnNonPortableTemplate(template) { } } +// This handles errors following the convention of the fs binding. +function handleErrorFromBinding(ctx) { + if (ctx.errno !== undefined) { // libuv error numbers + const err = uvException(ctx); + // eslint-disable-next-line no-restricted-syntax + Error.captureStackTrace(err, handleErrorFromBinding); + throw err; + } + if (ctx.error !== undefined) { // Errors created in C++ land. + // TODO(joyeecheung): currently, ctx.error are encoding errors + // usually caused by memory problems. We need to figure out proper error + // code(s) for this. + // eslint-disable-next-line no-restricted-syntax + Error.captureStackTrace(ctx.error, handleErrorFromBinding); + throw ctx.error; + } +} + module.exports = { + handleErrorFromBinding, assertEncoding, copyObject, Dirent, diff --git a/lib/internal/main/repl.js b/lib/internal/main/repl.js index 980893f9c34e20..58afb2be9879fa 100644 --- a/lib/internal/main/repl.js +++ b/lib/internal/main/repl.js @@ -11,7 +11,7 @@ const { evalScript } = require('internal/process/execution'); -const console = require('internal/console/global'); +const { print, kStderr, kStdout } = require('internal/util/print'); const { getOptionValue } = require('internal/options'); @@ -21,14 +21,12 @@ markBootstrapComplete(); // --input-type flag not supported in REPL if (getOptionValue('--input-type')) { - // If we can't write to stderr, we'd like to make this a noop, - // so use console.error. - console.error('Cannot specify --input-type for REPL'); + print(kStderr, 'Cannot specify --input-type for REPL'); process.exit(1); } -console.log(`Welcome to Node.js ${process.version}.\n` + - 'Type ".help" for more information.'); +print(kStdout, `Welcome to Node.js ${process.version}.\n` + + 'Type ".help" for more information.'); const cliRepl = require('internal/repl'); cliRepl.createInternalRepl(process.env, (err, repl) => { diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js index 46152f6742e5d3..565cd4a77a15c9 100644 --- a/lib/internal/main/worker_thread.js +++ b/lib/internal/main/worker_thread.js @@ -25,6 +25,7 @@ const { getEnvMessagePort } = internalBinding('worker'); +const workerIo = require('internal/worker/io'); const { messageTypes: { // Messages that may be received by workers @@ -38,7 +39,7 @@ const { STDIO_WANTS_MORE_DATA, }, kStdioWantsMoreDataCallback -} = require('internal/worker/io'); +} = workerIo; const { fatalException: originalFatalException @@ -89,6 +90,7 @@ if (process.env.NODE_CHANNEL_FD) { port.on('message', (message) => { if (message.type === LOAD_SCRIPT) { const { + cwdCounter, filename, doEval, workerData, @@ -111,6 +113,17 @@ port.on('message', (message) => { publicWorker.parentPort = publicPort; publicWorker.workerData = workerData; + // The counter is only passed to the workers created by the main thread, not + // to workers created by other workers. + let cachedCwd = ''; + const originalCwd = process.cwd; + + process.cwd = function() { + cachedCwd = originalCwd(); + return cachedCwd; + }; + workerIo.sharedCwdCounter = cwdCounter; + if (!hasStdin) process.stdin.push(null); diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 96b5e8b7b881b6..91b89860e7b66d 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -24,7 +24,7 @@ const { JSON, Object, Reflect } = primordials; const { NativeModule } = require('internal/bootstrap/loaders'); -const { pathToFileURL } = require('internal/url'); +const { pathToFileURL, fileURLToPath, URL } = require('internal/url'); const { deprecate } = require('internal/util'); const vm = require('vm'); const assert = require('internal/assert'); @@ -800,11 +800,9 @@ Module._extensions['.node'] = function(module, filename) { return process.dlopen(module, path.toNamespacedPath(filename)); }; -if (experimentalModules) { - Module._extensions['.mjs'] = function(module, filename) { - throw new ERR_REQUIRE_ESM(filename); - }; -} +Module._extensions['.mjs'] = function(module, filename) { + throw new ERR_REQUIRE_ESM(filename); +}; // Bootstrap main module. Module.runMain = function() { @@ -824,12 +822,48 @@ Module.runMain = function() { Module._load(process.argv[1], null, true); }; -Module.createRequireFromPath = (filename) => { - const m = new Module(filename); - m.filename = filename; - m.paths = Module._nodeModulePaths(path.dirname(filename)); +function createRequireFromPath(filename) { + // Allow a directory to be passed as the filename + const trailingSlash = + filename.endsWith(path.sep) || path.sep !== '/' && filename.endsWith('\\'); + + const proxyPath = trailingSlash ? + path.join(filename, 'noop.js') : + filename; + + const m = new Module(proxyPath); + m.filename = proxyPath; + + m.paths = Module._nodeModulePaths(m.path); return makeRequireFunction(m); -}; +} + +Module.createRequireFromPath = createRequireFromPath; + +const createRequireError = 'must be a file URL object, file URL string, or' + + 'absolute path string'; + +function createRequire(filename) { + let filepath; + if (typeof filename === 'object' && !(filename instanceof URL)) { + throw new ERR_INVALID_ARG_VALUE('filename', filename, createRequireError); + } else if (typeof filename === 'object' || + typeof filename === 'string' && !path.isAbsolute(filename)) { + try { + filepath = fileURLToPath(filename); + } catch { + throw new ERR_INVALID_ARG_VALUE('filename', filename, + createRequireError); + } + } else if (typeof filename !== 'string') { + throw new ERR_INVALID_ARG_VALUE('filename', filename, createRequireError); + } else { + filepath = filename; + } + return createRequireFromPath(filepath); +} + +Module.createRequire = createRequire; Module._initPaths = function() { var homeDir; diff --git a/lib/internal/process/execution.js b/lib/internal/process/execution.js index 19866d17226982..c95567c506237f 100644 --- a/lib/internal/process/execution.js +++ b/lib/internal/process/execution.js @@ -35,24 +35,22 @@ function tryGetCwd() { } } -function evalModule(source, print) { - const { log, error } = require('internal/console/global'); +function evalModule(source, printResult) { const { decorateErrorStack } = require('internal/util'); const asyncESM = require('internal/process/esm_loader'); + const { kStdout, kStderr, print } = require('internal/util/print'); asyncESM.loaderPromise.then(async (loader) => { const { result } = await loader.eval(source); - if (print) { - log(result); - } + if (printResult) { print(kStdout, result); } }) .catch((e) => { decorateErrorStack(e); - error(e); + print(kStderr, e); process.exit(1); }); } -function evalScript(name, body, breakFirstLine, print) { +function evalScript(name, body, breakFirstLine, printResult) { const CJSModule = require('internal/modules/cjs/loader'); const { kVmBreakFirstLineSymbol } = require('internal/util'); @@ -77,9 +75,9 @@ function evalScript(name, body, breakFirstLine, print) { [kVmBreakFirstLineSymbol]: ${!!breakFirstLine} });\n`; const result = module._compile(script, `${name}-wrapper`); - if (print) { - const { log } = require('internal/console/global'); - log(result); + if (printResult) { + const { kStdout, print } = require('internal/util/print'); + print(kStdout, result); } } diff --git a/lib/internal/process/main_thread_only.js b/lib/internal/process/main_thread_only.js index 358e2b37b0f834..8af402c57a6cb0 100644 --- a/lib/internal/process/main_thread_only.js +++ b/lib/internal/process/main_thread_only.js @@ -20,9 +20,15 @@ const { signals } = internalBinding('constants').os; // The execution of this function itself should not cause any side effects. function wrapProcessMethods(binding) { + // Cache the working directory to prevent lots of lookups. If the working + // directory is changed by `chdir`, it'll be updated. + let cachedCwd = ''; + function chdir(directory) { validateString(directory, 'directory'); - return binding.chdir(directory); + binding.chdir(directory); + // Mark cache that it requires an update. + cachedCwd = ''; } function umask(mask) { @@ -32,9 +38,15 @@ function wrapProcessMethods(binding) { return binding.umask(mask); } + function cwd() { + cachedCwd = binding.cwd(); + return cachedCwd; + } + return { chdir, - umask + umask, + cwd }; } diff --git a/lib/internal/process/task_queues.js b/lib/internal/process/task_queues.js index 309e27e6ecd0fa..51486284578bce 100644 --- a/lib/internal/process/task_queues.js +++ b/lib/internal/process/task_queues.js @@ -1,6 +1,6 @@ 'use strict'; -const { FunctionPrototype, Reflect } = primordials; +const { FunctionPrototype } = primordials; const { // For easy access to the nextTick state in the C++ land, @@ -81,7 +81,7 @@ function processTicksAndRejections() { if (tock.args === undefined) callback(); else - Reflect.apply(callback, undefined, tock.args); + callback(...tock.args); emitAfter(asyncId); } @@ -93,9 +93,6 @@ function processTicksAndRejections() { class TickObject { constructor(callback, args, triggerAsyncId) { - // This must be set to null first to avoid function tracking - // on the hidden class, revisit in V8 versions after 6.2 - this.callback = null; this.callback = callback; this.args = args; diff --git a/lib/internal/repl/await.js b/lib/internal/repl/await.js index ac0445311b7ba9..6fb10bbba0d2b8 100644 --- a/lib/internal/repl/await.js +++ b/lib/internal/repl/await.js @@ -4,6 +4,23 @@ const { Object } = primordials; const acorn = require('internal/deps/acorn/acorn/dist/acorn'); const walk = require('internal/deps/acorn/acorn-walk/dist/walk'); +const privateMethods = + require('internal/deps/acorn-plugins/acorn-private-methods/index'); +const bigInt = require('internal/deps/acorn-plugins/acorn-bigint/index'); +const classFields = + require('internal/deps/acorn-plugins/acorn-class-fields/index'); +const numericSeparator = + require('internal/deps/acorn-plugins/acorn-numeric-separator/index'); +const staticClassFeatures = + require('internal/deps/acorn-plugins/acorn-static-class-features/index'); + +const parser = acorn.Parser.extend( + privateMethods, + bigInt, + classFields, + numericSeparator, + staticClassFeatures +); const noop = () => {}; const visitorsWithoutAncestors = { @@ -76,7 +93,7 @@ function processTopLevelAwait(src) { const wrappedArray = wrapped.split(''); let root; try { - root = acorn.parse(wrapped, { ecmaVersion: 10 }); + root = parser.parse(wrapped, { ecmaVersion: 10 }); } catch { return null; } diff --git a/lib/internal/repl/utils.js b/lib/internal/repl/utils.js index 6830ebb08065e5..2ad78a8ab4dfaa 100644 --- a/lib/internal/repl/utils.js +++ b/lib/internal/repl/utils.js @@ -1,6 +1,15 @@ 'use strict'; const acorn = require('internal/deps/acorn/acorn/dist/acorn'); +const privateMethods = + require('internal/deps/acorn-plugins/acorn-private-methods/index'); +const bigInt = require('internal/deps/acorn-plugins/acorn-bigint/index'); +const classFields = + require('internal/deps/acorn-plugins/acorn-class-fields/index'); +const numericSeparator = + require('internal/deps/acorn-plugins/acorn-numeric-separator/index'); +const staticClassFeatures = + require('internal/deps/acorn-plugins/acorn-static-class-features/index'); const { tokTypes: tt, Parser: AcornParser } = acorn; // If the error is that we've unexpectedly ended the input, @@ -8,6 +17,12 @@ const { tokTypes: tt, Parser: AcornParser } = acorn; // Note: `e` (the original exception) is not used by the current implementation, // but may be needed in the future. function isRecoverableError(e, code) { + // For similar reasons as `defaultEval`, wrap expressions starting with a + // curly brace with parenthesis. Note: only the open parenthesis is added + // here as the point is to test for potentially valid but incomplete + // expressions. + if (/^\s*\{/.test(code) && isRecoverableError(e, `(${code}`)) return true; + let recoverable = false; // Determine if the point of any error raised is at the end of the input. @@ -26,34 +41,39 @@ function isRecoverableError(e, code) { // change these messages in the future, this will lead to a test // failure, indicating that this code needs to be updated. // - const RecoverableParser = AcornParser.extend((Parser) => { - return class extends Parser { - nextToken() { - super.nextToken(); - if (this.type === tt.eof) recoverable = true; - } - raise(pos, message) { - switch (message) { - case 'Unterminated template': - case 'Unterminated comment': - recoverable = true; - break; + const RecoverableParser = AcornParser + .extend( + privateMethods, + bigInt, + classFields, + numericSeparator, + staticClassFeatures, + (Parser) => { + return class extends Parser { + nextToken() { + super.nextToken(); + if (this.type === tt.eof) + recoverable = true; + } + raise(pos, message) { + switch (message) { + case 'Unterminated template': + case 'Unterminated comment': + recoverable = true; + break; - case 'Unterminated string constant': - const token = this.input.slice(this.lastTokStart, this.pos); - // See https://www.ecma-international.org/ecma-262/#sec-line-terminators - recoverable = /\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token); - } - super.raise(pos, message); + case 'Unterminated string constant': + const token = this.input.slice(this.lastTokStart, this.pos); + // See https://www.ecma-international.org/ecma-262/#sec-line-terminators + if (/\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token)) { + recoverable = true; + } + } + super.raise(pos, message); + } + }; } - }; - }); - - // For similar reasons as `defaultEval`, wrap expressions starting with a - // curly brace with parenthesis. Note: only the open parenthesis is added - // here as the point is to test for potentially valid but incomplete - // expressions. - if (/^\s*\{/.test(code) && isRecoverableError(e, `(${code}`)) return true; + ); // Try to parse the code with acorn. If the parse fails, ignore the acorn // error and return the recoverable status. diff --git a/lib/internal/timers.js b/lib/internal/timers.js index 566d7df0365389..8ba7923e57218e 100644 --- a/lib/internal/timers.js +++ b/lib/internal/timers.js @@ -72,7 +72,7 @@ // timers within (or creation of a new list). However, these operations combined // have shown to be trivial in comparison to other timers architectures. -const { Math, Object, Reflect } = primordials; +const { Math, Object } = primordials; const { scheduleTimer, @@ -438,7 +438,7 @@ function getTimerCallbacks(runNextTicks) { if (!argv) immediate._onImmediate(); else - Reflect.apply(immediate._onImmediate, immediate, argv); + immediate._onImmediate(...argv); } finally { immediate._onImmediate = null; @@ -530,7 +530,7 @@ function getTimerCallbacks(runNextTicks) { if (args === undefined) timer._onTimeout(); else - Reflect.apply(timer._onTimeout, timer, args); + timer._onTimeout(...args); } finally { if (timer._repeat && timer._idleTimeout !== -1) { timer._idleTimeout = timer._repeat; diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index fccb46085d4ead..90be07535730c4 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -28,6 +28,7 @@ const { kPending, kRejected, previewEntries, + getConstructorName: internalGetConstructorName, propertyFilter: { ALL_PROPERTIES, ONLY_ENUMERABLE @@ -49,6 +50,8 @@ const { } = require('internal/errors'); const { + isAsyncFunction, + isGeneratorFunction, isAnyArrayBuffer, isArrayBuffer, isArgumentsObject, @@ -347,6 +350,7 @@ function getEmptyFormatArray() { function getConstructorName(obj, ctx) { let firstProto; + const tmp = obj; while (obj) { const descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor'); if (descriptor !== undefined && @@ -365,7 +369,7 @@ function getConstructorName(obj, ctx) { return null; } - return `<${inspect(firstProto, { + return `${internalGetConstructorName(tmp)} <${inspect(firstProto, { ...ctx, customInspect: false })}>`; @@ -642,14 +646,9 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { return `${braces[0]}}`; } } else if (typeof value === 'function') { - const type = constructor || tag || 'Function'; - let name = `${type}`; - if (value.name && typeof value.name === 'string') { - name += `: ${value.name}`; - } + base = getFunctionBase(value, constructor, tag); if (keys.length === 0) - return ctx.stylize(`[${name}]`, 'special'); - base = `[${name}]`; + return ctx.stylize(base, 'special'); } else if (isRegExp(value)) { // Make RegExps say that they are RegExps base = RegExpPrototype.toString( @@ -834,6 +833,30 @@ function getBoxedBase(value, ctx, keys, constructor, tag) { return ctx.stylize(base, type.toLowerCase()); } +function getFunctionBase(value, constructor, tag) { + let type = 'Function'; + if (isAsyncFunction(value)) { + type = 'AsyncFunction'; + } else if (isGeneratorFunction(value)) { + type = 'GeneratorFunction'; + } + let base = `[${type}`; + if (constructor === null) { + base += ' (null prototype)'; + } + if (value.name !== '') { + base += `: ${value.name}`; + } + base += ']'; + if (constructor !== type && constructor !== null) { + base += ` ${constructor}`; + } + if (tag !== '' && constructor !== tag) { + base += ` [${tag}]`; + } + return base; +} + function formatError(err, constructor, tag, ctx) { // TODO(BridgeAR): Always show the error code if present. let stack = err.stack || ErrorPrototype.toString(err); @@ -1055,7 +1078,7 @@ function formatPrimitive(fn, value, ctx) { if (typeof value === 'undefined') return fn('undefined', 'undefined'); // es6 symbol primitive - return fn(value.toString(), 'symbol'); + return fn(SymbolPrototype.toString(value), 'symbol'); } function formatNamespaceObject(ctx, value, recurseTimes, keys) { @@ -1461,9 +1484,8 @@ function reduceToSingleString( return `${braces[0]}${ln}${join(output, `,\n${indentation} `)} ${braces[1]}`; } -const emptyOptions = {}; function format(...args) { - return formatWithOptions(emptyOptions, ...args); + return formatWithOptions(undefined, ...args); } @@ -1509,16 +1531,14 @@ function formatWithOptions(inspectOptions, ...args) { switch (nextChar) { case 115: // 's' const tempArg = args[++a]; - if (typeof tempArg === 'object' && tempArg !== null) { + if (typeof tempArg !== 'string' && + typeof tempArg !== 'function') { tempStr = inspect(tempArg, { ...inspectOptions, compact: 3, colors: false, depth: 0 }); - // eslint-disable-next-line valid-typeof - } else if (typeof tempArg === 'bigint') { - tempStr = `${tempArg}n`; } else { tempStr = String(tempArg); } @@ -1534,7 +1554,7 @@ function formatWithOptions(inspectOptions, ...args) { } else if (typeof tempNum === 'symbol') { tempStr = 'NaN'; } else { - tempStr = `${Number(tempNum)}`; + tempStr = formatNumber(stylizeNoColor, Number(tempNum)); } break; case 79: // 'O' @@ -1558,7 +1578,7 @@ function formatWithOptions(inspectOptions, ...args) { } else if (typeof tempInteger === 'symbol') { tempStr = 'NaN'; } else { - tempStr = `${parseInt(tempInteger)}`; + tempStr = formatNumber(stylizeNoColor, parseInt(tempInteger)); } break; case 102: // 'f' @@ -1566,7 +1586,7 @@ function formatWithOptions(inspectOptions, ...args) { if (typeof tempFloat === 'symbol') { tempStr = 'NaN'; } else { - tempStr = `${parseFloat(tempFloat)}`; + tempStr = formatNumber(stylizeNoColor, parseFloat(tempFloat)); } break; case 37: // '%' diff --git a/lib/internal/util/print.js b/lib/internal/util/print.js new file mode 100644 index 00000000000000..4c9327502ebad2 --- /dev/null +++ b/lib/internal/util/print.js @@ -0,0 +1,67 @@ +'use strict'; + +// This implements a light-weight printer that writes to stdout/stderr +// directly to avoid the overhead in the console abstraction. + +const { formatWithOptions } = require('internal/util/inspect'); +const { writeString } = internalBinding('fs'); +const { handleErrorFromBinding } = require('internal/fs/utils'); +const { guessHandleType } = internalBinding('util'); +const { log } = require('internal/console/global'); + +const kStdout = 1; +const kStderr = 2; +const handleType = [undefined, undefined, undefined]; +function getFdType(fd) { + if (handleType[fd] === undefined) { + handleType[fd] = guessHandleType(fd); + } + return handleType[fd]; +} + +function formatAndWrite(fd, obj, ignoreErrors, colors = false) { + const str = `${formatWithOptions({ colors }, obj)}\n`; + const ctx = {}; + writeString(fd, str, null, undefined, undefined, ctx); + if (!ignoreErrors) { + handleErrorFromBinding(ctx); + } +} + +let colors; +function getColors() { + if (colors === undefined) { + colors = require('internal/tty').getColorDepth() > 2; + } + return colors; +} + +// TODO(joyeecheung): replace more internal process._rawDebug() +// and console.log() usage with this if possible. +function print(fd, obj, ignoreErrors = true) { + switch (getFdType(fd)) { + case 'TTY': + formatAndWrite(fd, obj, ignoreErrors, getColors()); + break; + case 'FILE': + formatAndWrite(fd, obj, ignoreErrors); + break; + case 'PIPE': + case 'TCP': + // Fallback to console.log to handle IPC. + if (process.channel && process.channel.fd === fd) { + log(obj); + } else { + formatAndWrite(fd, obj, ignoreErrors); + } + break; + default: + log(obj); + } +} + +module.exports = { + print, + kStderr, + kStdout +}; diff --git a/lib/internal/worker.js b/lib/internal/worker.js index e9d961f35a0a71..fc2a5eceeddf8e 100644 --- a/lib/internal/worker.js +++ b/lib/internal/worker.js @@ -1,5 +1,7 @@ 'use strict'; +/* global SharedArrayBuffer */ + const { Object } = primordials; const EventEmitter = require('events'); @@ -16,6 +18,7 @@ const { const { validateString } = require('internal/validators'); const { getOptionValue } = require('internal/options'); +const workerIo = require('internal/worker/io'); const { drainMessagePort, MessageChannel, @@ -26,8 +29,8 @@ const { kStdioWantsMoreDataCallback, setupPortReferencing, ReadableWorkerStdio, - WritableWorkerStdio, -} = require('internal/worker/io'); + WritableWorkerStdio +} = workerIo; const { deserializeError } = require('internal/error-serdes'); const { pathToFileURL } = require('url'); @@ -50,6 +53,17 @@ const kParentSideStdio = Symbol('kParentSideStdio'); const SHARE_ENV = Symbol.for('nodejs.worker_threads.SHARE_ENV'); const debug = require('internal/util/debuglog').debuglog('worker'); +let cwdCounter; + +if (isMainThread) { + cwdCounter = new Uint32Array(new SharedArrayBuffer(4)); + const originalChdir = process.chdir; + process.chdir = function(path) { + Atomics.add(cwdCounter, 0, 1); + originalChdir(path); + }; +} + class Worker extends EventEmitter { constructor(filename, options = {}) { super(); @@ -131,6 +145,7 @@ class Worker extends EventEmitter { type: messageTypes.LOAD_SCRIPT, filename, doEval: !!options.eval, + cwdCounter: cwdCounter || workerIo.sharedCwdCounter, workerData: options.workerData, publicPort: port2, manifestSrc: getOptionValue('--experimental-policy') ? diff --git a/lib/repl.js b/lib/repl.js index a7eb22e396e847..d439d205a40e0c 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -1118,7 +1118,30 @@ function complete(line, callback) { } completionGroupsLoaded(); + } else if (match = line.match(/fs\.\s*[a-z][a-zA-Z]+\(\s*["'](.*)/)) { + let filePath = match[1]; + let fileList; + filter = ''; + + try { + fileList = fs.readdirSync(filePath, { withFileTypes: true }); + completionGroups.push(fileList.map((dirent) => dirent.name)); + completeOn = ''; + } catch { + try { + const baseName = path.basename(filePath); + filePath = path.dirname(filePath); + fileList = fs.readdirSync(filePath, { withFileTypes: true }); + const filteredValue = fileList.filter((d) => + d.name.startsWith(baseName)) + .map((d) => d.name); + completionGroups.push(filteredValue); + completeOn = filePath; + } catch {} + } + + completionGroupsLoaded(); // Handle variable member lookup. // We support simple chained expressions like the following (no function // calls, etc.). That is for simplicity and also because we *eval* that diff --git a/lib/timers.js b/lib/timers.js index ddce43e7491795..98acbf8fa44152 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -207,9 +207,6 @@ const Immediate = class Immediate { constructor(callback, args) { this._idleNext = null; this._idlePrev = null; - // This must be set to null first to avoid function tracking - // on the hidden class, revisit in V8 versions after 6.2 - this._onImmediate = null; this._onImmediate = callback; this._argv = args; this._destroyed = false; diff --git a/lib/tls.js b/lib/tls.js index 422ed7958a1ee7..fa247411f39aa5 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -60,6 +60,8 @@ if (getOptionValue('--tls-min-v1.0')) exports.DEFAULT_MIN_VERSION = 'TLSv1'; else if (getOptionValue('--tls-min-v1.1')) exports.DEFAULT_MIN_VERSION = 'TLSv1.1'; +else if (getOptionValue('--tls-min-v1.2')) + exports.DEFAULT_MIN_VERSION = 'TLSv1.2'; else if (getOptionValue('--tls-min-v1.3')) exports.DEFAULT_MIN_VERSION = 'TLSv1.3'; else diff --git a/node.gyp b/node.gyp index 53bd954afb3e39..1ab6b15d73133f 100644 --- a/node.gyp +++ b/node.gyp @@ -184,6 +184,7 @@ 'lib/internal/url.js', 'lib/internal/util.js', 'lib/internal/util/comparisons.js', + 'lib/internal/util/print.js', 'lib/internal/util/debuglog.js', 'lib/internal/util/inspect.js', 'lib/internal/util/inspector.js', @@ -223,6 +224,12 @@ 'deps/node-inspect/lib/internal/inspect_repl.js', 'deps/acorn/acorn/dist/acorn.js', 'deps/acorn/acorn-walk/dist/walk.js', + 'deps/acorn-plugins/acorn-bigint/index.js', + 'deps/acorn-plugins/acorn-class-fields/index.js', + 'deps/acorn-plugins/acorn-numeric-separator/index.js', + 'deps/acorn-plugins/acorn-private-class-elements/index.js', + 'deps/acorn-plugins/acorn-private-methods/index.js', + 'deps/acorn-plugins/acorn-static-class-features/index.js', ], 'node_mksnapshot_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)node_mksnapshot<(EXECUTABLE_SUFFIX)', 'mkcodecache_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mkcodecache<(EXECUTABLE_SUFFIX)', @@ -605,7 +612,6 @@ 'src/node_options-inl.h', 'src/node_perf.h', 'src/node_perf_common.h', - 'src/node_persistent.h', 'src/node_platform.h', 'src/node_process.h', 'src/node_revert.h', diff --git a/src/async_wrap.cc b/src/async_wrap.cc index 9cfa0924c79568..0c84b06fdde346 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -35,6 +35,7 @@ using v8::EscapableHandleScope; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; +using v8::Global; using v8::HandleScope; using v8::Integer; using v8::Isolate; @@ -177,7 +178,7 @@ void AsyncWrap::EmitAfter(Environment* env, double async_id) { class PromiseWrap : public AsyncWrap { public: PromiseWrap(Environment* env, Local object, bool silent) - : AsyncWrap(env, object, PROVIDER_PROMISE, -1, silent) { + : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) { MakeWeak(); } @@ -346,8 +347,8 @@ class DestroyParam { public: double asyncId; Environment* env; - Persistent target; - Persistent propBag; + Global target; + Global propBag; }; void AsyncWrap::WeakCallback(const WeakCallbackInfo& info) { @@ -387,7 +388,7 @@ static void RegisterDestroyHook(const FunctionCallbackInfo& args) { void AsyncWrap::GetAsyncId(const FunctionCallbackInfo& args) { AsyncWrap* wrap; - args.GetReturnValue().Set(-1); + args.GetReturnValue().Set(kInvalidAsyncId); ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); args.GetReturnValue().Set(wrap->get_async_id()); } @@ -414,10 +415,15 @@ void AsyncWrap::AsyncReset(const FunctionCallbackInfo& args) { AsyncWrap* wrap; ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); double execution_async_id = - args[0]->IsNumber() ? args[0].As()->Value() : -1; + args[0]->IsNumber() ? args[0].As()->Value() : kInvalidAsyncId; wrap->AsyncReset(execution_async_id); } +void AsyncWrap::EmitDestroy() { + AsyncWrap::EmitDestroy(env(), async_id_); + // Ensure no double destroy is emitted via AsyncReset(). + async_id_ = kInvalidAsyncId; +} void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo& args) { CHECK(args[0]->IsNumber()); @@ -480,7 +486,7 @@ void AsyncWrap::Initialize(Local target, // kDefaultTriggerAsyncId: Write the id of the resource responsible for a // handle's creation just before calling the new handle's constructor. // After the new handle is constructed kDefaultTriggerAsyncId is set back - // to -1. + // to kInvalidAsyncId. FORCE_SET_TARGET_FIELD(target, "async_id_fields", env->async_hooks()->async_id_fields().GetJSArray()); @@ -568,10 +574,16 @@ AsyncWrap::AsyncWrap(Environment* env, AsyncReset(execution_async_id, silent); } +AsyncWrap::AsyncWrap(Environment* env, v8::Local object) + : BaseObject(env, object), + provider_type_(PROVIDER_NONE) { + CHECK_GE(object->InternalFieldCount(), 1); +} + AsyncWrap::~AsyncWrap() { EmitTraceEventDestroy(); - EmitDestroy(env(), get_async_id()); + EmitDestroy(); } void AsyncWrap::EmitTraceEventDestroy() { @@ -611,16 +623,18 @@ void AsyncWrap::AsyncReset(double execution_async_id, bool silent) { // the resource is pulled out of the pool and put back into use. void AsyncWrap::AsyncReset(Local resource, double execution_async_id, bool silent) { - if (async_id_ != -1) { + CHECK_NE(provider_type(), PROVIDER_NONE); + + if (async_id_ != kInvalidAsyncId) { // This instance was in use before, we have already emitted an init with // its previous async_id and need to emit a matching destroy for that // before generating a new async_id. - EmitDestroy(env(), async_id_); + EmitDestroy(); } // Now we can assign a new async_id_ to this instance. - async_id_ = - execution_async_id == -1 ? env()->new_async_id() : execution_async_id; + async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id() + : execution_async_id; trigger_async_id_ = env()->get_default_trigger_async_id(); switch (provider_type()) { diff --git a/src/async_wrap.h b/src/async_wrap.h index bcd37bb0c0d5b6..20134f4a7bbfad 100644 --- a/src/async_wrap.h +++ b/src/async_wrap.h @@ -109,12 +109,18 @@ class AsyncWrap : public BaseObject { AsyncWrap(Environment* env, v8::Local object, ProviderType provider, - double execution_async_id = -1); + double execution_async_id = kInvalidAsyncId); + + // This constructor creates a reuseable instance where user is responsible + // to call set_provider_type() and AsyncReset() before use. + AsyncWrap(Environment* env, v8::Local object); ~AsyncWrap() override; AsyncWrap() = delete; + static constexpr double kInvalidAsyncId = -1; + static v8::Local GetConstructorTemplate( Environment* env); @@ -141,6 +147,8 @@ class AsyncWrap : public BaseObject { static void EmitAfter(Environment* env, double async_id); static void EmitPromiseResolve(Environment* env, double async_id); + void EmitDestroy(); + void EmitTraceEventBefore(); static void EmitTraceEventAfter(ProviderType type, double async_id); void EmitTraceEventDestroy(); @@ -155,10 +163,11 @@ class AsyncWrap : public BaseObject { inline double get_trigger_async_id() const; void AsyncReset(v8::Local resource, - double execution_async_id = -1, + double execution_async_id = kInvalidAsyncId, bool silent = false); - void AsyncReset(double execution_async_id = -1, bool silent = false); + void AsyncReset(double execution_async_id = kInvalidAsyncId, + bool silent = false); // Only call these within a valid HandleScope. v8::MaybeLocal MakeCallback(const v8::Local cb, @@ -210,7 +219,7 @@ class AsyncWrap : public BaseObject { bool silent); ProviderType provider_type_; // Because the values may be Reset(), cannot be made const. - double async_id_ = -1; + double async_id_ = kInvalidAsyncId; double trigger_async_id_; }; diff --git a/src/base_object-inl.h b/src/base_object-inl.h index e3d645056a5dc2..fd61c15feaee91 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -56,7 +56,7 @@ BaseObject::~BaseObject() { } -Persistent& BaseObject::persistent() { +v8::Global& BaseObject::persistent() { return persistent_handle_; } diff --git a/src/base_object.h b/src/base_object.h index f1c666224f0401..cb83462ff51e54 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -24,7 +24,6 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "node_persistent.h" #include "memory_tracker-inl.h" #include "v8.h" #include // std::remove_reference @@ -50,7 +49,7 @@ class BaseObject : public MemoryRetainer { // is associated with the passed Isolate in debug mode. inline v8::Local object(v8::Isolate* isolate) const; - inline Persistent& persistent(); + inline v8::Global& persistent(); inline Environment* env() const; @@ -62,7 +61,7 @@ class BaseObject : public MemoryRetainer { template static inline T* FromJSObject(v8::Local object); - // Make the `Persistent` a weak reference and, `delete` this object once + // Make the `v8::Global` a weak reference and, `delete` this object once // the JS object has been garbage collected. inline void MakeWeak(); @@ -96,7 +95,7 @@ class BaseObject : public MemoryRetainer { friend int GenDebugSymbols(); friend class CleanupHookCallback; - Persistent persistent_handle_; + v8::Global persistent_handle_; Environment* env_; }; diff --git a/src/env-inl.h b/src/env-inl.h index 36f8506bafb5a7..992e51354e6cf2 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -673,16 +673,24 @@ Environment::cpu_profiler_connection() { return cpu_profiler_connection_.get(); } -inline void Environment::set_cpu_profile_path(const std::string& path) { - cpu_profile_path_ = path; +inline void Environment::set_cpu_prof_interval(uint64_t interval) { + cpu_prof_interval_ = interval; } -inline const std::string& Environment::cpu_profile_path() const { - return cpu_profile_path_; +inline uint64_t Environment::cpu_prof_interval() const { + return cpu_prof_interval_; } -inline void Environment::set_cpu_prof_dir(const std::string& path) { - cpu_prof_dir_ = path; +inline void Environment::set_cpu_prof_name(const std::string& name) { + cpu_prof_name_ = name; +} + +inline const std::string& Environment::cpu_prof_name() const { + return cpu_prof_name_; +} + +inline void Environment::set_cpu_prof_dir(const std::string& dir) { + cpu_prof_dir_ = dir; } inline const std::string& Environment::cpu_prof_dir() const { @@ -1106,10 +1114,13 @@ void AsyncRequest::set_stopped(bool flag) { inline void Environment::set_ ## PropertyName(v8::Local value) { \ PropertyName ## _.Reset(isolate(), value); \ } - ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) + ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) #undef V + inline v8::Local Environment::context() const { + return PersistentToLocal::Strong(context_); + } } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/env.cc b/src/env.cc index ad43b13607006e..197cd5bd904208 100644 --- a/src/env.cc +++ b/src/env.cc @@ -907,20 +907,6 @@ void Environment::stop_sub_worker_contexts() { #if HAVE_INSPECTOR -void Environment::InitializeCPUProfDir(const std::string& dir) { - if (!dir.empty()) { - cpu_prof_dir_ = dir; - return; - } - char cwd[CWD_BUFSIZE]; - size_t size = CWD_BUFSIZE; - int err = uv_cwd(cwd, &size); - // TODO(joyeecheung): fallback to exec path / argv[0] - CHECK_EQ(err, 0); - CHECK_GT(size, 0); - cpu_prof_dir_ = cwd; -} - #endif // HAVE_INSPECTOR void MemoryTracker::TrackField(const char* edge_name, diff --git a/src/env.h b/src/env.h index d4991535186d51..a3c6ec3cc9092f 100644 --- a/src/env.h +++ b/src/env.h @@ -340,11 +340,10 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2; V(x_forwarded_string, "x-forwarded-for") \ V(zero_return_string, "ZERO_RETURN") -#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ +#define ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) \ V(as_callback_data_template, v8::FunctionTemplate) \ V(async_wrap_ctor_template, v8::FunctionTemplate) \ V(async_wrap_object_ctor_template, v8::FunctionTemplate) \ - V(context, v8::Context) \ V(fd_constructor_template, v8::ObjectTemplate) \ V(fdclose_constructor_template, v8::ObjectTemplate) \ V(filehandlereadwrap_template, v8::ObjectTemplate) \ @@ -421,8 +420,8 @@ class IsolateData : public MemoryRetainer { MultiIsolatePlatform* platform = nullptr, ArrayBufferAllocator* node_allocator = nullptr, const std::vector* indexes = nullptr); - SET_MEMORY_INFO_NAME(IsolateData); - SET_SELF_SIZE(IsolateData); + SET_MEMORY_INFO_NAME(IsolateData) + SET_SELF_SIZE(IsolateData) void MemoryInfo(MemoryTracker* tracker) const override; std::vector Serialize(v8::SnapshotCreator* creator); @@ -585,8 +584,8 @@ extern std::shared_ptr system_environment; class AsyncHooks : public MemoryRetainer { public: - SET_MEMORY_INFO_NAME(AsyncHooks); - SET_SELF_SIZE(AsyncHooks); + SET_MEMORY_INFO_NAME(AsyncHooks) + SET_SELF_SIZE(AsyncHooks) void MemoryInfo(MemoryTracker* tracker) const override; // Reason for both UidFields and Fields are that one is stored as a double* @@ -688,8 +687,8 @@ class ImmediateInfo : public MemoryRetainer { ImmediateInfo(const ImmediateInfo&) = delete; ImmediateInfo& operator=(const ImmediateInfo&) = delete; - SET_MEMORY_INFO_NAME(ImmediateInfo); - SET_SELF_SIZE(ImmediateInfo); + SET_MEMORY_INFO_NAME(ImmediateInfo) + SET_SELF_SIZE(ImmediateInfo) void MemoryInfo(MemoryTracker* tracker) const override; private: @@ -707,8 +706,8 @@ class TickInfo : public MemoryRetainer { inline bool has_tick_scheduled() const; inline bool has_rejection_to_warn() const; - SET_MEMORY_INFO_NAME(TickInfo); - SET_SELF_SIZE(TickInfo); + SET_MEMORY_INFO_NAME(TickInfo) + SET_SELF_SIZE(TickInfo) void MemoryInfo(MemoryTracker* tracker) const override; TickInfo(const TickInfo&) = delete; @@ -787,7 +786,7 @@ class Environment : public MemoryRetainer { Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; - SET_MEMORY_INFO_NAME(Environment); + SET_MEMORY_INFO_NAME(Environment) inline size_t SelfSize() const override; bool IsRootNode() const override { return true; } @@ -929,7 +928,7 @@ class Environment : public MemoryRetainer { std::unordered_map id_to_script_map; std::unordered_set compile_fn_entries; - std::unordered_map> id_to_function_map; + std::unordered_map> id_to_function_map; inline uint32_t get_next_module_id(); inline uint32_t get_next_script_id(); @@ -1061,9 +1060,11 @@ class Environment : public MemoryRetainer { inline v8::Local PropertyName() const; \ inline void set_ ## PropertyName(v8::Local value); ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) - ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) + ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) #undef V + inline v8::Local context() const; + #if HAVE_INSPECTOR inline inspector::Agent* inspector_agent() const { return inspector_agent_.get(); @@ -1139,13 +1140,14 @@ class Environment : public MemoryRetainer { std::unique_ptr connection); profiler::V8CpuProfilerConnection* cpu_profiler_connection(); - inline void set_cpu_profile_path(const std::string& path); - inline const std::string& cpu_profile_path() const; + inline void set_cpu_prof_name(const std::string& name); + inline const std::string& cpu_prof_name() const; - inline void set_cpu_prof_dir(const std::string& path); - inline const std::string& cpu_prof_dir() const; + inline void set_cpu_prof_interval(uint64_t interval); + inline uint64_t cpu_prof_interval() const; - void InitializeCPUProfDir(const std::string& dir); + inline void set_cpu_prof_dir(const std::string& dir); + inline const std::string& cpu_prof_dir() const; #endif // HAVE_INSPECTOR private: @@ -1183,7 +1185,8 @@ class Environment : public MemoryRetainer { std::unique_ptr cpu_profiler_connection_; std::string coverage_directory_; std::string cpu_prof_dir_; - std::string cpu_profile_path_; + std::string cpu_prof_name_; + uint64_t cpu_prof_interval_; #endif // HAVE_INSPECTOR std::shared_ptr options_; @@ -1292,10 +1295,12 @@ class Environment : public MemoryRetainer { template void ForEachBaseObject(T&& iterator); -#define V(PropertyName, TypeName) Persistent PropertyName ## _; +#define V(PropertyName, TypeName) v8::Global PropertyName ## _; ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) - ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) + ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) #undef V + + v8::Global context_; }; } // namespace node diff --git a/src/heap_utils.cc b/src/heap_utils.cc index d5b5afa4d5be9e..654dfabafe62b6 100644 --- a/src/heap_utils.cc +++ b/src/heap_utils.cc @@ -8,6 +8,7 @@ using v8::EmbedderGraph; using v8::EscapableHandleScope; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; +using v8::Global; using v8::HandleScope; using v8::HeapSnapshot; using v8::Isolate; @@ -56,7 +57,7 @@ class JSGraphJSNode : public EmbedderGraph::Node { }; private: - Persistent persistent_; + Global persistent_; }; class JSGraph : public EmbedderGraph { diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 10b607ff6c53c2..fce174012f7a71 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -9,6 +9,7 @@ #include "node/inspector/protocol/Protocol.h" #include "node_errors.h" #include "node_internals.h" +#include "node_options-inl.h" #include "node_process.h" #include "node_url.h" #include "v8-inspector.h" @@ -34,6 +35,7 @@ using node::FatalError; using v8::Context; using v8::Function; +using v8::Global; using v8::HandleScope; using v8::Isolate; using v8::Local; @@ -834,7 +836,7 @@ void Agent::DisableAsyncHook() { } void Agent::ToggleAsyncHook(Isolate* isolate, - const node::Persistent& fn) { + const Global& fn) { CHECK(parent_env_->has_run_bootstrapping_code()); HandleScope handle_scope(isolate); CHECK(!fn.IsEmpty()); diff --git a/src/inspector_agent.h b/src/inspector_agent.h index b079ea675fbafa..1c2bde0da73e84 100644 --- a/src/inspector_agent.h +++ b/src/inspector_agent.h @@ -6,8 +6,7 @@ #error("This header can only be used when inspector is enabled") #endif -#include "node_options-inl.h" -#include "node_persistent.h" +#include "node_options.h" #include "v8.h" #include @@ -114,7 +113,7 @@ class Agent { private: void ToggleAsyncHook(v8::Isolate* isolate, - const node::Persistent& fn); + const v8::Global& fn); node::Environment* parent_env_; // Encapsulates majority of the Inspector functionality @@ -133,8 +132,8 @@ class Agent { bool pending_enable_async_hook_ = false; bool pending_disable_async_hook_ = false; - node::Persistent enable_async_hook_function_; - node::Persistent disable_async_hook_function_; + v8::Global enable_async_hook_function_; + v8::Global disable_async_hook_function_; }; } // namespace inspector diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 51ec14a63a1ad1..4948bd8797a9e4 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -15,6 +15,7 @@ using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; +using v8::Global; using v8::HandleScope; using v8::Isolate; using v8::Local; @@ -116,7 +117,7 @@ class JSBindingsConnection : public AsyncWrap { private: std::unique_ptr session_; - Persistent callback_; + Global callback_; }; static bool InspectorEnabled(Environment* env) { diff --git a/src/inspector_profiler.cc b/src/inspector_profiler.cc index 3507ae4ef2f1e0..2d3f061e987d35 100644 --- a/src/inspector_profiler.cc +++ b/src/inspector_profiler.cc @@ -1,4 +1,5 @@ #include "inspector_profiler.h" +#include #include "base_object-inl.h" #include "debug_utils.h" #include "node_file.h" @@ -20,7 +21,6 @@ using v8::Object; using v8::String; using v8::Value; -using v8_inspector::StringBuffer; using v8_inspector::StringView; #ifdef _WIN32 @@ -33,12 +33,6 @@ const char* const kPathSeparator = "/"; #define CWD_BUFSIZE (PATH_MAX) #endif -std::unique_ptr ToProtocolString(Isolate* isolate, - Local value) { - TwoByteValue buffer(isolate, value); - return StringBuffer::create(StringView(*buffer, buffer.length())); -} - V8ProfilerConnection::V8ProfilerConnection(Environment* env) : session_(env->inspector_agent()->Connect( std::make_unique( @@ -46,49 +40,77 @@ V8ProfilerConnection::V8ProfilerConnection(Environment* env) false)), env_(env) {} -void V8ProfilerConnection::DispatchMessage(Local message) { - session_->Dispatch(ToProtocolString(env()->isolate(), message)->string()); +size_t V8ProfilerConnection::DispatchMessage(const char* method, + const char* params) { + std::stringstream ss; + size_t id = next_id(); + ss << R"({ "id": )" << id; + DCHECK(method != nullptr); + ss << R"(, "method": ")" << method << '"'; + if (params != nullptr) { + ss << R"(, "params": )" << params; + } + ss << " }"; + std::string message = ss.str(); + const uint8_t* message_data = + reinterpret_cast(message.c_str()); + Debug(env(), + DebugCategory::INSPECTOR_PROFILER, + "Dispatching message %s\n", + message.c_str()); + session_->Dispatch(StringView(message_data, message.length())); + // TODO(joyeecheung): use this to identify the ending message. + return id; } -bool V8ProfilerConnection::WriteResult(const char* path, Local result) { - int ret = WriteFileSync(env()->isolate(), path, result); +static void WriteResult(Environment* env, + const char* path, + Local result) { + int ret = WriteFileSync(env->isolate(), path, result); if (ret != 0) { char err_buf[128]; uv_err_name_r(ret, err_buf, sizeof(err_buf)); fprintf(stderr, "%s: Failed to write file %s\n", err_buf, path); - return false; + return; } - Debug( - env(), DebugCategory::INSPECTOR_PROFILER, "Written result to %s\n", path); - return true; + Debug(env, DebugCategory::INSPECTOR_PROFILER, "Written result to %s\n", path); } -void V8CoverageConnection::OnMessage(const v8_inspector::StringView& message) { - Debug(env(), +void V8ProfilerConnection::V8ProfilerSessionDelegate::SendMessageToFrontend( + const v8_inspector::StringView& message) { + Environment* env = connection_->env(); + Isolate* isolate = env->isolate(); + HandleScope handle_scope(isolate); + Context::Scope context_scope(env->context()); + + // TODO(joyeecheung): always parse the message so that we can use the id to + // identify ending messages as well as printing the message in the debug + // output when there is an error. + const char* type = connection_->type(); + Debug(env, DebugCategory::INSPECTOR_PROFILER, - "Receive coverage message, ending = %s\n", - ending_ ? "true" : "false"); - if (!ending_) { + "Receive %s profile message, ending = %s\n", + type, + connection_->ending() ? "true" : "false"); + if (!connection_->ending()) { return; } - Isolate* isolate = env()->isolate(); - Local context = env()->context(); - HandleScope handle_scope(isolate); - Context::Scope context_scope(context); - Local result; + + // Convert StringView to a Local. + Local message_str; if (!String::NewFromTwoByte(isolate, message.characters16(), NewStringType::kNormal, message.length()) - .ToLocal(&result)) { - fprintf(stderr, "Failed to covert coverage message\n"); + .ToLocal(&message_str)) { + fprintf(stderr, "Failed to covert %s profile message\n", type); + return; } - WriteCoverage(result); + + connection_->WriteProfile(message_str); } -bool V8CoverageConnection::WriteCoverage(Local message) { - const std::string& directory = env()->coverage_directory(); - CHECK(!directory.empty()); +static bool EnsureDirectory(const std::string& directory, const char* type) { uv_fs_t req; int ret = fs::MKDirpSync(nullptr, &req, directory, 0777, nullptr); uv_fs_req_cleanup(&req); @@ -96,12 +118,16 @@ bool V8CoverageConnection::WriteCoverage(Local message) { char err_buf[128]; uv_err_name_r(ret, err_buf, sizeof(err_buf)); fprintf(stderr, - "%s: Failed to create coverage directory %s\n", + "%s: Failed to create %s profile directory %s\n", err_buf, + type, directory.c_str()); return false; } + return true; +} +std::string V8CoverageConnection::GetFilename() const { std::string thread_id = std::to_string(env()->thread_id()); std::string pid = std::to_string(uv_os_getpid()); std::string timestamp = std::to_string( @@ -113,223 +139,187 @@ bool V8CoverageConnection::WriteCoverage(Local message) { pid.c_str(), timestamp.c_str(), thread_id.c_str()); - std::string target = directory + kPathSeparator + filename; - MaybeLocal result = GetResult(message); - if (result.IsEmpty()) { - return false; - } - return WriteResult(target.c_str(), result.ToLocalChecked()); + return filename; } -MaybeLocal V8CoverageConnection::GetResult(Local message) { - Local context = env()->context(); - Isolate* isolate = env()->isolate(); +static MaybeLocal ParseProfile(Environment* env, + Local message, + const char* type) { + Local context = env->context(); + Isolate* isolate = env->isolate(); + + // Get message.result from the response Local parsed; if (!v8::JSON::Parse(context, message).ToLocal(&parsed) || !parsed->IsObject()) { - fprintf(stderr, "Failed to parse coverage result as JSON object\n"); - return MaybeLocal(); + fprintf(stderr, "Failed to parse %s profile result as JSON object\n", type); + return MaybeLocal(); } Local result_v; if (!parsed.As() ->Get(context, FIXED_ONE_BYTE_STRING(isolate, "result")) .ToLocal(&result_v)) { - fprintf(stderr, "Failed to get result from coverage message\n"); - return MaybeLocal(); + fprintf(stderr, "Failed to get 'result' from %s profile message\n", type); + return MaybeLocal(); } - if (result_v->IsUndefined()) { - fprintf(stderr, "'result' from coverage message is undefined\n"); - return MaybeLocal(); + if (!result_v->IsObject()) { + fprintf( + stderr, "'result' from %s profile message is not an object\n", type); + return MaybeLocal(); } + return result_v.As(); +} + +void V8ProfilerConnection::WriteProfile(Local message) { + Local context = env_->context(); + + // Get message.result from the response. + Local result; + if (!ParseProfile(env_, message, type()).ToLocal(&result)) { + return; + } + // Generate the profile output from the subclass. + Local profile; + if (!GetProfile(result).ToLocal(&profile)) { + return; + } Local result_s; - if (!v8::JSON::Stringify(context, result_v).ToLocal(&result_s)) { - fprintf(stderr, "Failed to stringify coverage result\n"); - return MaybeLocal(); + if (!v8::JSON::Stringify(context, profile).ToLocal(&result_s)) { + fprintf(stderr, "Failed to stringify %s profile result\n", type()); + return; + } + + // Create the directory if necessary. + std::string directory = GetDirectory(); + DCHECK(!directory.empty()); + if (!EnsureDirectory(directory, type())) { + return; } - return result_s; + std::string filename = GetFilename(); + DCHECK(!filename.empty()); + std::string path = directory + kPathSeparator + filename; + + WriteResult(env_, path.c_str(), result_s); +} + +MaybeLocal V8CoverageConnection::GetProfile(Local result) { + return result; +} + +std::string V8CoverageConnection::GetDirectory() const { + return env()->coverage_directory(); } void V8CoverageConnection::Start() { - Debug(env(), - DebugCategory::INSPECTOR_PROFILER, - "Sending Profiler.startPreciseCoverage\n"); - Isolate* isolate = env()->isolate(); - Local enable = FIXED_ONE_BYTE_STRING( - isolate, R"({"id": 1, "method": "Profiler.enable"})"); - Local start = FIXED_ONE_BYTE_STRING(isolate, R"({ - "id": 2, - "method": "Profiler.startPreciseCoverage", - "params": { "callCount": true, "detailed": true } - })"); - DispatchMessage(enable); - DispatchMessage(start); + DispatchMessage("Profiler.enable"); + DispatchMessage("Profiler.startPreciseCoverage", + R"({ "callCount": true, "detailed": true })"); } void V8CoverageConnection::End() { CHECK_EQ(ending_, false); ending_ = true; - Debug(env(), - DebugCategory::INSPECTOR_PROFILER, - "Sending Profiler.takePreciseCoverage\n"); - Isolate* isolate = env()->isolate(); - HandleScope scope(isolate); - Local end = FIXED_ONE_BYTE_STRING(isolate, R"({ - "id": 3, - "method": "Profiler.takePreciseCoverage" - })"); - DispatchMessage(end); + DispatchMessage("Profiler.takePreciseCoverage"); } -void V8CpuProfilerConnection::OnMessage( - const v8_inspector::StringView& message) { - Debug(env(), - DebugCategory::INSPECTOR_PROFILER, - "Receive cpu profiling message, ending = %s\n", - ending_ ? "true" : "false"); - if (!ending_) { - return; - } - Isolate* isolate = env()->isolate(); - HandleScope handle_scope(isolate); - Local context = env()->context(); - Context::Scope context_scope(context); - Local result; - if (!String::NewFromTwoByte(isolate, - message.characters16(), - NewStringType::kNormal, - message.length()) - .ToLocal(&result)) { - fprintf(stderr, "Failed to convert profiling message\n"); - } - WriteCpuProfile(result); +std::string V8CpuProfilerConnection::GetDirectory() const { + return env()->cpu_prof_dir(); } -void V8CpuProfilerConnection::WriteCpuProfile(Local message) { - const std::string& path = env()->cpu_profile_path(); - CHECK(!path.empty()); - std::string directory = path.substr(0, path.find_last_of(kPathSeparator)); - if (directory != path) { - uv_fs_t req; - int ret = fs::MKDirpSync(nullptr, &req, directory, 0777, nullptr); - uv_fs_req_cleanup(&req); - if (ret < 0 && ret != UV_EEXIST) { - char err_buf[128]; - uv_err_name_r(ret, err_buf, sizeof(err_buf)); - fprintf(stderr, - "%s: Failed to create cpu profile directory %s\n", - err_buf, - directory.c_str()); - return; - } - } - MaybeLocal result = GetResult(message); - if (!result.IsEmpty()) { - WriteResult(path.c_str(), result.ToLocalChecked()); - } +std::string V8CpuProfilerConnection::GetFilename() const { + return env()->cpu_prof_name(); } -MaybeLocal V8CpuProfilerConnection::GetResult(Local message) { - Local context = env()->context(); - Isolate* isolate = env()->isolate(); - Local parsed; - if (!v8::JSON::Parse(context, message).ToLocal(&parsed) || - !parsed->IsObject()) { - fprintf(stderr, "Failed to parse CPU profile result as JSON object\n"); - return MaybeLocal(); - } - - Local result_v; - if (!parsed.As() - ->Get(context, FIXED_ONE_BYTE_STRING(isolate, "result")) - .ToLocal(&result_v)) { - fprintf(stderr, "Failed to get result from CPU profile message\n"); - return MaybeLocal(); - } - - if (!result_v->IsObject()) { - fprintf(stderr, "'result' from CPU profile message is not an object\n"); - return MaybeLocal(); - } - +MaybeLocal V8CpuProfilerConnection::GetProfile(Local result) { Local profile_v; - if (!result_v.As() - ->Get(context, FIXED_ONE_BYTE_STRING(isolate, "profile")) + if (!result + ->Get(env()->context(), + FIXED_ONE_BYTE_STRING(env()->isolate(), "profile")) .ToLocal(&profile_v)) { fprintf(stderr, "'profile' from CPU profile result is undefined\n"); - return MaybeLocal(); + return MaybeLocal(); } - - Local result_s; - if (!v8::JSON::Stringify(context, profile_v).ToLocal(&result_s)) { - fprintf(stderr, "Failed to stringify CPU profile result\n"); - return MaybeLocal(); + if (!profile_v->IsObject()) { + fprintf(stderr, "'profile' from CPU profile result is not an Object\n"); + return MaybeLocal(); } - - return result_s; + return profile_v.As(); } void V8CpuProfilerConnection::Start() { - Debug(env(), DebugCategory::INSPECTOR_PROFILER, "Sending Profiler.start\n"); - Isolate* isolate = env()->isolate(); - Local enable = FIXED_ONE_BYTE_STRING( - isolate, R"({"id": 1, "method": "Profiler.enable"})"); - Local start = FIXED_ONE_BYTE_STRING( - isolate, R"({"id": 2, "method": "Profiler.start"})"); - DispatchMessage(enable); - DispatchMessage(start); + DispatchMessage("Profiler.enable"); + DispatchMessage("Profiler.start"); + std::string params = R"({ "interval": )"; + params += std::to_string(env()->cpu_prof_interval()); + params += " }"; + DispatchMessage("Profiler.setSamplingInterval", params.c_str()); } void V8CpuProfilerConnection::End() { CHECK_EQ(ending_, false); ending_ = true; - Debug(env(), DebugCategory::INSPECTOR_PROFILER, "Sending Profiler.stop\n"); - Isolate* isolate = env()->isolate(); - HandleScope scope(isolate); - Local end = - FIXED_ONE_BYTE_STRING(isolate, R"({"id": 3, "method": "Profiler.stop"})"); - DispatchMessage(end); + DispatchMessage("Profiler.stop"); } // For now, we only support coverage profiling, but we may add more // in the future. void EndStartedProfilers(Environment* env) { Debug(env, DebugCategory::INSPECTOR_PROFILER, "EndStartedProfilers\n"); - V8ProfilerConnection* connection = env->coverage_connection(); + V8ProfilerConnection* connection = env->cpu_profiler_connection(); if (connection != nullptr && !connection->ending()) { - Debug( - env, DebugCategory::INSPECTOR_PROFILER, "Ending coverage collection\n"); + Debug(env, DebugCategory::INSPECTOR_PROFILER, "Ending cpu profiling\n"); connection->End(); } - connection = env->cpu_profiler_connection(); + connection = env->coverage_connection(); if (connection != nullptr && !connection->ending()) { - Debug(env, DebugCategory::INSPECTOR_PROFILER, "Ending cpu profiling\n"); + Debug( + env, DebugCategory::INSPECTOR_PROFILER, "Ending coverage collection\n"); connection->End(); } } -void StartCoverageCollection(Environment* env) { - CHECK_NULL(env->coverage_connection()); - env->set_coverage_connection(std::make_unique(env)); - env->coverage_connection()->Start(); +std::string GetCwd() { + char cwd[CWD_BUFSIZE]; + size_t size = CWD_BUFSIZE; + int err = uv_cwd(cwd, &size); + // This can fail if the cwd is deleted. + // TODO(joyeecheung): store this in the Environment during Environment + // creation and fallback to exec_path and argv0, then we no longer need + // SetCoverageDirectory(). + CHECK_EQ(err, 0); + CHECK_GT(size, 0); + return cwd; } -void StartCpuProfiling(Environment* env, const std::string& profile_name) { - std::string path = env->cpu_prof_dir() + std::string(kPathSeparator); - if (profile_name.empty()) { - DiagnosticFilename filename(env, "CPU", "cpuprofile"); - path += *filename; - } else { - path += profile_name; +void StartProfilers(Environment* env) { + Isolate* isolate = env->isolate(); + Local coverage_str = env->env_vars()->Get( + isolate, FIXED_ONE_BYTE_STRING(isolate, "NODE_V8_COVERAGE")); + if (!coverage_str.IsEmpty() && coverage_str->Length() > 0) { + CHECK_NULL(env->coverage_connection()); + env->set_coverage_connection(std::make_unique(env)); + env->coverage_connection()->Start(); + } + if (env->options()->cpu_prof) { + const std::string& dir = env->options()->cpu_prof_dir; + env->set_cpu_prof_interval(env->options()->cpu_prof_interval); + env->set_cpu_prof_dir(dir.empty() ? GetCwd() : dir); + if (env->options()->cpu_prof_name.empty()) { + DiagnosticFilename filename(env, "CPU", "cpuprofile"); + env->set_cpu_prof_name(*filename); + } else { + env->set_cpu_prof_name(env->options()->cpu_prof_name); + } + CHECK_NULL(env->cpu_profiler_connection()); + env->set_cpu_profiler_connection( + std::make_unique(env)); + env->cpu_profiler_connection()->Start(); } - env->set_cpu_profile_path(std::move(path)); - env->set_cpu_profiler_connection( - std::make_unique(env)); - env->cpu_profiler_connection()->Start(); } static void SetCoverageDirectory(const FunctionCallbackInfo& args) { diff --git a/src/inspector_profiler.h b/src/inspector_profiler.h index 7120819c13b070..219405b8c7f3f4 100644 --- a/src/inspector_profiler.h +++ b/src/inspector_profiler.h @@ -24,9 +24,7 @@ class V8ProfilerConnection { : connection_(connection) {} void SendMessageToFrontend( - const v8_inspector::StringView& message) override { - connection_->OnMessage(message); - } + const v8_inspector::StringView& message) override; private: V8ProfilerConnection* connection_; @@ -34,22 +32,40 @@ class V8ProfilerConnection { explicit V8ProfilerConnection(Environment* env); virtual ~V8ProfilerConnection() = default; - Environment* env() { return env_; } + + Environment* env() const { return env_; } + + // Dispatch a protocol message, and returns the id of the message. + // `method` does not need to be surrounded by quotes. + // The optional `params` should be formatted in JSON. + // The strings should be in one byte characters - which is enough for + // the commands we use here. + size_t DispatchMessage(const char* method, const char* params = nullptr); // Use DispatchMessage() to dispatch necessary inspector messages + // to start and end the profiling. virtual void Start() = 0; virtual void End() = 0; - // Override this to respond to the messages sent from the session. - virtual void OnMessage(const v8_inspector::StringView& message) = 0; - virtual bool ending() const = 0; - void DispatchMessage(v8::Local message); - // Write the result to a path - bool WriteResult(const char* path, v8::Local result); + // Return a descriptive name of the profile for debugging. + virtual const char* type() const = 0; + // Return if the profile is ending and the response can be parsed. + virtual bool ending() const = 0; + // Return the directory where the profile should be placed. + virtual std::string GetDirectory() const = 0; + // Return the filename the profile should be written as. + virtual std::string GetFilename() const = 0; + // Return the profile object parsed from `message.result`, + // which will be then written as a JSON. + virtual v8::MaybeLocal GetProfile( + v8::Local result) = 0; private: + size_t next_id() { return id_++; } + void WriteProfile(v8::Local message); std::unique_ptr session_; Environment* env_ = nullptr; + size_t id_ = 1; }; class V8CoverageConnection : public V8ProfilerConnection { @@ -58,14 +74,18 @@ class V8CoverageConnection : public V8ProfilerConnection { void Start() override; void End() override; - void OnMessage(const v8_inspector::StringView& message) override; + + const char* type() const override { return type_.c_str(); } bool ending() const override { return ending_; } + std::string GetDirectory() const override; + std::string GetFilename() const override; + v8::MaybeLocal GetProfile(v8::Local result) override; + private: - bool WriteCoverage(v8::Local message); - v8::MaybeLocal GetResult(v8::Local message); std::unique_ptr session_; bool ending_ = false; + std::string type_ = "coverage"; }; class V8CpuProfilerConnection : public V8ProfilerConnection { @@ -75,15 +95,18 @@ class V8CpuProfilerConnection : public V8ProfilerConnection { void Start() override; void End() override; - void OnMessage(const v8_inspector::StringView& message) override; + + const char* type() const override { return type_.c_str(); } bool ending() const override { return ending_; } - private: - void WriteCpuProfile(v8::Local message); - v8::MaybeLocal GetResult(v8::Local message); + std::string GetDirectory() const override; + std::string GetFilename() const override; + v8::MaybeLocal GetProfile(v8::Local result) override; + private: std::unique_ptr session_; bool ending_ = false; + std::string type_ = "CPU"; }; } // namespace profiler diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index e05163c32f8265..befef0af658511 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -870,7 +870,14 @@ napi_status napi_get_property_names(napi_env env, v8::Local obj; CHECK_TO_OBJECT(env, context, obj, object); - auto maybe_propertynames = obj->GetPropertyNames(context); + v8::MaybeLocal maybe_propertynames = obj->GetPropertyNames( + context, + v8::KeyCollectionMode::kIncludePrototypes, + static_cast( + v8::PropertyFilter::ONLY_ENUMERABLE | + v8::PropertyFilter::SKIP_SYMBOLS), + v8::IndexFilter::kIncludeIndices, + v8::KeyConversionMode::kConvertToString); CHECK_MAYBE_EMPTY(env, maybe_propertynames, napi_generic_failure); diff --git a/src/js_native_api_v8_internals.h b/src/js_native_api_v8_internals.h index dcdc62297f6f59..ddd219818cdfa9 100644 --- a/src/js_native_api_v8_internals.h +++ b/src/js_native_api_v8_internals.h @@ -29,7 +29,7 @@ namespace v8impl { template -using Persistent = node::Persistent; +using Persistent = v8::Global; using PersistentToLocal = node::PersistentToLocal; diff --git a/src/memory_tracker-inl.h b/src/memory_tracker-inl.h index b17b8fbab2cada..da37f72c737607 100644 --- a/src/memory_tracker-inl.h +++ b/src/memory_tracker-inl.h @@ -184,9 +184,9 @@ void MemoryTracker::TrackField(const char* edge_name, TrackField(edge_name, value.Get(isolate_)); } -template +template void MemoryTracker::TrackField(const char* edge_name, - const v8::Persistent& value, + const v8::PersistentBase& value, const char* node_name) { TrackField(edge_name, value.Get(isolate_)); } diff --git a/src/memory_tracker.h b/src/memory_tracker.h index 032c9a984e51d6..d22116918afec8 100644 --- a/src/memory_tracker.h +++ b/src/memory_tracker.h @@ -90,9 +90,9 @@ class CleanupHookCallback; * NonPointerRetainerClass non_pointer_retainer; * InternalClass internal_member_; * std::vector vector_; - * node::Persistent target_; + * v8::Global target_; * - * node::Persistent wrapped_; + * v8::Global wrapped_; * } * * This creates the following graph: @@ -185,9 +185,9 @@ class MemoryTracker { void TrackField(const char* edge_name, const v8::Eternal& value, const char* node_name); - template + template inline void TrackField(const char* edge_name, - const v8::Persistent& value, + const v8::PersistentBase& value, const char* node_name = nullptr); template inline void TrackField(const char* edge_name, diff --git a/src/module_wrap.cc b/src/module_wrap.cc index d6ad0da622476f..a4e81dcc29474b 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -25,6 +25,7 @@ using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; +using v8::Global; using v8::HandleScope; using v8::Integer; using v8::IntegrityLevel; @@ -611,7 +612,7 @@ Maybe GetPackageConfig(Environment* env, env->exports_string()).ToLocal(&exports_v) && (exports_v->IsObject() || exports_v->IsString() || exports_v->IsBoolean())) { - Persistent exports; + Global exports; exports.Reset(env->isolate(), exports_v); auto entry = env->package_json_cache.emplace(path, diff --git a/src/module_wrap.h b/src/module_wrap.h index fddb852a79dd70..6c79781a9d3a78 100644 --- a/src/module_wrap.h +++ b/src/module_wrap.h @@ -75,11 +75,11 @@ class ModuleWrap : public BaseObject { v8::Local referrer); static ModuleWrap* GetFromModule(node::Environment*, v8::Local); - Persistent module_; - Persistent url_; + v8::Global module_; + v8::Global url_; bool linked_ = false; - std::unordered_map> resolve_cache_; - Persistent context_; + std::unordered_map> resolve_cache_; + v8::Global context_; uint32_t id_; }; diff --git a/src/node.cc b/src/node.cc index 636a92eab3f760..d611460f4f2921 100644 --- a/src/node.cc +++ b/src/node.cc @@ -227,21 +227,8 @@ MaybeLocal RunBootstrapping(Environment* env) { Isolate* isolate = env->isolate(); Local context = env->context(); - Local coverage_str = env->env_vars()->Get( - isolate, FIXED_ONE_BYTE_STRING(isolate, "NODE_V8_COVERAGE")); - if (!coverage_str.IsEmpty() && coverage_str->Length() > 0) { #if HAVE_INSPECTOR - profiler::StartCoverageCollection(env); -#else - fprintf(stderr, "NODE_V8_COVERAGE cannot be used without inspector\n"); -#endif // HAVE_INSPECTOR - } - -#if HAVE_INSPECTOR - if (env->options()->cpu_prof) { - env->InitializeCPUProfDir(env->options()->cpu_prof_dir); - profiler::StartCpuProfiling(env, env->options()->cpu_prof_name); - } + profiler::StartProfilers(env); #endif // HAVE_INSPECTOR // Add a reference to the global object diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 58175a8fd5f615..3b4be5a8105f62 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -62,6 +62,7 @@ using v8::ArrayBufferView; using v8::Context; using v8::EscapableHandleScope; using v8::FunctionCallbackInfo; +using v8::Global; using v8::Integer; using v8::Isolate; using v8::Just; @@ -99,7 +100,7 @@ class CallbackInfo { FreeCallback callback, char* data, void* hint); - Persistent persistent_; + Global persistent_; FreeCallback const callback_; char* const data_; void* const hint_; diff --git a/src/node_contextify.h b/src/node_contextify.h index 4186e5190f8ef9..d04bf9ea28efb2 100644 --- a/src/node_contextify.h +++ b/src/node_contextify.h @@ -100,7 +100,7 @@ class ContextifyContext { uint32_t index, const v8::PropertyCallbackInfo& args); Environment* const env_; - Persistent context_; + v8::Global context_; }; class ContextifyScript : public BaseObject { @@ -129,7 +129,7 @@ class ContextifyScript : public BaseObject { inline uint32_t id() { return id_; } private: - node::Persistent script_; + v8::Global script_; uint32_t id_; }; diff --git a/src/node_crypto.h b/src/node_crypto.h index 657789afc42e1f..44206b58ddd6bf 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -321,8 +321,8 @@ class SSLWrap { ClientHelloParser hello_parser_; - Persistent ocsp_response_; - Persistent sni_context_; + v8::Global ocsp_response_; + v8::Global sni_context_; friend class SecureContext; }; diff --git a/src/node_file.h b/src/node_file.h index f5c523fb0708cc..b417d4916f8c35 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -451,8 +451,8 @@ class FileHandle : public AsyncWrap, public StreamBase { CloseReq& operator=(const CloseReq&&) = delete; private: - Persistent promise_{}; - Persistent ref_{}; + v8::Global promise_{}; + v8::Global ref_{}; }; // Asynchronous close diff --git a/src/node_http_parser_impl.h b/src/node_http_parser_impl.h index a8a8db554783fb..a354c6fcc51eba 100644 --- a/src/node_http_parser_impl.h +++ b/src/node_http_parser_impl.h @@ -154,14 +154,10 @@ struct StringPtr { class Parser : public AsyncWrap, public StreamListener { public: - Parser(Environment* env, Local wrap, parser_type_t type) - : AsyncWrap(env, wrap, - type == HTTP_REQUEST ? - AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE : - AsyncWrap::PROVIDER_HTTPCLIENTREQUEST), + Parser(Environment* env, Local wrap) + : AsyncWrap(env, wrap), current_buffer_len_(0), current_buffer_data_(nullptr) { - Init(type); } @@ -426,11 +422,7 @@ class Parser : public AsyncWrap, public StreamListener { static void New(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - CHECK(args[0]->IsInt32()); - parser_type_t type = - static_cast(args[0].As()->Value()); - CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE); - new Parser(env, args.This(), type); + new Parser(env, args.This()); } @@ -443,14 +435,13 @@ class Parser : public AsyncWrap, public StreamListener { static void Free(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder()); // Since the Parser destructor isn't going to run the destroy() callbacks // it needs to be triggered manually. parser->EmitTraceEventDestroy(); - parser->EmitDestroy(env, parser->get_async_id()); + parser->EmitDestroy(); } @@ -526,6 +517,7 @@ class Parser : public AsyncWrap, public StreamListener { : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST); parser->set_provider_type(provider); + parser->AsyncReset(args[1].As()); parser->Init(type); } diff --git a/src/node_internals.h b/src/node_internals.h index fc924e3e1637ce..5e99ac4c66a38d 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -28,7 +28,6 @@ #include "node.h" #include "node_binding.h" #include "node_mutex.h" -#include "node_persistent.h" #include "tracing/trace_event.h" #include "util-inl.h" #include "uv.h" @@ -325,8 +324,7 @@ void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params); #if HAVE_INSPECTOR namespace profiler { -void StartCoverageCollection(Environment* env); -void StartCpuProfiling(Environment* env, const std::string& profile_name); +void StartProfilers(Environment* env); void EndStartedProfilers(Environment* env); } #endif // HAVE_INSPECTOR diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 2719b49e976ff6..04ad277b8e825b 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -65,13 +65,12 @@ class NodeMainInstance { static v8::StartupData* GetEmbeddedSnapshotBlob(); static const size_t kNodeContextIndex = 0; - - private: NodeMainInstance(const NodeMainInstance&) = delete; NodeMainInstance& operator=(const NodeMainInstance&) = delete; NodeMainInstance(NodeMainInstance&&) = delete; NodeMainInstance& operator=(NodeMainInstance&&) = delete; + private: NodeMainInstance(v8::Isolate* isolate, uv_loop_t* event_loop, MultiIsolatePlatform* platform, diff --git a/src/node_native_module.h b/src/node_native_module.h index bbd4d89c4001cd..5450c63c161cf2 100644 --- a/src/node_native_module.h +++ b/src/node_native_module.h @@ -27,14 +27,16 @@ using NativeModuleCacheMap = // the its own singleton - that should be encapsulated in NativeModuleEnv // instead. class NativeModuleLoader { + public: + NativeModuleLoader(const NativeModuleLoader&) = delete; + NativeModuleLoader& operator=(const NativeModuleLoader&) = delete; + private: // Only allow access from friends. friend class NativeModuleEnv; friend class CodeCacheBuilder; NativeModuleLoader(); - NativeModuleLoader(const NativeModuleLoader&) = delete; - NativeModuleLoader& operator=(const NativeModuleLoader&) = delete; static NativeModuleLoader* GetInstance(); // Generated by tools/js2c.py as node_javascript.cc diff --git a/src/node_options.cc b/src/node_options.cc index adc6f61586853b..a36666c3e0f452 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -148,6 +148,11 @@ void EnvironmentOptions::CheckOptions(std::vector* errors) { errors->push_back("invalid value for --unhandled-rejections"); } + if (tls_min_v1_3 && tls_max_v1_2) { + errors->push_back("either --tls-min-v1.3 or --tls-max-v1.2 can be " + "used, not both"); + } + #if HAVE_INSPECTOR if (!cpu_prof) { if (!cpu_prof_name.empty()) { @@ -156,6 +161,11 @@ void EnvironmentOptions::CheckOptions(std::vector* errors) { if (!cpu_prof_dir.empty()) { errors->push_back("--cpu-prof-dir must be used with --cpu-prof"); } + // We can't catch the case where the value passed is the default value, + // then the option just becomes a noop which is fine. + if (cpu_prof_interval != kDefaultCpuProfInterval) { + errors->push_back("--cpu-prof-interval must be used with --cpu-prof"); + } } debug_options_.CheckOptions(errors); @@ -351,6 +361,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "specified file name of the V8 CPU profile generated with " "--cpu-prof", &EnvironmentOptions::cpu_prof_name); + AddOption("--cpu-prof-interval", + "specified sampling interval in microseconds for the V8 CPU " + "profile generated with --cpu-prof. (default: 1000)", + &EnvironmentOptions::cpu_prof_interval); AddOption("--cpu-prof-dir", "Directory where the V8 profiles generated by --cpu-prof will be " "placed. Does not affect --prof.", @@ -373,6 +387,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "first tick", &EnvironmentOptions::trace_sync_io, kAllowedInEnvironment); + AddOption("--trace-tls", + "prints TLS packet trace information to stderr", + &EnvironmentOptions::trace_tls, + kAllowedInEnvironment); AddOption("--trace-warnings", "show stack traces on process warnings", &EnvironmentOptions::trace_warnings, @@ -424,6 +442,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "set default TLS minimum to TLSv1.1 (default: TLSv1.2)", &EnvironmentOptions::tls_min_v1_1, kAllowedInEnvironment); + AddOption("--tls-min-v1.2", + "set default TLS minimum to TLSv1.2 (default: TLSv1.2)", + &EnvironmentOptions::tls_min_v1_2, + kAllowedInEnvironment); AddOption("--tls-min-v1.3", "set default TLS minimum to TLSv1.3 (default: TLSv1.2)", &EnvironmentOptions::tls_min_v1_3, diff --git a/src/node_options.h b/src/node_options.h index 3b2513a183bc1b..db564ddb3d3e6d 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -111,6 +111,8 @@ class EnvironmentOptions : public Options { bool prof_process = false; #if HAVE_INSPECTOR std::string cpu_prof_dir; + static const uint64_t kDefaultCpuProfInterval = 1000; + uint64_t cpu_prof_interval = kDefaultCpuProfInterval; std::string cpu_prof_name; bool cpu_prof = false; #endif // HAVE_INSPECTOR @@ -118,6 +120,7 @@ class EnvironmentOptions : public Options { bool throw_deprecation = false; bool trace_deprecation = false; bool trace_sync_io = false; + bool trace_tls = false; bool trace_warnings = false; std::string unhandled_rejections; std::string userland_loader; @@ -133,6 +136,7 @@ class EnvironmentOptions : public Options { bool tls_min_v1_0 = false; bool tls_min_v1_1 = false; + bool tls_min_v1_2 = false; bool tls_min_v1_3 = false; bool tls_max_v1_2 = false; bool tls_max_v1_3 = false; diff --git a/src/node_persistent.h b/src/node_persistent.h deleted file mode 100644 index 6126ebc6c20fd5..00000000000000 --- a/src/node_persistent.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef SRC_NODE_PERSISTENT_H_ -#define SRC_NODE_PERSISTENT_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include "v8.h" - -namespace node { - -template -struct ResetInDestructorPersistentTraits { - static const bool kResetInDestructor = true; - template - // Disallow copy semantics by leaving this unimplemented. - inline static void Copy( - const v8::Persistent&, - v8::Persistent>*); -}; - -// v8::Persistent does not reset the object slot in its destructor. That is -// acknowledged as a flaw in the V8 API and expected to change in the future -// but for now node::Persistent is the easier and safer alternative. -template -using Persistent = v8::Persistent>; - -class PersistentToLocal { - public: - // If persistent.IsWeak() == false, then do not call persistent.Reset() - // while the returned Local is still in scope, it will destroy the - // reference to the object. - template - static inline v8::Local Default( - v8::Isolate* isolate, - const Persistent& persistent) { - if (persistent.IsWeak()) { - return PersistentToLocal::Weak(isolate, persistent); - } else { - return PersistentToLocal::Strong(persistent); - } - } - - // Unchecked conversion from a non-weak Persistent to Local, - // use with care! - // - // Do not call persistent.Reset() while the returned Local is still in - // scope, it will destroy the reference to the object. - template - static inline v8::Local Strong( - const Persistent& persistent) { - return *reinterpret_cast*>( - const_cast*>(&persistent)); - } - - template - static inline v8::Local Weak( - v8::Isolate* isolate, - const Persistent& persistent) { - return v8::Local::New(isolate, persistent); - } -}; - -} // namespace node - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_NODE_PERSISTENT_H_ diff --git a/src/node_report.cc b/src/node_report.cc index 8a257b0c9c6ef4..d917a772812b27 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -231,7 +231,7 @@ static void WriteNodeReport(Isolate* isolate, // Report out the command line. if (!node::per_process::cli_options->cmdline.empty()) { writer.json_arraystart("commandLine"); - for (std::string arg : node::per_process::cli_options->cmdline) { + for (const std::string& arg : node::per_process::cli_options->cmdline) { writer.json_element(arg); } writer.json_arrayend(); diff --git a/src/node_util.cc b/src/node_util.cc index 961df0b73c3deb..0c498e2838c4fd 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -13,6 +13,7 @@ using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; +using v8::Global; using v8::IndexFilter; using v8::Integer; using v8::Isolate; @@ -57,6 +58,16 @@ static void GetOwnNonIndexProperties( args.GetReturnValue().Set(properties); } +static void GetConstructorName( + const FunctionCallbackInfo& args) { + CHECK(args[0]->IsObject()); + + Local object = args[0].As(); + Local name = object->GetConstructorName(); + + args.GetReturnValue().Set(name); +} + static void GetPromiseDetails(const FunctionCallbackInfo& args) { // Return undefined if it's not a Promise. if (!args[0]->IsPromise()) @@ -189,7 +200,7 @@ class WeakReference : public BaseObject { SET_NO_MEMORY_INFO() private: - Persistent target_; + Global target_; }; static void GuessHandleType(const FunctionCallbackInfo& args) { @@ -261,6 +272,7 @@ void Initialize(Local target, env->SetMethodNoSideEffect(target, "previewEntries", PreviewEntries); env->SetMethodNoSideEffect(target, "getOwnNonIndexProperties", GetOwnNonIndexProperties); + env->SetMethodNoSideEffect(target, "getConstructorName", GetConstructorName); env->SetMethod(target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer); Local constants = Object::New(env->isolate()); diff --git a/src/node_version.h b/src/node_version.h index 4912fb947d5ffe..4cf3217f84ef77 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,13 +23,13 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 12 -#define NODE_MINOR_VERSION 1 -#define NODE_PATCH_VERSION 1 +#define NODE_MINOR_VERSION 2 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_LTS 0 #define NODE_VERSION_LTS_CODENAME "" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) diff --git a/src/node_worker.cc b/src/node_worker.cc index c1a1123ef1399e..f9b675e96ad1f1 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -2,6 +2,7 @@ #include "debug_utils.h" #include "node_errors.h" #include "node_buffer.h" +#include "node_options-inl.h" #include "node_perf.h" #include "util.h" #include "async_wrap-inl.h" diff --git a/src/node_zlib.cc b/src/node_zlib.cc index b5abcfa5850833..f389257882215e 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -47,6 +47,7 @@ using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; +using v8::Global; using v8::HandleScope; using v8::Int32; using v8::Integer; @@ -526,7 +527,7 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork { bool closed_ = false; unsigned int refs_ = 0; uint32_t* write_result_ = nullptr; - Persistent write_js_callback_; + Global write_js_callback_; std::atomic unreported_allocations_{0}; size_t zlib_memory_ = 0; diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index a034dd42a6e351..4c5d002295644b 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -912,6 +912,29 @@ void TLSWrap::EnableSessionCallbacks( wrap); } +// Check required capabilities were not excluded from the OpenSSL build: +// - OPENSSL_NO_SSL_TRACE excludes SSL_trace() +// - OPENSSL_NO_STDIO excludes BIO_new_fp() +// HAVE_SSL_TRACE is available on the internal tcp_wrap binding for the tests. +#if defined(OPENSSL_NO_SSL_TRACE) || defined(OPENSSL_NO_STDIO) +# define HAVE_SSL_TRACE 0 +#else +# define HAVE_SSL_TRACE 1 +#endif + +void TLSWrap::EnableTrace( + const FunctionCallbackInfo& args) { + TLSWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); + +#if HAVE_SSL_TRACE + if (wrap->ssl_) { + BIO* b = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT); + SSL_set_msg_callback(wrap->ssl_.get(), SSL_trace); + SSL_set_msg_callback_arg(wrap->ssl_.get(), b); + } +#endif +} void TLSWrap::DestroySSL(const FunctionCallbackInfo& args) { TLSWrap* wrap; @@ -1057,6 +1080,8 @@ void TLSWrap::Initialize(Local target, env->SetMethod(target, "wrap", TLSWrap::Wrap); + NODE_DEFINE_CONSTANT(target, HAVE_SSL_TRACE); + Local t = BaseObject::MakeLazilyInitializedJSTemplate(env); Local tlsWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "TLSWrap"); @@ -1080,6 +1105,7 @@ void TLSWrap::Initialize(Local target, env->SetProtoMethod(t, "start", Start); env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode); env->SetProtoMethod(t, "enableSessionCallbacks", EnableSessionCallbacks); + env->SetProtoMethod(t, "enableTrace", EnableTrace); env->SetProtoMethod(t, "destroySSL", DestroySSL); env->SetProtoMethod(t, "enableCertCb", EnableCertCb); diff --git a/src/tls_wrap.h b/src/tls_wrap.h index 85a53f236df5c9..41e16ea9ac95a6 100644 --- a/src/tls_wrap.h +++ b/src/tls_wrap.h @@ -160,6 +160,7 @@ class TLSWrap : public AsyncWrap, static void SetVerifyMode(const v8::FunctionCallbackInfo& args); static void EnableSessionCallbacks( const v8::FunctionCallbackInfo& args); + static void EnableTrace(const v8::FunctionCallbackInfo& args); static void EnableCertCb(const v8::FunctionCallbackInfo& args); static void DestroySSL(const v8::FunctionCallbackInfo& args); static void GetServername(const v8::FunctionCallbackInfo& args); diff --git a/src/util.h b/src/util.h index 3a6cef2e3524a4..c9c605685070ff 100644 --- a/src/util.h +++ b/src/util.h @@ -24,7 +24,6 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "node_persistent.h" #include "v8.h" #include @@ -669,6 +668,44 @@ class SlicedArguments : public MaybeStackBuffer> { const v8::FunctionCallbackInfo& args, size_t start = 0); }; +// Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra +// optimization for strong persistent handles. +class PersistentToLocal { + public: + // If persistent.IsWeak() == false, then do not call persistent.Reset() + // while the returned Local is still in scope, it will destroy the + // reference to the object. + template + static inline v8::Local Default( + v8::Isolate* isolate, + const v8::PersistentBase& persistent) { + if (persistent.IsWeak()) { + return PersistentToLocal::Weak(isolate, persistent); + } else { + return PersistentToLocal::Strong(persistent); + } + } + + // Unchecked conversion from a non-weak Persistent to Local, + // use with care! + // + // Do not call persistent.Reset() while the returned Local is still in + // scope, it will destroy the reference to the object. + template + static inline v8::Local Strong( + const v8::PersistentBase& persistent) { + return *reinterpret_cast*>( + const_cast*>(&persistent)); + } + + template + static inline v8::Local Weak( + v8::Isolate* isolate, + const v8::PersistentBase& persistent) { + return v8::Local::New(isolate, persistent); + } +}; + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/test/addons/openssl-client-cert-engine/test.js b/test/addons/openssl-client-cert-engine/test.js index 1320e7b945d66d..9e7d507b07b7ac 100644 --- a/test/addons/openssl-client-cert-engine/test.js +++ b/test/addons/openssl-client-cert-engine/test.js @@ -29,10 +29,10 @@ const serverOptions = { rejectUnauthorized: true }; -const server = https.createServer(serverOptions, (req, res) => { +const server = https.createServer(serverOptions, common.mustCall((req, res) => { res.writeHead(200); res.end('hello world'); -}).listen(0, common.localhostIPv4, () => { +})).listen(0, common.localhostIPv4, common.mustCall(() => { const clientOptions = { method: 'GET', host: common.localhostIPv4, @@ -57,4 +57,4 @@ const server = https.createServer(serverOptions, (req, res) => { })); req.end(); -}); +})); diff --git a/test/async-hooks/coverage.md b/test/async-hooks/coverage.md index 0a2af0d06bfd62..1ba18a938330a9 100644 --- a/test/async-hooks/coverage.md +++ b/test/async-hooks/coverage.md @@ -9,7 +9,8 @@ Showing which kind of async resource is covered by which test: | FSREQCALLBACK | test-fsreqcallback-{access,readFile}.js | | GETADDRINFOREQWRAP | test-getaddrinforeqwrap.js | | GETNAMEINFOREQWRAP | test-getnameinforeqwrap.js | -| HTTPPARSER | test-httpparser.{request,response}.js | +| HTTPINCOMINGMESSAGE | test-httpparser.request.js | +| HTTPCLIENTREQUEST | test-httpparser.response.js | | Immediate | test-immediate.js | | JSSTREAM | TODO (crashes when accessing directly) | | PBKDF2REQUEST | test-crypto-pbkdf2.js | diff --git a/test/async-hooks/test-graph.http.js b/test/async-hooks/test-graph.http.js index 3461974ef9c477..55b9b055a0f050 100644 --- a/test/async-hooks/test-graph.http.js +++ b/test/async-hooks/test-graph.http.js @@ -35,13 +35,13 @@ process.on('exit', function() { { type: 'TCPCONNECTWRAP', id: 'tcpconnect:1', triggerAsyncId: 'tcp:1' }, - { type: 'HTTPPARSER', - id: 'httpparser:1', + { type: 'HTTPCLIENTREQUEST', + id: 'httpclientrequest:1', triggerAsyncId: 'tcpserver:1' }, { type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: 'tcpserver:1' }, { type: 'Timeout', id: 'timeout:1', triggerAsyncId: 'tcp:2' }, - { type: 'HTTPPARSER', - id: 'httpparser:2', + { type: 'HTTPINCOMINGMESSAGE', + id: 'httpincomingmessage:1', triggerAsyncId: 'tcp:2' }, { type: 'Timeout', id: 'timeout:2', diff --git a/test/async-hooks/test-graph.tls-write.js b/test/async-hooks/test-graph.tls-write.js index 580264316dea90..5aee38e6b6841a 100644 --- a/test/async-hooks/test-graph.tls-write.js +++ b/test/async-hooks/test-graph.tls-write.js @@ -64,12 +64,8 @@ function onexit() { id: 'getaddrinforeq:1', triggerAsyncId: 'tls:1' }, { type: 'TCPCONNECTWRAP', id: 'tcpconnect:1', triggerAsyncId: 'tcp:1' }, - { type: 'WRITEWRAP', id: 'write:1', triggerAsyncId: 'tcpconnect:1' }, { type: 'TCPWRAP', id: 'tcp:2', triggerAsyncId: 'tcpserver:1' }, { type: 'TLSWRAP', id: 'tls:2', triggerAsyncId: 'tcpserver:1' }, - { type: 'WRITEWRAP', id: 'write:2', triggerAsyncId: null }, - { type: 'WRITEWRAP', id: 'write:3', triggerAsyncId: null }, - { type: 'WRITEWRAP', id: 'write:4', triggerAsyncId: null }, { type: 'Immediate', id: 'immediate:1', triggerAsyncId: 'tcp:2' }, { type: 'Immediate', id: 'immediate:2', triggerAsyncId: 'tcp:1' }, ] diff --git a/test/async-hooks/test-httparser-reuse.js b/test/async-hooks/test-httparser-reuse.js index b6d82d7d5e9087..06441562e05aa8 100644 --- a/test/async-hooks/test-httparser-reuse.js +++ b/test/async-hooks/test-httparser-reuse.js @@ -1,28 +1,54 @@ 'use strict'; const common = require('../common'); -const http = require('http'); const assert = require('assert'); const { createHook } = require('async_hooks'); +const http = require('http'); + +// Verify that resource emitted for an HTTPParser is not reused. +// Verify that correct create/destroy events are emitted. + const reused = Symbol('reused'); -let reusedHTTPParser = false; -const asyncHook = createHook({ +const reusedParser = []; +const incomingMessageParser = []; +const clientRequestParser = []; +const dupDestroys = []; +const destroyed = []; + +createHook({ init(asyncId, type, triggerAsyncId, resource) { + switch (type) { + case 'HTTPINCOMINGMESSAGE': + incomingMessageParser.push(asyncId); + break; + case 'HTTPCLIENTREQUEST': + clientRequestParser.push(asyncId); + break; + } + if (resource[reused]) { - reusedHTTPParser = true; + reusedParser.push( + `resource reused: ${asyncId}, ${triggerAsyncId}, ${type}` + ); } resource[reused] = true; + }, + destroy(asyncId) { + if (destroyed.includes(asyncId)) { + dupDestroys.push(asyncId); + } else { + destroyed.push(asyncId); + } } -}); -asyncHook.enable(); +}).enable(); -const server = http.createServer(function(req, res) { +const server = http.createServer((req, res) => { res.end(); }); const PORT = 3000; -const url = 'http://127.0.0.1:' + PORT; +const url = `http://127.0.0.1:${PORT}`; server.listen(PORT, common.mustCall(() => { http.get(url, common.mustCall(() => { @@ -30,10 +56,21 @@ server.listen(PORT, common.mustCall(() => { server.listen(PORT, common.mustCall(() => { http.get(url, common.mustCall(() => { server.close(common.mustCall(() => { - assert.strictEqual(reusedHTTPParser, false); + setTimeout(common.mustCall(verify), 200); })); })); })); })); })); })); + +function verify() { + assert.strictEqual(reusedParser.length, 0); + + assert.strictEqual(incomingMessageParser.length, 2); + assert.strictEqual(clientRequestParser.length, 2); + + assert.strictEqual(dupDestroys.length, 0); + incomingMessageParser.forEach((id) => assert.ok(destroyed.includes(id))); + clientRequestParser.forEach((id) => assert.ok(destroyed.includes(id))); +} diff --git a/test/async-hooks/test-httpparser.request.js b/test/async-hooks/test-httpparser.request.js index 7ba8feefe34d5d..f4552398d38e8f 100644 --- a/test/async-hooks/test-httpparser.request.js +++ b/test/async-hooks/test-httpparser.request.js @@ -20,7 +20,8 @@ const request = Buffer.from( 'GET /hello HTTP/1.1\r\n\r\n' ); -const parser = new HTTPParser(REQUEST); +const parser = new HTTPParser(); +parser.initialize(REQUEST, {}); const as = hooks.activitiesOfTypes('HTTPINCOMINGMESSAGE'); const httpparser = as[0]; diff --git a/test/async-hooks/test-httpparser.response.js b/test/async-hooks/test-httpparser.response.js index 85d6f76525d49b..a207a62636f291 100644 --- a/test/async-hooks/test-httpparser.response.js +++ b/test/async-hooks/test-httpparser.response.js @@ -25,7 +25,8 @@ const request = Buffer.from( 'pong' ); -const parser = new HTTPParser(RESPONSE); +const parser = new HTTPParser(); +parser.initialize(RESPONSE, {}); const as = hooks.activitiesOfTypes('HTTPCLIENTREQUEST'); const httpparser = as[0]; diff --git a/test/async-hooks/verify-graph.js b/test/async-hooks/verify-graph.js index d1e09f92bc4adf..1b188faa149b21 100644 --- a/test/async-hooks/verify-graph.js +++ b/test/async-hooks/verify-graph.js @@ -98,6 +98,18 @@ module.exports = function verifyGraph(hooks, graph) { ); } assert.strictEqual(errors.length, 0); + + // Verify that all expected types are present + const expTypes = Object.create(null); + for (let i = 0; i < graph.length; i++) { + if (expTypes[graph[i].type] == null) expTypes[graph[i].type] = 0; + expTypes[graph[i].type]++; + } + + for (const type in expTypes) { + assert.strictEqual(typeSeen[type], expTypes[type], + `Expecting type '${type}' in graph`); + } }; // diff --git a/test/benchmark/test-benchmark-misc.js b/test/benchmark/test-benchmark-misc.js index b88415280833bc..13bd41e54016f5 100644 --- a/test/benchmark/test-benchmark-misc.js +++ b/test/benchmark/test-benchmark-misc.js @@ -10,6 +10,7 @@ runBenchmark('misc', [ 'method=', 'n=1', 'type=', + 'code=1', 'val=magyarország.icom.museum', 'script=test/fixtures/semicolon', 'mode=worker' diff --git a/test/common/README.md b/test/common/README.md index 0542c38bbcb419..391b753f0481df 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -4,15 +4,20 @@ This directory contains modules used to test the Node.js implementation. ## Table of Contents +* [ArrayStream module](#arraystream-module) * [Benchmark module](#benchmark-module) * [Common module API](#common-module-api) * [Countdown module](#countdown-module) * [DNS module](#dns-module) * [Duplex pair helper](#duplex-pair-helper) +* [Environment variables](#environment-variables) * [Fixtures module](#fixtures-module) * [Heap dump checker module](#heap-dump-checker-module) +* [hijackstdio module](#hijackstdio-module) * [HTTP2 module](#http2-module) * [Internet module](#internet-module) +* [ongc module](#ongc-module) +* [Report module](#report-module) * [tick module](#tick-module) * [tmpdir module](#tmpdir-module) * [WPT module](#wpt-module) @@ -495,6 +500,26 @@ which returns an object `{ clientSide, serverSide }` where each side is a There is no difference between client or server side beyond their names. +## Environment variables + +The behavior of the Node.js test suite can be altered using the following +environment variables. + +### NODE_COMMON_PORT + +If set, `NODE_COMMON_PORT`'s value overrides the `common.PORT` default value of +12346. + +### NODE_SKIP_FLAG_CHECK + +If set, command line arguments passed to individual tests are not validated. + +### NODE_TEST_KNOWN_GLOBALS + +A comma-separated list of variables names that are appended to the global +variable whitelist. Alternatively, if `NODE_TEST_KNOWN_GLOBALS` is set to `'0'`, +global leak detection is disabled. + ## Fixtures Module The `common/fixtures` module provides convenience methods for working with @@ -780,6 +805,33 @@ a full `setImmediate()` invocation passes. `listener` is an object to make it easier to use a closure; the target object should not be in scope when `listener.ongc()` is created. +## Report Module + +The `report` module provides helper functions for testing diagnostic reporting +functionality. + +### findReports(pid, dir) + +* `pid` [<number>] Process ID to retrieve diagnostic report files for. +* `dir` [<string>] Directory to search for diagnostic report files. +* return [<Array>] + +Returns an array of diagnotic report file names found in `dir`. The files should +have been generated by a process whose PID matches `pid`. + +### validate(report) + +* `report` [<string>] Diagnostic report file name to validate. + +Validates the schema of a diagnostic report file whose path is specified in +`report`. If the report fails validation, an exception is thrown. + +### validateContent(data) + +* `data` [<string>] Contents of a diagnostic report file. + +Validates the schema of a diagnostic report whose content is specified in +`data`. If the report fails validation, an exception is thrown. ## tick Module diff --git a/test/es-module/test-esm-basic-imports.mjs b/test/es-module/test-esm-basic-imports.mjs index d9bb22be0a5f12..c21804d78b292b 100644 --- a/test/es-module/test-esm-basic-imports.mjs +++ b/test/es-module/test-esm-basic-imports.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import assert from 'assert'; import ok from '../fixtures/es-modules/test-esm-ok.mjs'; diff --git a/test/es-module/test-esm-cyclic-dynamic-import.mjs b/test/es-module/test-esm-cyclic-dynamic-import.mjs index a207efc73ecb0a..03d405baf3ce9c 100644 --- a/test/es-module/test-esm-cyclic-dynamic-import.mjs +++ b/test/es-module/test-esm-cyclic-dynamic-import.mjs @@ -1,4 +1,3 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import('./test-esm-cyclic-dynamic-import.mjs'); diff --git a/test/es-module/test-esm-double-encoding.mjs b/test/es-module/test-esm-double-encoding.mjs index 9366d4bd6bcc68..2edfc8add5d2db 100644 --- a/test/es-module/test-esm-double-encoding.mjs +++ b/test/es-module/test-esm-double-encoding.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; // Assert we can import files with `%` in their pathname. diff --git a/test/es-module/test-esm-encoded-path.mjs b/test/es-module/test-esm-encoded-path.mjs index 2cabfdacff3954..efb681ef0b4dfe 100644 --- a/test/es-module/test-esm-encoded-path.mjs +++ b/test/es-module/test-esm-encoded-path.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import assert from 'assert'; // ./test-esm-ok.mjs diff --git a/test/es-module/test-esm-forbidden-globals.mjs b/test/es-module/test-esm-forbidden-globals.mjs index cf110ff2900eff..b66f278a8a9bb8 100644 --- a/test/es-module/test-esm-forbidden-globals.mjs +++ b/test/es-module/test-esm-forbidden-globals.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; // eslint-disable-next-line no-undef diff --git a/test/es-module/test-esm-import-meta.mjs b/test/es-module/test-esm-import-meta.mjs index 4c34b337fb8914..54c14a44f5e281 100644 --- a/test/es-module/test-esm-import-meta.mjs +++ b/test/es-module/test-esm-import-meta.mjs @@ -1,6 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ - import '../common/index.mjs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-json-cache.mjs b/test/es-module/test-esm-json-cache.mjs index ecd27c5488c7dc..d1fee4f444c2c0 100644 --- a/test/es-module/test-esm-json-cache.mjs +++ b/test/es-module/test-esm-json-cache.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules --experimental-json-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import { strictEqual, deepStrictEqual } from 'assert'; diff --git a/test/es-module/test-esm-json.mjs b/test/es-module/test-esm-json.mjs index b140d031cae8be..3d246124a9bdae 100644 --- a/test/es-module/test-esm-json.mjs +++ b/test/es-module/test-esm-json.mjs @@ -1,6 +1,4 @@ // Flags: --experimental-modules --experimental-json-modules -/* eslint-disable node-core/required-modules */ - import '../common/index.mjs'; import { strictEqual } from 'assert'; diff --git a/test/es-module/test-esm-live-binding.mjs b/test/es-module/test-esm-live-binding.mjs index 880a6c389b422c..5858b13bb51861 100644 --- a/test/es-module/test-esm-live-binding.mjs +++ b/test/es-module/test-esm-live-binding.mjs @@ -1,6 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ - import '../common/index.mjs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-loader-invalid-format.mjs b/test/es-module/test-esm-loader-invalid-format.mjs index c3f3a874079fa7..e4e4e30f5cc2e8 100644 --- a/test/es-module/test-esm-loader-invalid-format.mjs +++ b/test/es-module/test-esm-loader-invalid-format.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-invalid-format.mjs -/* eslint-disable node-core/required-modules */ import { expectsError, mustCall } from '../common/index.mjs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-loader-invalid-url.mjs b/test/es-module/test-esm-loader-invalid-url.mjs index 9cf17b2478ef13..44bacf9347c840 100644 --- a/test/es-module/test-esm-loader-invalid-url.mjs +++ b/test/es-module/test-esm-loader-invalid-url.mjs @@ -1,6 +1,4 @@ // Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-invalid-url.mjs -/* eslint-disable node-core/required-modules */ - import { expectsError, mustCall } from '../common/index.mjs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs b/test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs index ab2da7adcedb52..50fbf0c83ecea9 100644 --- a/test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs +++ b/test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs @@ -1,6 +1,4 @@ // Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/missing-dynamic-instantiate-hook.mjs -/* eslint-disable node-core/required-modules */ - import { expectsError } from '../common/index.mjs'; import('test').catch(expectsError({ diff --git a/test/es-module/test-esm-main-lookup.mjs b/test/es-module/test-esm-main-lookup.mjs index 19c025beab9ea9..cbc6424dd2ff1c 100644 --- a/test/es-module/test-esm-main-lookup.mjs +++ b/test/es-module/test-esm-main-lookup.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-named-exports.mjs b/test/es-module/test-esm-named-exports.mjs index e235f598cb1d34..8b7c429b3d802d 100644 --- a/test/es-module/test-esm-named-exports.mjs +++ b/test/es-module/test-esm-named-exports.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import { readFile } from 'fs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-namespace.mjs b/test/es-module/test-esm-namespace.mjs index 38b7ef12d585fc..07c58cd2dc99c8 100644 --- a/test/es-module/test-esm-namespace.mjs +++ b/test/es-module/test-esm-namespace.mjs @@ -1,6 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ - import '../common/index.mjs'; import * as fs from 'fs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-process.mjs b/test/es-module/test-esm-process.mjs index 3a23573d33b8b1..a2b0d31f1efa27 100644 --- a/test/es-module/test-esm-process.mjs +++ b/test/es-module/test-esm-process.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import assert from 'assert'; import process from 'process'; diff --git a/test/es-module/test-esm-require-cache.mjs b/test/es-module/test-esm-require-cache.mjs index 09030e0578e8c5..8c126c39e0eefe 100644 --- a/test/es-module/test-esm-require-cache.mjs +++ b/test/es-module/test-esm-require-cache.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import { createRequire } from '../common/index.mjs'; import assert from 'assert'; // diff --git a/test/es-module/test-esm-shared-loader-dep.mjs b/test/es-module/test-esm-shared-loader-dep.mjs index b8953ab1ec1a72..00ba1ec31a226a 100644 --- a/test/es-module/test-esm-shared-loader-dep.mjs +++ b/test/es-module/test-esm-shared-loader-dep.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-shared-dep.mjs -/* eslint-disable node-core/required-modules */ import { createRequire } from '../common/index.mjs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-shebang.mjs b/test/es-module/test-esm-shebang.mjs index 486e04dadece61..1d22551bd7a4be 100644 --- a/test/es-module/test-esm-shebang.mjs +++ b/test/es-module/test-esm-shebang.mjs @@ -1,6 +1,5 @@ #! }]) // isn't js // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; const isJs = true; diff --git a/test/es-module/test-esm-snapshot.mjs b/test/es-module/test-esm-snapshot.mjs index 3997e24ed703c6..99767f10e2846e 100644 --- a/test/es-module/test-esm-snapshot.mjs +++ b/test/es-module/test-esm-snapshot.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import '../fixtures/es-modules/esm-snapshot-mutator.js'; import one from '../fixtures/es-modules/esm-snapshot.js'; diff --git a/test/es-module/test-esm-throw-undefined.mjs b/test/es-module/test-esm-throw-undefined.mjs index 97e917da5e8d44..4c091e61532640 100644 --- a/test/es-module/test-esm-throw-undefined.mjs +++ b/test/es-module/test-esm-throw-undefined.mjs @@ -1,6 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ - import '../common/index.mjs'; import assert from 'assert'; diff --git a/test/es-module/test-esm-type-flag.mjs b/test/es-module/test-esm-type-flag.mjs index 4c04ef03e121f7..e820c9ad67458f 100644 --- a/test/es-module/test-esm-type-flag.mjs +++ b/test/es-module/test-esm-type-flag.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import cjs from '../fixtures/baz.js'; import '../common/index.mjs'; import { message } from '../fixtures/es-modules/message.mjs'; diff --git a/test/fixtures/test-repl-tab-completion/.hiddenfiles b/test/fixtures/test-repl-tab-completion/.hiddenfiles new file mode 100644 index 00000000000000..8943faefedd9e6 --- /dev/null +++ b/test/fixtures/test-repl-tab-completion/.hiddenfiles @@ -0,0 +1 @@ +This is hidden \ No newline at end of file diff --git a/test/fixtures/test-repl-tab-completion/hellorandom.txt b/test/fixtures/test-repl-tab-completion/hellorandom.txt new file mode 100644 index 00000000000000..35268b4f156814 --- /dev/null +++ b/test/fixtures/test-repl-tab-completion/hellorandom.txt @@ -0,0 +1 @@ +Random txt \ No newline at end of file diff --git a/test/fixtures/test-repl-tab-completion/helloworld.js b/test/fixtures/test-repl-tab-completion/helloworld.js new file mode 100644 index 00000000000000..0f504264f5b1af --- /dev/null +++ b/test/fixtures/test-repl-tab-completion/helloworld.js @@ -0,0 +1 @@ +console.log("hello world"); \ No newline at end of file diff --git a/test/fixtures/workload/fibonacci-worker-argv.js b/test/fixtures/workload/fibonacci-worker-argv.js index 9c968bfeec4ae2..69a78ec4e175ef 100644 --- a/test/fixtures/workload/fibonacci-worker-argv.js +++ b/test/fixtures/workload/fibonacci-worker-argv.js @@ -3,5 +3,9 @@ const { Worker } = require('worker_threads'); const path = require('path'); new Worker(path.join(__dirname, 'fibonacci.js'), { - execArgv: ['--cpu-prof'] + execArgv: [ + '--cpu-prof', + '--cpu-prof-interval', + process.env.CPU_PROF_INTERVAL || '100' + ] }); diff --git a/test/js-native-api/test_object/test.js b/test/js-native-api/test_object/test.js index 3047b1f58dc602..d6e15dcfcef00b 100644 --- a/test/js-native-api/test_object/test.js +++ b/test/js-native-api/test_object/test.js @@ -202,3 +202,26 @@ assert.strictEqual(newObject.test_string, 'test string'); assert.strictEqual(test_object.Delete(obj, 'foo'), true); assert.strictEqual(obj.foo, 'baz'); } + +{ + // Verify that napi_get_property_names gets the right set of property names, + // i.e.: includes prototypes, only enumerable properties, skips symbols, + // and includes indices and converts them to strings. + + const object = Object.create({ + inherited: 1 + }); + + object.normal = 2; + object[Symbol('foo')] = 3; + Object.defineProperty(object, 'unenumerable', { + value: 4, + enumerable: false, + writable: true, + configurable: true + }); + object[5] = 5; + + assert.deepStrictEqual(test_object.GetPropertyNames(object), + ['5', 'normal', 'inherited']); +} diff --git a/test/js-native-api/test_object/test_object.c b/test/js-native-api/test_object/test_object.c index b6dbbd4dd33bb0..30768bdc812619 100644 --- a/test/js-native-api/test_object/test_object.c +++ b/test/js-native-api/test_object/test_object.c @@ -63,6 +63,25 @@ static napi_value GetNamed(napi_env env, napi_callback_info info) { return output; } +static napi_value GetPropertyNames(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype value_type0; + NAPI_CALL(env, napi_typeof(env, args[0], &value_type0)); + + NAPI_ASSERT(env, value_type0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_value output; + NAPI_CALL(env, napi_get_property_names(env, args[0], &output)); + + return output; +} + static napi_value Set(napi_env env, napi_callback_info info) { size_t argc = 3; napi_value args[3]; @@ -325,6 +344,7 @@ napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Get", Get), DECLARE_NAPI_PROPERTY("GetNamed", GetNamed), + DECLARE_NAPI_PROPERTY("GetPropertyNames", GetPropertyNames), DECLARE_NAPI_PROPERTY("Set", Set), DECLARE_NAPI_PROPERTY("SetNamed", SetNamed), DECLARE_NAPI_PROPERTY("Has", Has), diff --git a/test/js-native-api/test_reference/test_reference.c b/test/js-native-api/test_reference/test_reference.c index 6a02eb3d005a6f..05d5ae3eab8eb5 100644 --- a/test/js-native-api/test_reference/test_reference.c +++ b/test/js-native-api/test_reference/test_reference.c @@ -1,4 +1,5 @@ #include +#include #include #include "../common.h" @@ -135,6 +136,9 @@ static napi_value GetReferenceValue(napi_env env, napi_callback_info info) { static void DeleteBeforeFinalizeFinalizer( napi_env env, void* finalize_data, void* finalize_hint) { napi_ref* ref = (napi_ref*)finalize_data; + napi_value value; + assert(napi_get_reference_value(env, *ref, &value) == napi_ok); + assert(value == NULL); napi_delete_reference(env, *ref); free(ref); } diff --git a/test/message/async_error_sync_esm.mjs b/test/message/async_error_sync_esm.mjs index 86a901a1225572..f16256d7778b81 100644 --- a/test/message/async_error_sync_esm.mjs +++ b/test/message/async_error_sync_esm.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import four from '../fixtures/async-error.js'; diff --git a/test/message/async_error_sync_esm.out b/test/message/async_error_sync_esm.out index 99ce9ed0b21c2f..f34628ef44e52a 100644 --- a/test/message/async_error_sync_esm.out +++ b/test/message/async_error_sync_esm.out @@ -4,4 +4,4 @@ Error: test at two (*fixtures*async-error.js:17:9) at async three (*fixtures*async-error.js:20:3) at async four (*fixtures*async-error.js:24:3) - at async main (*message*async_error_sync_esm.mjs:8:5) + at async main (*message*async_error_sync_esm.mjs:7:5) diff --git a/test/message/esm_display_syntax_error_import.mjs b/test/message/esm_display_syntax_error_import.mjs index 12d10270e96854..4c41b292efd4d6 100644 --- a/test/message/esm_display_syntax_error_import.mjs +++ b/test/message/esm_display_syntax_error_import.mjs @@ -1,5 +1,5 @@ // Flags: --experimental-modules -/* eslint-disable no-unused-vars, node-core/required-modules */ +/* eslint-disable no-unused-vars */ import '../common/index.mjs'; import { foo, diff --git a/test/message/esm_display_syntax_error_import_module.mjs b/test/message/esm_display_syntax_error_import_module.mjs index a53bbbcd19243f..346b3489fd920d 100644 --- a/test/message/esm_display_syntax_error_import_module.mjs +++ b/test/message/esm_display_syntax_error_import_module.mjs @@ -1,4 +1,3 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import '../fixtures/es-module-loaders/syntax-error-import.mjs'; diff --git a/test/message/esm_display_syntax_error_module.mjs b/test/message/esm_display_syntax_error_module.mjs index 5905d2a95478c1..1f2b87ecd0cb1a 100644 --- a/test/message/esm_display_syntax_error_module.mjs +++ b/test/message/esm_display_syntax_error_module.mjs @@ -1,4 +1,3 @@ // Flags: --experimental-modules -/* eslint-disable node-core/required-modules */ import '../common/index.mjs'; import '../fixtures/es-module-loaders/syntax-error.mjs'; diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index 8511d1b21de112..33576ffc633a9f 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -9,6 +9,8 @@ prefix parallel test-net-connect-options-port: PASS,FLAKY # https://github.com/nodejs/node/issues/26401 test-worker-prof: PASS,FLAKY +# https://github.com/nodejs/node/issues/27553 +test-tls-enable-trace-cli: PASS,FLAKY [$system==win32] test-http2-pipe: PASS,FLAKY @@ -23,10 +25,6 @@ test-http2-client-upload-reject: PASS,FLAKY [$system==linux] [$system==macos] -# https://github.com/nodejs/node/issues/26910 -test-tls-sni-option: PASS,FLAKY -# https://github.com/nodejs/node/issues/27219 -test-tls-sni-server-client: PASS,FLAKY # https://github.com/nodejs/node/issues/26938 test-tls-js-stream: PASS,FLAKY diff --git a/test/parallel/test-assert-async.js b/test/parallel/test-assert-async.js index 140bd05d1a3c8f..8aad1d865c097e 100644 --- a/test/parallel/test-assert-async.js +++ b/test/parallel/test-assert-async.js @@ -114,11 +114,36 @@ promises.push(assert.rejects( } )); +{ + const handler = (generated, actual, err) => { + assert.strictEqual(err.generatedMessage, generated); + assert.strictEqual(err.code, 'ERR_ASSERTION'); + assert.strictEqual(err.actual, actual); + assert.strictEqual(err.operator, 'rejects'); + assert(/rejects/.test(err.stack)); + return true; + }; + const err = new Error(); + promises.push(assert.rejects( + assert.rejects(Promise.reject(null), { code: 'FOO' }), + handler.bind(null, true, null) + )); + promises.push(assert.rejects( + assert.rejects(Promise.reject(5), { code: 'FOO' }, 'AAAAA'), + handler.bind(null, false, 5) + )); + promises.push(assert.rejects( + assert.rejects(Promise.reject(err), { code: 'FOO' }, 'AAAAA'), + handler.bind(null, false, err) + )); +} + // Check `assert.doesNotReject`. { // `assert.doesNotReject` accepts a function or a promise // or a thenable as first argument. - const promise = assert.doesNotReject(() => new Map(), common.mustNotCall()); + /* eslint-disable no-restricted-syntax */ + let promise = assert.doesNotReject(() => new Map(), common.mustNotCall()); promises.push(assert.rejects(promise, { message: 'Expected instance of Promise to be returned ' + 'from the "promiseFn" function but got instance of Map.', @@ -149,9 +174,7 @@ promises.push(assert.rejects( code: 'ERR_INVALID_RETURN_VALUE' }) ); -} -{ const handler1 = (err) => { assert(err instanceof assert.AssertionError, `${err.name} is not instance of AssertionError`); @@ -173,7 +196,7 @@ promises.push(assert.rejects( const rejectingFn = async () => assert.fail(); - let promise = assert.doesNotReject(rejectingFn, common.mustCall(handler1)); + promise = assert.doesNotReject(rejectingFn, common.mustCall(handler1)); promises.push(assert.rejects(promise, common.mustCall(handler2))); promise = assert.doesNotReject(rejectingFn(), common.mustCall(handler1)); @@ -181,39 +204,16 @@ promises.push(assert.rejects( promise = assert.doesNotReject(() => assert.fail(), common.mustNotCall()); promises.push(assert.rejects(promise, common.mustCall(handler1))); -} -promises.push(assert.rejects( - assert.doesNotReject(123), - { - code: 'ERR_INVALID_ARG_TYPE', - message: 'The "promiseFn" argument must be one of type ' + - 'Function or Promise. Received type number' - } -)); - -{ - const handler = (generated, actual, err) => { - assert.strictEqual(err.generatedMessage, generated); - assert.strictEqual(err.code, 'ERR_ASSERTION'); - assert.strictEqual(err.actual, actual); - assert.strictEqual(err.operator, 'rejects'); - assert(/rejects/.test(err.stack)); - return true; - }; - const err = new Error(); promises.push(assert.rejects( - assert.rejects(Promise.reject(null), { code: 'FOO' }), - handler.bind(null, true, null) - )); - promises.push(assert.rejects( - assert.rejects(Promise.reject(5), { code: 'FOO' }, 'AAAAA'), - handler.bind(null, false, 5) - )); - promises.push(assert.rejects( - assert.rejects(Promise.reject(err), { code: 'FOO' }, 'AAAAA'), - handler.bind(null, false, err) + assert.doesNotReject(123), + { + code: 'ERR_INVALID_ARG_TYPE', + message: 'The "promiseFn" argument must be one of type ' + + 'Function or Promise. Received type number' + } )); + /* eslint-enable no-restricted-syntax */ } // Make sure all async code gets properly executed. diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 62ed50f6a43fa9..003e67b380d88d 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -631,13 +631,13 @@ common.expectsError( } ); common.expectsError( - () => assert(typeof 123 === 'string'), + () => assert(typeof 123n === 'string'), { code: 'ERR_ASSERTION', type: assert.AssertionError, generatedMessage: true, message: 'The expression evaluated to a falsy value:\n\n ' + - "assert(typeof 123 === 'string')\n" + "assert(typeof 123n === 'string')\n" } ); diff --git a/test/parallel/test-async-hooks-http-parser-destroy.js b/test/parallel/test-async-hooks-http-parser-destroy.js index d2e1071c280d66..8e92f6359c6e72 100644 --- a/test/parallel/test-async-hooks-http-parser-destroy.js +++ b/test/parallel/test-async-hooks-http-parser-destroy.js @@ -1,6 +1,5 @@ 'use strict'; -const common = require('../common'); -const Countdown = require('../common/countdown'); +require('../common'); const assert = require('assert'); const async_hooks = require('async_hooks'); const http = require('http'); @@ -15,17 +14,22 @@ const KEEP_ALIVE = 100; const createdIds = []; const destroyedIds = []; async_hooks.createHook({ - init: common.mustCallAtLeast((asyncId, type) => { - if (type === 'HTTPPARSER') { + init: (asyncId, type) => { + if (type === 'HTTPINCOMINGMESSAGE' || type === 'HTTPCLIENTREQUEST') { createdIds.push(asyncId); } - }, N), + }, destroy: (asyncId) => { - destroyedIds.push(asyncId); + if (createdIds.includes(asyncId)) { + destroyedIds.push(asyncId); + } + if (destroyedIds.length === 2 * N) { + server.close(); + } } }).enable(); -const server = http.createServer(function(req, res) { +const server = http.createServer((req, res) => { res.end('Hello'); }); @@ -34,18 +38,6 @@ const keepAliveAgent = new http.Agent({ keepAliveMsecs: KEEP_ALIVE, }); -const countdown = new Countdown(N, () => { - server.close(() => { - // Give the server sockets time to close (which will also free their - // associated parser objects) after the server has been closed. - setTimeout(() => { - createdIds.forEach((createdAsyncId) => { - assert.ok(destroyedIds.indexOf(createdAsyncId) >= 0); - }); - }, KEEP_ALIVE * 2); - }); -}); - server.listen(0, function() { for (let i = 0; i < N; ++i) { (function makeRequest() { @@ -53,9 +45,24 @@ server.listen(0, function() { port: server.address().port, agent: keepAliveAgent }, function(res) { - countdown.dec(); res.resume(); }); })(); } }); + +function checkOnExit() { + assert.deepStrictEqual(destroyedIds.sort(), createdIds.sort()); + // There should be two IDs for each request. + assert.strictEqual(createdIds.length, N * 2); +} + +process.on('SIGTERM', () => { + // Catching SIGTERM and calling `process.exit(1)` so that the `exit` event + // is triggered and the assertions are checked. This can be useful for + // troubleshooting this test if it times out. + process.exit(1); +}); + +// Ordinary exit. +process.on('exit', checkOnExit); diff --git a/test/parallel/test-buffer-bigint64.js b/test/parallel/test-buffer-bigint64.js index 859a40811e1bb9..60d376bdaf84af 100644 --- a/test/parallel/test-buffer-bigint64.js +++ b/test/parallel/test-buffer-bigint64.js @@ -37,7 +37,11 @@ const buf = Buffer.allocUnsafe(8); assert.throws(function() { const val = 0x10000000000000000n; buf['writeBigUInt64' + endianness](val, 0); - }, RangeError); + }, { + code: 'ERR_OUT_OF_RANGE', + message: 'The value of "value" is out of range. It must be ' + + '>= 0n and < 2n ** 64n. Received 18_446_744_073_709_551_616n' + }); // Should throw a TypeError upon invalid input assert.throws(function() { diff --git a/test/parallel/test-buffer-writeint.js b/test/parallel/test-buffer-writeint.js index 7dba14211cf758..05b0cd1ebbfada 100644 --- a/test/parallel/test-buffer-writeint.js +++ b/test/parallel/test-buffer-writeint.js @@ -217,15 +217,21 @@ const errorOutOfBounds = common.expectsError({ ['writeIntBE', 'writeIntLE'].forEach((fn) => { const min = -(2 ** (i * 8 - 1)); const max = 2 ** (i * 8 - 1) - 1; - + let range = `>= ${min} and <= ${max}`; + if (i > 4) { + range = `>= -(2 ** ${i * 8 - 1}) and < 2 ** ${i * 8 - 1}`; + } [min - 1, max + 1].forEach((val) => { + const received = i > 4 ? + String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') : + val; assert.throws(() => { data[fn](val, 0, i); }, { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', message: 'The value of "value" is out of range. ' + - `It must be >= ${min} and <= ${max}. Received ${val}` + `It must be ${range}. Received ${received}` }); }); diff --git a/test/parallel/test-buffer-writeuint.js b/test/parallel/test-buffer-writeuint.js index cd500004429ba9..3823b74d565519 100644 --- a/test/parallel/test-buffer-writeuint.js +++ b/test/parallel/test-buffer-writeuint.js @@ -171,6 +171,10 @@ const assert = require('assert'); // Test 1 to 6 bytes. for (let i = 1; i < 6; i++) { + const range = i < 5 ? `= ${val - 1}` : ` 2 ** ${i * 8}`; + const received = i > 4 ? + String(val).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1_') : + val; ['writeUIntBE', 'writeUIntLE'].forEach((fn) => { assert.throws(() => { data[fn](val, 0, i); @@ -178,7 +182,7 @@ const assert = require('assert'); code: 'ERR_OUT_OF_RANGE', name: 'RangeError', message: 'The value of "value" is out of range. ' + - `It must be >= 0 and <= ${val - 1}. Received ${val}` + `It must be >= 0 and <${range}. Received ${received}` }); ['', '0', null, {}, [], () => {}, true, false].forEach((o) => { diff --git a/test/parallel/test-child-process-pipe-dataflow.js b/test/parallel/test-child-process-pipe-dataflow.js index f5068b5d366468..88a31f4ff8429b 100644 --- a/test/parallel/test-child-process-pipe-dataflow.js +++ b/test/parallel/test-child-process-pipe-dataflow.js @@ -33,6 +33,10 @@ const MB = KB * KB; grep = spawn('grep', ['x'], { stdio: [cat.stdout, 'pipe', 'pipe'] }); wc = spawn('wc', ['-c'], { stdio: [grep.stdout, 'pipe', 'pipe'] }); + // Extra checks: We never try to start reading data ourselves. + cat.stdout._handle.readStart = common.mustNotCall(); + grep.stdout._handle.readStart = common.mustNotCall(); + [cat, grep, wc].forEach((child, index) => { child.stderr.on('data', (d) => { // Don't want to assert here, as we might miss error code info. diff --git a/test/parallel/test-child-process-server-close.js b/test/parallel/test-child-process-server-close.js index ec95fed67b4fa7..d70926f2e8278e 100644 --- a/test/parallel/test-child-process-server-close.js +++ b/test/parallel/test-child-process-server-close.js @@ -8,11 +8,11 @@ const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); const server = net.createServer((conn) => { - conn.on('close', common.mustCall()); - spawn(process.execPath, ['-v'], { stdio: ['ignore', conn, 'ignore'] - }).on('close', common.mustCall()); + }).on('close', common.mustCall(() => { + conn.end(); + })); }).listen(common.PIPE, () => { const client = net.connect(common.PIPE, common.mustCall()); client.on('data', () => { diff --git a/test/parallel/test-child-process-stdio-merge-stdouts-into-cat.js b/test/parallel/test-child-process-stdio-merge-stdouts-into-cat.js new file mode 100644 index 00000000000000..64373e9e160937 --- /dev/null +++ b/test/parallel/test-child-process-stdio-merge-stdouts-into-cat.js @@ -0,0 +1,30 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { spawn } = require('child_process'); + +// Regression test for https://github.com/nodejs/node/issues/27097. +// Check that (cat [p1] ; cat [p2]) | cat [p3] works. + +const p3 = spawn('cat', { stdio: ['pipe', 'pipe', 'inherit'] }); +const p1 = spawn('cat', { stdio: ['pipe', p3.stdin, 'inherit'] }); +const p2 = spawn('cat', { stdio: ['pipe', p3.stdin, 'inherit'] }); +p3.stdout.setEncoding('utf8'); + +// Write three different chunks: +// - 'hello' from this process to p1 to p3 back to us +// - 'world' from this process to p2 to p3 back to us +// - 'foobar' from this process to p3 back to us +// Do so sequentially in order to avoid race conditions. +p1.stdin.end('hello\n'); +p3.stdout.once('data', common.mustCall((chunk) => { + assert.strictEqual(chunk, 'hello\n'); + p2.stdin.end('world\n'); + p3.stdout.once('data', common.mustCall((chunk) => { + assert.strictEqual(chunk, 'world\n'); + p3.stdin.end('foobar\n'); + p3.stdout.once('data', common.mustCall((chunk) => { + assert.strictEqual(chunk, 'foobar\n'); + })); + })); +})); diff --git a/test/parallel/test-child-process-stdio-reuse-readable-stdio.js b/test/parallel/test-child-process-stdio-reuse-readable-stdio.js new file mode 100644 index 00000000000000..263270f8e8891f --- /dev/null +++ b/test/parallel/test-child-process-stdio-reuse-readable-stdio.js @@ -0,0 +1,27 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { spawn } = require('child_process'); + +// Check that, once a child process has ended, it’s safe to read from a pipe +// that the child had used as input. +// We simulate that using cat | (head -n1; ...) + +const p1 = spawn('cat', { stdio: ['pipe', 'pipe', 'inherit'] }); +const p2 = spawn('head', ['-n1'], { stdio: [p1.stdout, 'pipe', 'inherit'] }); + +// First, write the line that gets passed through p2, making 'head' exit. +p1.stdin.write('hello\n'); +p2.stdout.setEncoding('utf8'); +p2.stdout.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk, 'hello\n'); +})); +p2.on('exit', common.mustCall(() => { + // We can now use cat’s output, because 'head' is no longer reading from it. + p1.stdin.end('world\n'); + p1.stdout.setEncoding('utf8'); + p1.stdout.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk, 'world\n'); + })); + p1.stdout.resume(); +})); diff --git a/test/parallel/test-crypto-pbkdf2.js b/test/parallel/test-crypto-pbkdf2.js index 4e3c4f64f076d8..1d4e6f6617f074 100644 --- a/test/parallel/test-crypto-pbkdf2.js +++ b/test/parallel/test-crypto-pbkdf2.js @@ -111,8 +111,8 @@ assert.throws( }, { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', - message: 'The value of "keylen" is out of range. It ' + - `must be >= 0 && < 4294967296. Received ${input}` + message: 'The value of "keylen" is out of range. It must be >= 0 && < ' + + `4294967296. Received ${input === -1 ? '-1' : '4_294_967_297'}` }); }); diff --git a/test/parallel/test-dgram-connect-send-callback-buffer-length.js b/test/parallel/test-dgram-connect-send-callback-buffer-length.js index 3dc089e7386b5a..08c220682e79af 100644 --- a/test/parallel/test-dgram-connect-send-callback-buffer-length.js +++ b/test/parallel/test-dgram-connect-send-callback-buffer-length.js @@ -17,8 +17,8 @@ const messageSent = common.mustCall(function messageSent(err, bytes) { client.close(); }); -client.bind(0, () => { +client.bind(0, common.mustCall(() => { client.connect(client.address().port, common.mustCall(() => { client.send(buf, offset, len, messageSent); })); -}); +})); diff --git a/test/parallel/test-dgram-connect-send-callback-buffer.js b/test/parallel/test-dgram-connect-send-callback-buffer.js index a03d45429b5cf7..ad756b03effa6f 100644 --- a/test/parallel/test-dgram-connect-send-callback-buffer.js +++ b/test/parallel/test-dgram-connect-send-callback-buffer.js @@ -14,8 +14,8 @@ const onMessage = common.mustCall(function(err, bytes) { client.close(); }); -client.bind(0, () => { +client.bind(0, common.mustCall(() => { client.connect(client.address().port, common.mustCall(() => { client.send(buf, onMessage); })); -}); +})); diff --git a/test/parallel/test-dgram-connect-send-multi-buffer-copy.js b/test/parallel/test-dgram-connect-send-multi-buffer-copy.js index 24de99a1e9d61d..ae8de70a6b4799 100644 --- a/test/parallel/test-dgram-connect-send-multi-buffer-copy.js +++ b/test/parallel/test-dgram-connect-send-multi-buffer-copy.js @@ -14,12 +14,12 @@ const onMessage = common.mustCall(common.mustCall((err, bytes) => { const buf1 = Buffer.alloc(256, 'x'); const buf2 = Buffer.alloc(256, 'y'); -client.on('listening', function() { +client.on('listening', common.mustCall(function() { const toSend = [buf1, buf2]; client.connect(client.address().port, common.mustCall(() => { client.send(toSend, onMessage); })); -}); +})); client.on('message', common.mustCall(function onMessage(buf, info) { const expected = Buffer.concat([buf1, buf2]); diff --git a/test/parallel/test-dgram-implicit-bind.js b/test/parallel/test-dgram-implicit-bind.js index 70e29c1f3ab95f..b5aa2781ce12a5 100644 --- a/test/parallel/test-dgram-implicit-bind.js +++ b/test/parallel/test-dgram-implicit-bind.js @@ -36,11 +36,11 @@ target.on('message', common.mustCall(function(buf) { } }, 2)); -target.on('listening', function() { +target.on('listening', common.mustCall(function() { // Second .send() call should not throw a bind error. const port = this.address().port; source.send(Buffer.from('abc'), 0, 3, port, '127.0.0.1'); source.send(Buffer.from('def'), 0, 3, port, '127.0.0.1'); -}); +})); target.bind(0); diff --git a/test/parallel/test-dgram-listen-after-bind.js b/test/parallel/test-dgram-listen-after-bind.js index 6a7e156e008a77..a580a2386b8ea0 100644 --- a/test/parallel/test-dgram-listen-after-bind.js +++ b/test/parallel/test-dgram-listen-after-bind.js @@ -21,6 +21,7 @@ 'use strict'; require('../common'); +const common = require('../common'); const assert = require('assert'); const dgram = require('dgram'); @@ -33,12 +34,12 @@ const timer = setTimeout(() => { socket.close(); }, 100); -socket.on('listening', () => { +socket.on('listening', common.mustCall(() => { clearTimeout(timer); fired = true; socket.close(); -}); +})); -socket.on('close', () => { +socket.on('close', common.mustCall(() => { assert(fired, 'listening should fire after bind'); -}); +})); diff --git a/test/parallel/test-event-emitter-max-listeners.js b/test/parallel/test-event-emitter-max-listeners.js index a906000477f7da..39b5737fde92a2 100644 --- a/test/parallel/test-event-emitter-max-listeners.js +++ b/test/parallel/test-event-emitter-max-listeners.js @@ -22,6 +22,7 @@ 'use strict'; const common = require('../common'); const events = require('events'); +const { inspect } = require('util'); const e = new events.EventEmitter(); e.on('maxListeners', common.mustCall()); @@ -38,7 +39,7 @@ for (const obj of throwsObjs) { code: 'ERR_OUT_OF_RANGE', type: RangeError, message: 'The value of "n" is out of range. ' + - `It must be a non-negative number. Received ${obj}` + `It must be a non-negative number. Received ${inspect(obj)}` } ); @@ -48,7 +49,7 @@ for (const obj of throwsObjs) { code: 'ERR_OUT_OF_RANGE', type: RangeError, message: 'The value of "defaultMaxListeners" is out of range. ' + - `It must be a non-negative number. Received ${obj}` + `It must be a non-negative number. Received ${inspect(obj)}` } ); } diff --git a/test/parallel/test-file-write-stream3.js b/test/parallel/test-file-write-stream3.js index 618fbdf884c0c6..45c431b5d51b94 100644 --- a/test/parallel/test-file-write-stream3.js +++ b/test/parallel/test-file-write-stream3.js @@ -199,8 +199,8 @@ const run_test_5 = common.mustCall(function() { }; const err = { code: 'ERR_OUT_OF_RANGE', - message: 'The value of "start" is out of range. ' + - 'It must be >= 0 and <= 2 ** 53 - 1. Received 9007199254740992', + message: 'The value of "start" is out of range. It must be ' + + '>= 0 and <= 2 ** 53 - 1. Received 9_007_199_254_740_992', type: RangeError }; common.expectsError(fn, err); diff --git a/test/parallel/test-fs-copyfile-respect-permissions.js b/test/parallel/test-fs-copyfile-respect-permissions.js index 2021e9ba63155d..ae7829fba38d49 100644 --- a/test/parallel/test-fs-copyfile-respect-permissions.js +++ b/test/parallel/test-fs-copyfile-respect-permissions.js @@ -5,6 +5,9 @@ const common = require('../common'); +if (!common.isWindows && process.getuid() === 0) + common.skip('as this test should not be run as `root`'); + const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); diff --git a/test/parallel/test-fs-read-stream-fd.js b/test/parallel/test-fs-read-stream-fd.js index 7d4b264002b9f3..ddb62799ace034 100644 --- a/test/parallel/test-fs-read-stream-fd.js +++ b/test/parallel/test-fs-read-stream-fd.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const fs = require('fs'); const assert = require('assert'); const path = require('path'); @@ -35,9 +35,9 @@ fs.writeFileSync(file, input); const fd = fs.openSync(file, 'r'); const stream = fs.createReadStream(null, { fd: fd, encoding: 'utf8' }); -stream.on('data', (data) => { +stream.on('data', common.mustCallAtLeast((data) => { output += data; -}); +})); process.on('exit', () => { assert.strictEqual(output, input); diff --git a/test/parallel/test-fs-read-stream-inherit.js b/test/parallel/test-fs-read-stream-inherit.js index 69f3b9c3f724bd..ef965971dc9704 100644 --- a/test/parallel/test-fs-read-stream-inherit.js +++ b/test/parallel/test-fs-read-stream-inherit.js @@ -26,7 +26,7 @@ const rangeFile = fixtures.path('x.txt'); file.resume(); })); - file.on('data', function(data) { + file.on('data', common.mustCallAtLeast(function(data) { assert.ok(data instanceof Buffer); assert.ok(!paused); file.length += data.length; @@ -38,7 +38,7 @@ const rangeFile = fixtures.path('x.txt'); paused = false; file.resume(); }, 10); - }); + })); file.on('end', common.mustCall()); diff --git a/test/parallel/test-fs-read-stream-resume.js b/test/parallel/test-fs-read-stream-resume.js index bae9ef86d0ea2f..36e3d809cdf637 100644 --- a/test/parallel/test-fs-read-stream-resume.js +++ b/test/parallel/test-fs-read-stream-resume.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const fixtures = require('../common/fixtures'); const assert = require('assert'); @@ -32,13 +32,13 @@ let first = true; const stream = fs.createReadStream(file); stream.setEncoding('utf8'); -stream.on('data', function(chunk) { +stream.on('data', common.mustCallAtLeast(function(chunk) { data += chunk; if (first) { first = false; stream.resume(); } -}); +})); process.nextTick(function() { stream.pause(); diff --git a/test/parallel/test-fs-read-stream.js b/test/parallel/test-fs-read-stream.js index b1559ed9ea8c04..e33c6dec4ee264 100644 --- a/test/parallel/test-fs-read-stream.js +++ b/test/parallel/test-fs-read-stream.js @@ -55,6 +55,7 @@ const rangeFile = fixtures.path('x.txt'); file.on('data', function(data) { assert.ok(data instanceof Buffer); + assert.ok(data.byteOffset % 8 === 0); assert.ok(!paused); file.length += data.length; diff --git a/test/parallel/test-fs-readdir-types.js b/test/parallel/test-fs-readdir-types.js index 96a3b73098728d..78f1b0d4e1b627 100644 --- a/test/parallel/test-fs-readdir-types.js +++ b/test/parallel/test-fs-readdir-types.js @@ -72,13 +72,12 @@ fs.readdir(readdirDir, { assertDirents(dirents); })); -// Check the promisified version -assert.doesNotReject(async () => { +(async () => { const dirents = await fs.promises.readdir(readdirDir, { withFileTypes: true }); assertDirents(dirents); -}); +})(); // Check for correct types when the binding returns unknowns const UNKNOWN = constants.UV_DIRENT_UNKNOWN; diff --git a/test/parallel/test-fs-readfile-empty.js b/test/parallel/test-fs-readfile-empty.js index 7bb942fc2d6fe3..f6303777b29384 100644 --- a/test/parallel/test-fs-readfile-empty.js +++ b/test/parallel/test-fs-readfile-empty.js @@ -20,27 +20,26 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); // Trivial test of fs.readFile on an empty file. - -const assert = require('assert'); +const common = require('../common'); const fs = require('fs'); +const assert = require('assert'); const fixtures = require('../common/fixtures'); const fn = fixtures.path('empty.txt'); -fs.readFile(fn, function(err, data) { +fs.readFile(fn, common.mustCall((err, data) => { assert.ok(data); -}); +})); -fs.readFile(fn, 'utf8', function(err, data) { +fs.readFile(fn, 'utf8', common.mustCall((err, data) => { assert.strictEqual(data, ''); -}); +})); -fs.readFile(fn, { encoding: 'utf8' }, function(err, data) { +fs.readFile(fn, { encoding: 'utf8' }, common.mustCall((err, data) => { assert.strictEqual(data, ''); -}); +})); assert.ok(fs.readFileSync(fn)); assert.strictEqual(fs.readFileSync(fn, 'utf8'), ''); diff --git a/test/parallel/test-fs-readfile-pipe-large.js b/test/parallel/test-fs-readfile-pipe-large.js index b2b5192c789271..78c5feedb7210c 100644 --- a/test/parallel/test-fs-readfile-pipe-large.js +++ b/test/parallel/test-fs-readfile-pipe-large.js @@ -29,7 +29,7 @@ const exec = require('child_process').exec; const f = JSON.stringify(__filename); const node = JSON.stringify(process.execPath); const cmd = `cat ${filename} | ${node} ${f} child`; -exec(cmd, { maxBuffer: 1000000 }, function(err, stdout, stderr) { +exec(cmd, { maxBuffer: 1000000 }, common.mustCall((err, stdout, stderr) => { assert.ifError(err); assert.strictEqual( stdout, @@ -42,7 +42,7 @@ exec(cmd, { maxBuffer: 1000000 }, function(err, stdout, stderr) { `expect that it does not write to stderr, but got : ${stderr}` ); console.log('ok'); -}); +})); process.on('exit', function() { fs.unlinkSync(filename); diff --git a/test/parallel/test-fs-readfile-pipe.js b/test/parallel/test-fs-readfile-pipe.js index 861ce20cfc798d..a21801e3890894 100644 --- a/test/parallel/test-fs-readfile-pipe.js +++ b/test/parallel/test-fs-readfile-pipe.js @@ -31,10 +31,10 @@ const assert = require('assert'); const fs = require('fs'); if (process.argv[2] === 'child') { - fs.readFile('/dev/stdin', function(er, data) { + fs.readFile('/dev/stdin', common.mustCall(function(er, data) { assert.ifError(er); process.stdout.write(data); - }); + })); return; } @@ -47,7 +47,7 @@ const exec = require('child_process').exec; const f = JSON.stringify(__filename); const node = JSON.stringify(process.execPath); const cmd = `cat ${filename} | ${node} ${f} child`; -exec(cmd, function(err, stdout, stderr) { +exec(cmd, common.mustCall(function(err, stdout, stderr) { assert.ifError(err); assert.strictEqual( stdout, @@ -58,4 +58,4 @@ exec(cmd, function(err, stdout, stderr) { '', `expected not to read anything from stderr but got: '${stderr}'`); console.log('ok'); -}); +})); diff --git a/test/parallel/test-fs-readfile-unlink.js b/test/parallel/test-fs-readfile-unlink.js index 1ed6fefb5ccfc7..3ff9b6ac9029fe 100644 --- a/test/parallel/test-fs-readfile-unlink.js +++ b/test/parallel/test-fs-readfile-unlink.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); // Test that unlink succeeds immediately after readFile completes. @@ -37,7 +37,7 @@ tmpdir.refresh(); fs.writeFileSync(fileName, buf); -fs.readFile(fileName, function(err, data) { +fs.readFile(fileName, common.mustCall((err, data) => { assert.ifError(err); assert.strictEqual(data.length, buf.length); assert.strictEqual(buf[0], 42); @@ -45,4 +45,4 @@ fs.readFile(fileName, function(err, data) { // Unlink should not throw. This is part of the test. It used to throw on // Windows due to a bug. fs.unlinkSync(fileName); -}); +})); diff --git a/test/parallel/test-fs-readfilesync-pipe-large.js b/test/parallel/test-fs-readfilesync-pipe-large.js index f8ad5a63318481..0f180f0f86005c 100644 --- a/test/parallel/test-fs-readfilesync-pipe-large.js +++ b/test/parallel/test-fs-readfilesync-pipe-large.js @@ -26,12 +26,16 @@ const exec = require('child_process').exec; const f = JSON.stringify(__filename); const node = JSON.stringify(process.execPath); const cmd = `cat ${filename} | ${node} ${f} child`; -exec(cmd, { maxBuffer: 1000000 }, function(err, stdout, stderr) { - assert.ifError(err); - assert.strictEqual(stdout, dataExpected); - assert.strictEqual(stderr, ''); - console.log('ok'); -}); +exec( + cmd, + { maxBuffer: 1000000 }, + common.mustCall(function(err, stdout, stderr) { + assert.ifError(err); + assert.strictEqual(stdout, dataExpected); + assert.strictEqual(stderr, ''); + console.log('ok'); + }) +); process.on('exit', function() { fs.unlinkSync(filename); diff --git a/test/parallel/test-http-abort-client.js b/test/parallel/test-http-abort-client.js index eda08ced97c55c..80492b9d22734d 100644 --- a/test/parallel/test-http-abort-client.js +++ b/test/parallel/test-http-abort-client.js @@ -24,11 +24,11 @@ const common = require('../common'); const http = require('http'); let serverRes; -const server = http.Server((req, res) => { +const server = http.Server(common.mustCall((req, res) => { serverRes = res; res.writeHead(200); res.write('Part of my res.'); -}); +})); server.listen(0, common.mustCall(() => { http.get({ diff --git a/test/parallel/test-http-abort-queued.js b/test/parallel/test-http-abort-queued.js index 224d0b606ea744..17950c106c3769 100644 --- a/test/parallel/test-http-abort-queued.js +++ b/test/parallel/test-http-abort-queued.js @@ -26,7 +26,7 @@ const http = require('http'); let complete; -const server = http.createServer((req, res) => { +const server = http.createServer(common.mustCall((req, res) => { // We should not see the queued /thatotherone request within the server // as it should be aborted before it is sent. assert.strictEqual(req.url, '/'); @@ -37,10 +37,9 @@ const server = http.createServer((req, res) => { complete = complete || function() { res.end(); }; -}); +})); - -server.listen(0, () => { +server.listen(0, common.mustCall(() => { const agent = new http.Agent({ maxSockets: 1 }); assert.strictEqual(Object.keys(agent.sockets).length, 0); @@ -93,4 +92,4 @@ server.listen(0, () => { }); req1.end(); -}); +})); diff --git a/test/parallel/test-http-dns-error.js b/test/parallel/test-http-dns-error.js index e3d09a39d0e276..20e12f24fbf4f7 100644 --- a/test/parallel/test-http-dns-error.js +++ b/test/parallel/test-http-dns-error.js @@ -32,9 +32,7 @@ const https = require('https'); const host = '*'.repeat(64); const MAX_TRIES = 5; -let errCode = 'ENOTFOUND'; -if (common.isOpenBSD) - errCode = 'EAI_FAIL'; +const errCodes = ['ENOTFOUND', 'EAI_FAIL']; function tryGet(mod, tries) { // Bad host name should not throw an uncatchable exception. @@ -45,7 +43,7 @@ function tryGet(mod, tries) { tryGet(mod, ++tries); return; } - assert.strictEqual(err.code, errCode); + assert(errCodes.includes(err.code), err); })); // http.get() called req1.end() for us } @@ -61,7 +59,7 @@ function tryRequest(mod, tries) { tryRequest(mod, ++tries); return; } - assert.strictEqual(err.code, errCode); + assert(errCodes.includes(err.code), err); })); req.end(); } diff --git a/test/parallel/test-http-parser-bad-ref.js b/test/parallel/test-http-parser-bad-ref.js index 0b132d69a2dc96..2c1bfe67485db7 100644 --- a/test/parallel/test-http-parser-bad-ref.js +++ b/test/parallel/test-http-parser-bad-ref.js @@ -24,7 +24,8 @@ function flushPool() { function demoBug(part1, part2) { flushPool(); - const parser = new HTTPParser(HTTPParser.REQUEST); + const parser = new HTTPParser(); + parser.initialize(HTTPParser.REQUEST, {}); parser.headers = []; parser.url = ''; diff --git a/test/parallel/test-http-parser-lazy-loaded.js b/test/parallel/test-http-parser-lazy-loaded.js index 6d6b2ddd256bd4..79b6ac37b3cbfe 100644 --- a/test/parallel/test-http-parser-lazy-loaded.js +++ b/test/parallel/test-http-parser-lazy-loaded.js @@ -7,7 +7,10 @@ const { getOptionValue } = require('internal/options'); // Monkey patch before requiring anything class DummyParser { - constructor(type) { + constructor() { + this.test_type = null; + } + initialize(type) { this.test_type = type; } } @@ -25,6 +28,7 @@ const { parsers } = require('_http_common'); // Test _http_common was not loaded before monkey patching const parser = parsers.alloc(); +parser.initialize(DummyParser.REQUEST, {}); assert.strictEqual(parser instanceof DummyParser, true); assert.strictEqual(parser.test_type, DummyParser.REQUEST); diff --git a/test/parallel/test-http-parser.js b/test/parallel/test-http-parser.js index 078895d49b13aa..97dc57f755ad88 100644 --- a/test/parallel/test-http-parser.js +++ b/test/parallel/test-http-parser.js @@ -38,7 +38,8 @@ const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0; function newParser(type) { - const parser = new HTTPParser(type); + const parser = new HTTPParser(); + parser.initialize(type, {}); parser.headers = []; parser.url = ''; @@ -95,7 +96,7 @@ function expectBody(expected) { throw new Error('hello world'); }; - parser.initialize(HTTPParser.REQUEST, request); + parser.initialize(REQUEST, {}); assert.throws( () => { parser.execute(request, 0, request.length); }, diff --git a/test/parallel/test-http-slow-headers-keepalive.js b/test/parallel/test-http-slow-headers-keepalive.js index 4e62b59168326e..4958d534ef77d4 100644 --- a/test/parallel/test-http-slow-headers-keepalive.js +++ b/test/parallel/test-http-slow-headers-keepalive.js @@ -8,7 +8,7 @@ const { finished } = require('stream'); const headers = 'GET / HTTP/1.1\r\n' + 'Host: localhost\r\n' + - 'Connection: keep-alive' + + 'Connection: keep-alive\r\n' + 'Agent: node\r\n'; let sendCharEvery = 1000; diff --git a/test/parallel/test-http2-util-nghttp2error.js b/test/parallel/test-http2-util-nghttp2error.js index 7a9009515b3234..100ce2cb45993b 100644 --- a/test/parallel/test-http2-util-nghttp2error.js +++ b/test/parallel/test-http2-util-nghttp2error.js @@ -14,3 +14,9 @@ common.expectsError(() => { type: NghttpError, message: 'Invalid argument' }); + +// Should convert the NghttpError object to string properly +{ + const err = new NghttpError(401); + strictEqual(err.toString(), 'Error [ERR_HTTP2_ERROR]: Unknown error code'); +} diff --git a/test/parallel/test-https-agent-sni.js b/test/parallel/test-https-agent-sni.js index 80278ed2d8fe96..1ddeff7ce205d9 100644 --- a/test/parallel/test-https-agent-sni.js +++ b/test/parallel/test-https-agent-sni.js @@ -18,9 +18,12 @@ let waiting = TOTAL; const server = https.Server(options, function(req, res) { if (--waiting === 0) server.close(); - res.writeHead(200, { - 'x-sni': req.socket.servername - }); + const servername = req.socket.servername; + + if (servername !== false) { + res.setHeader('x-sni', servername); + } + res.end('hello world'); }); @@ -28,7 +31,8 @@ server.listen(0, function() { function expectResponse(id) { return common.mustCall(function(res) { res.resume(); - assert.strictEqual(res.headers['x-sni'], `sni.${id}`); + assert.strictEqual(res.headers['x-sni'], + id === false ? undefined : `sni.${id}`); }); } @@ -46,4 +50,13 @@ server.listen(0, function() { rejectUnauthorized: false }, expectResponse(j)); } + https.get({ + agent: agent, + + path: '/', + port: this.address().port, + host: '127.0.0.1', + servername: '', + rejectUnauthorized: false + }, expectResponse(false)); }); diff --git a/test/parallel/test-internal-fs.js b/test/parallel/test-internal-fs.js index 2e47e2a3823a9c..bfdf0022f421c3 100644 --- a/test/parallel/test-internal-fs.js +++ b/test/parallel/test-internal-fs.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const assert = require('assert'); const fs = require('internal/fs/utils'); // Valid encodings and no args should not throw. @@ -12,3 +13,41 @@ common.expectsError( () => fs.assertEncoding('foo'), { code: 'ERR_INVALID_OPT_VALUE_ENCODING', type: TypeError } ); + +// Test junction symlinks +{ + const pathString = 'c:\\test1'; + const linkPathString = '\\test2'; + + const preprocessSymlinkDestination = fs.preprocessSymlinkDestination( + pathString, + 'junction', + linkPathString + ); + + if (process.platform === 'win32') { + assert.strictEqual(/^\\\\\?\\/.test(preprocessSymlinkDestination), true); + } else { + assert.strictEqual(preprocessSymlinkDestination, pathString); + } +} + +// Test none junction symlinks +{ + const pathString = 'c:\\test1'; + const linkPathString = '\\test2'; + + const preprocessSymlinkDestination = fs.preprocessSymlinkDestination( + pathString, + undefined, + linkPathString + ); + + if (process.platform === 'win32') { + // There should not be any forward slashes + assert.strictEqual( + /\//.test(preprocessSymlinkDestination), false); + } else { + assert.strictEqual(preprocessSymlinkDestination, pathString); + } +} diff --git a/test/parallel/test-loaders-unknown-builtin-module.mjs b/test/parallel/test-loaders-unknown-builtin-module.mjs index 5f47f191f54094..b7d815c812ce3f 100644 --- a/test/parallel/test-loaders-unknown-builtin-module.mjs +++ b/test/parallel/test-loaders-unknown-builtin-module.mjs @@ -1,5 +1,4 @@ // Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs -/* eslint-disable node-core/required-modules */ import { expectsError, mustCall } from '../common/index.mjs'; import assert from 'assert'; diff --git a/test/parallel/test-module-create-require-from-directory.js b/test/parallel/test-module-create-require-from-directory.js new file mode 100644 index 00000000000000..f043adacf994d8 --- /dev/null +++ b/test/parallel/test-module-create-require-from-directory.js @@ -0,0 +1,18 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const path = require('path'); + +const { createRequireFromPath } = require('module'); + +const fixPath = path.resolve(__dirname, '..', 'fixtures'); +const p = path.join(fixPath, path.sep); + +const req = createRequireFromPath(p); +const reqFromNotDir = createRequireFromPath(fixPath); + +assert.strictEqual(req('./baz'), 'perhaps I work'); +assert.throws(() => { + reqFromNotDir('./baz'); +}, { code: 'MODULE_NOT_FOUND' }); diff --git a/test/parallel/test-module-create-require.js b/test/parallel/test-module-create-require.js index 03ed31939fba67..fa25b87f95921b 100644 --- a/test/parallel/test-module-create-require.js +++ b/test/parallel/test-module-create-require.js @@ -4,9 +4,31 @@ require('../common'); const assert = require('assert'); const path = require('path'); -const { createRequireFromPath } = require('module'); +const { createRequire, createRequireFromPath } = require('module'); const p = path.resolve(__dirname, '..', 'fixtures', 'fake.js'); +const u = new URL(`file://${p}`); const req = createRequireFromPath(p); assert.strictEqual(req('./baz'), 'perhaps I work'); + +const reqToo = createRequire(u); +assert.deepStrictEqual(reqToo('./experimental'), { ofLife: 42 }); + +assert.throws(() => { + createRequire('https://github.com/nodejs/node/pull/27405/'); +}, { + code: 'ERR_INVALID_ARG_VALUE' +}); + +assert.throws(() => { + createRequire('../'); +}, { + code: 'ERR_INVALID_ARG_VALUE' +}); + +assert.throws(() => { + createRequire({}); +}, { + code: 'ERR_INVALID_ARG_VALUE' +}); diff --git a/test/parallel/test-net-after-close.js b/test/parallel/test-net-after-close.js index 0750ba0f435512..641e61bd04c5d0 100644 --- a/test/parallel/test-net-after-close.js +++ b/test/parallel/test-net-after-close.js @@ -24,10 +24,10 @@ const common = require('../common'); const assert = require('assert'); const net = require('net'); -const server = net.createServer(function(s) { +const server = net.createServer(common.mustCall(function(s) { console.error('SERVER: got connection'); s.end(); -}); +})); server.listen(0, common.mustCall(function() { const c = net.createConnection(this.address().port); diff --git a/test/parallel/test-net-buffersize.js b/test/parallel/test-net-buffersize.js index 1359a257440822..7225d70af318a0 100644 --- a/test/parallel/test-net-buffersize.js +++ b/test/parallel/test-net-buffersize.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const net = require('net'); @@ -36,12 +36,12 @@ const server = net.createServer(function(socket) { }); }); -server.listen(0, function() { +server.listen(0, common.mustCall(function() { const client = net.connect(this.address().port); - client.on('finish', function() { + client.on('finish', common.mustCall(() => { assert.strictEqual(client.bufferSize, 0); - }); + })); for (let i = 1; i < iter; i++) { client.write('a'); @@ -49,4 +49,4 @@ server.listen(0, function() { } client.end(); -}); +})); diff --git a/test/parallel/test-net-bytes-read.js b/test/parallel/test-net-bytes-read.js index fa6b2383b4f317..d569d78403e1d5 100644 --- a/test/parallel/test-net-bytes-read.js +++ b/test/parallel/test-net-bytes-read.js @@ -6,10 +6,12 @@ const net = require('net'); const big = Buffer.alloc(1024 * 1024); -const server = net.createServer((socket) => { +const handler = common.mustCall((socket) => { socket.end(big); server.close(); -}).listen(0, () => { +}); + +const onListen = common.mustCall(() => { let prev = 0; function checkRaise(value) { @@ -17,22 +19,29 @@ const server = net.createServer((socket) => { prev = value; } - const socket = net.connect(server.address().port, () => { - socket.on('data', (chunk) => { - checkRaise(socket.bytesRead); - }); + const onData = common.mustCallAtLeast((chunk) => { + checkRaise(socket.bytesRead); + }); - socket.on('end', common.mustCall(() => { - assert.strictEqual(socket.bytesRead, prev); - assert.strictEqual(big.length, prev); - })); + const onEnd = common.mustCall(() => { + assert.strictEqual(socket.bytesRead, prev); + assert.strictEqual(big.length, prev); + }); - socket.on('close', common.mustCall(() => { - assert(!socket._handle); - assert.strictEqual(socket.bytesRead, prev); - assert.strictEqual(big.length, prev); - })); + const onClose = common.mustCall(() => { + assert(!socket._handle); + assert.strictEqual(socket.bytesRead, prev); + assert.strictEqual(big.length, prev); + }); + const onConnect = common.mustCall(() => { + socket.on('data', onData); + socket.on('end', onEnd); + socket.on('close', onClose); socket.end(); }); + + const socket = net.connect(server.address().port, onConnect); }); + +const server = net.createServer(handler).listen(0, onListen); diff --git a/test/parallel/test-net-can-reset-timeout.js b/test/parallel/test-net-can-reset-timeout.js index 2fac07eab05e23..c72efb5f339c98 100644 --- a/test/parallel/test-net-can-reset-timeout.js +++ b/test/parallel/test-net-can-reset-timeout.js @@ -37,13 +37,13 @@ const server = net.createServer(common.mustCall(function(stream) { stream.write('WHAT.'); })); - stream.on('end', function() { + stream.on('end', common.mustCall(function() { console.log('server side end'); stream.end(); - }); + })); })); -server.listen(0, function() { +server.listen(0, common.mustCall(function() { const c = net.createConnection(this.address().port); c.on('data', function() { @@ -54,4 +54,4 @@ server.listen(0, function() { console.log('client side end'); server.close(); }); -}); +})); diff --git a/test/parallel/test-net-connect-buffer.js b/test/parallel/test-net-connect-buffer.js index 81dd8f0c569c71..8c95400fb6a606 100644 --- a/test/parallel/test-net-connect-buffer.js +++ b/test/parallel/test-net-connect-buffer.js @@ -33,11 +33,11 @@ const tcp = net.Server(common.mustCall((s) => { buf += d; }); - s.on('end', function() { + s.on('end', common.mustCall(function() { console.error('SERVER: end', buf); assert.strictEqual(buf, "L'État, c'est moi"); s.end(); - }); + })); })); tcp.listen(0, common.mustCall(function() { diff --git a/test/parallel/test-net-connect-paused-connection.js b/test/parallel/test-net-connect-paused-connection.js index a53177ed4c7e7e..801bba1cf5b2be 100644 --- a/test/parallel/test-net-connect-paused-connection.js +++ b/test/parallel/test-net-connect-paused-connection.js @@ -26,8 +26,8 @@ const net = require('net'); net.createServer(function(conn) { conn.unref(); -}).listen(0, function() { +}).listen(0, common.mustCall(function() { net.connect(this.address().port, 'localhost').pause(); setTimeout(common.mustNotCall('expected to exit'), 1000).unref(); -}).unref(); +})).unref(); diff --git a/test/parallel/test-net-eaddrinuse.js b/test/parallel/test-net-eaddrinuse.js index 29508e4582852e..cfe004b6839e9b 100644 --- a/test/parallel/test-net-eaddrinuse.js +++ b/test/parallel/test-net-eaddrinuse.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const net = require('net'); @@ -28,10 +28,10 @@ const server1 = net.createServer(function(socket) { }); const server2 = net.createServer(function(socket) { }); -server1.listen(0, function() { +server1.listen(0, common.mustCall(function() { server2.on('error', function(error) { assert.strictEqual(error.message.includes('EADDRINUSE'), true); server1.close(); }); server2.listen(this.address().port); -}); +})); diff --git a/test/parallel/test-policy-parse-integrity.js b/test/parallel/test-policy-parse-integrity.js new file mode 100644 index 00000000000000..7779f767fb97b7 --- /dev/null +++ b/test/parallel/test-policy-parse-integrity.js @@ -0,0 +1,86 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) common.skip('missing crypto'); + +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const { spawnSync } = require('child_process'); +const crypto = require('crypto'); +const fs = require('fs'); +const path = require('path'); +const { pathToFileURL } = require('url'); + +tmpdir.refresh(); + +function hash(algo, body) { + const h = crypto.createHash(algo); + h.update(body); + return h.digest('base64'); +} + +const policyFilepath = path.join(tmpdir.path, 'policy'); + +const parentFilepath = path.join(tmpdir.path, 'parent.js'); +const parentBody = "require('./dep.js')"; + +const depFilepath = path.join(tmpdir.path, 'dep.js'); +const depURL = pathToFileURL(depFilepath); +const depBody = ''; + +fs.writeFileSync(parentFilepath, parentBody); +fs.writeFileSync(depFilepath, depBody); + +const tmpdirURL = pathToFileURL(tmpdir.path); +if (!tmpdirURL.pathname.endsWith('/')) { + tmpdirURL.pathname += '/'; +} + +function test({ shouldFail, integrity }) { + const resources = { + [depURL]: { + body: depBody, + integrity + } + }; + const manifest = { + resources: {}, + }; + for (const [url, { body, integrity }] of Object.entries(resources)) { + manifest.resources[url] = { + integrity, + }; + fs.writeFileSync(new URL(url, tmpdirURL.href), body); + } + fs.writeFileSync(policyFilepath, JSON.stringify(manifest, null, 2)); + const { status } = spawnSync(process.execPath, [ + '--experimental-policy', + policyFilepath, + depFilepath + ]); + if (shouldFail) { + assert.notStrictEqual(status, 0); + } else { + assert.strictEqual(status, 0); + } +} + +test({ + shouldFail: false, + integrity: `sha256-${hash('sha256', depBody)}`, +}); +test({ + shouldFail: true, + integrity: `1sha256-${hash('sha256', depBody)}`, +}); +test({ + shouldFail: true, + integrity: 'hoge', +}); +test({ + shouldFail: true, + integrity: `sha256-${hash('sha256', depBody)}sha256-${hash( + 'sha256', + depBody + )}`, +}); diff --git a/test/parallel/test-process-abort.js b/test/parallel/test-process-abort.js new file mode 100644 index 00000000000000..665e1399a3f362 --- /dev/null +++ b/test/parallel/test-process-abort.js @@ -0,0 +1,12 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +if (!common.isMainThread) + common.skip('process.abort() is not available in Workers'); + +// Check that our built-in methods do not have a prototype/constructor behaviour +// if they don't need to. This could be tested for any of our C++ methods. +assert.strictEqual(process.abort.prototype, undefined); +assert.throws(() => new process.abort(), TypeError); diff --git a/test/parallel/test-process-chdir.js b/test/parallel/test-process-chdir.js index 005e17fac25a90..e66d366fb7874f 100644 --- a/test/parallel/test-process-chdir.js +++ b/test/parallel/test-process-chdir.js @@ -42,8 +42,3 @@ const err = { }; common.expectsError(function() { process.chdir({}); }, err); common.expectsError(function() { process.chdir(); }, err); - -// Check that our built-in methods do not have a prototype/constructor behaviour -// if they don't need to. This could be tested for any of our C++ methods. -assert.strictEqual(process.cwd.prototype, undefined); -assert.throws(() => new process.cwd(), TypeError); diff --git a/test/parallel/test-repl-tab-complete.js b/test/parallel/test-repl-tab-complete.js index 02cd06c9534bc5..364d880e8cc479 100644 --- a/test/parallel/test-repl-tab-complete.js +++ b/test/parallel/test-repl-tab-complete.js @@ -397,6 +397,45 @@ testMe.complete('obj.', common.mustCall((error, data) => { assert(data[0].includes('obj.key')); })); +// Tab completion for files/directories +{ + putIn.run(['.clear']); + process.chdir(__dirname); + + const readFileSync = 'fs.readFileSync("'; + const fixturePath = `${readFileSync}../fixtures/test-repl-tab-completion`; + if (!common.isWindows) { + testMe.complete(fixturePath, common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.ok(data[0][0].includes('.hiddenfiles')); + assert.ok(data[0][1].includes('hellorandom.txt')); + assert.ok(data[0][2].includes('helloworld.js')); + })); + + testMe.complete(`${fixturePath}/hello`, + common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.ok(data[0][0].includes('hellorandom.txt')); + assert.ok(data[0][1].includes('helloworld.js')); + }) + ); + + testMe.complete(`${fixturePath}/.h`, + common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.ok(data[0][0].includes('.hiddenfiles')); + }) + ); + + testMe.complete(`${readFileSync}./xxxRandom/random`, + common.mustCall((err, data) => { + assert.strictEqual(err, null); + assert.strictEqual(data[0].length, 0); + }) + ); + } +} + [ Array, Buffer, diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index f9f5d196aa3e6b..c0869c84b30b71 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -328,6 +328,21 @@ const errorTests = [ send: '1 }', expect: '{ a: 1 }' }, + // Multiline class with private member. + { + send: 'class Foo { #private = true ', + expect: '... ' + }, + // Class field with bigint. + { + send: 'num = 123456789n', + expect: '... ' + }, + // Static class features. + { + send: 'static foo = "bar" }', + expect: 'undefined' + }, // Multiline anonymous function with comment { send: '(function() {', @@ -338,12 +353,12 @@ const errorTests = [ expect: '... ' }, { - send: 'return 1;', + send: 'return 1n;', expect: '... ' }, { send: '})()', - expect: '1' + expect: '1n' }, // Multiline function call { diff --git a/test/parallel/test-require-mjs.js b/test/parallel/test-require-mjs.js new file mode 100644 index 00000000000000..69f8527555db71 --- /dev/null +++ b/test/parallel/test-require-mjs.js @@ -0,0 +1,11 @@ +'use strict'; +require('../common'); +const assert = require('assert'); + +assert.throws( + () => require('../fixtures/es-modules/test-esm-ok.mjs'), + { + message: /Must use import to load ES Module/, + code: 'ERR_REQUIRE_ESM' + } +); diff --git a/test/parallel/test-tls-cli-min-max-conflict.js b/test/parallel/test-tls-cli-min-max-conflict.js new file mode 100644 index 00000000000000..68aae4c635bcec --- /dev/null +++ b/test/parallel/test-tls-cli-min-max-conflict.js @@ -0,0 +1,14 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) common.skip('missing crypto'); + +// Check that conflicting TLS protocol versions are not allowed + +const assert = require('assert'); +const child_process = require('child_process'); + +const args = ['--tls-min-v1.3', '--tls-max-v1.2', '-p', 'process.version']; +child_process.execFile(process.argv[0], args, (err) => { + assert(err); + assert(/not both/.test(err.message)); +}); diff --git a/test/parallel/test-tls-cli-min-version-1.2.js b/test/parallel/test-tls-cli-min-version-1.2.js new file mode 100644 index 00000000000000..8385eabd0baba0 --- /dev/null +++ b/test/parallel/test-tls-cli-min-version-1.2.js @@ -0,0 +1,15 @@ +// Flags: --tls-min-v1.2 +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) common.skip('missing crypto'); + +// Check that node `--tls-min-v1.2` is supported. + +const assert = require('assert'); +const tls = require('tls'); + +assert.strictEqual(tls.DEFAULT_MAX_VERSION, 'TLSv1.3'); +assert.strictEqual(tls.DEFAULT_MIN_VERSION, 'TLSv1.2'); + +// Check the min-max version protocol versions against these CLI settings. +require('./test-tls-min-max-version.js'); diff --git a/test/parallel/test-tls-enable-trace-cli.js b/test/parallel/test-tls-enable-trace-cli.js new file mode 100644 index 00000000000000..5b7189af702dad --- /dev/null +++ b/test/parallel/test-tls-enable-trace-cli.js @@ -0,0 +1,59 @@ +// Flags: --expose-internals +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) common.skip('missing crypto'); +const fixtures = require('../common/fixtures'); + +// Test --trace-tls CLI flag. + +const assert = require('assert'); +const { fork } = require('child_process'); + +if (process.argv[2] === 'test') + return test(); + +const binding = require('internal/test/binding').internalBinding; + +if (!binding('tls_wrap').HAVE_SSL_TRACE) + return common.skip('no SSL_trace() compiled into openssl'); + +const child = fork(__filename, ['test'], { + silent: true, + execArgv: ['--trace-tls'] +}); + +let stderr = ''; +child.stderr.setEncoding('utf8'); +child.stderr.on('data', (data) => stderr += data); +child.on('close', common.mustCall(() => { + assert(/Warning: Enabling --trace-tls can expose sensitive/.test(stderr)); + assert(/Received Record/.test(stderr)); + assert(/ClientHello/.test(stderr)); +})); + +// For debugging and observation of actual trace output. +child.stderr.pipe(process.stderr); +child.stdout.pipe(process.stdout); + +child.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); +})); + +function test() { + const { + connect, keys + } = require(fixtures.path('tls-connect')); + + connect({ + client: { + checkServerIdentity: (servername, cert) => { }, + ca: `${keys.agent1.cert}\n${keys.agent6.ca}`, + }, + server: { + cert: keys.agent6.cert, + key: keys.agent6.key + }, + }, common.mustCall((err, pair, cleanup) => { + return cleanup(); + })); +} diff --git a/test/parallel/test-tls-enable-trace.js b/test/parallel/test-tls-enable-trace.js new file mode 100644 index 00000000000000..a3b1721ade10c2 --- /dev/null +++ b/test/parallel/test-tls-enable-trace.js @@ -0,0 +1,58 @@ +// Flags: --expose-internals +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) common.skip('missing crypto'); +const fixtures = require('../common/fixtures'); + +// Test enableTrace: option for TLS. + +const assert = require('assert'); +const { fork } = require('child_process'); + +if (process.argv[2] === 'test') + return test(); + +const binding = require('internal/test/binding').internalBinding; + +if (!binding('tls_wrap').HAVE_SSL_TRACE) + return common.skip('no SSL_trace() compiled into openssl'); + +const child = fork(__filename, ['test'], { silent: true }); + +let stderr = ''; +child.stderr.setEncoding('utf8'); +child.stderr.on('data', (data) => stderr += data); +child.on('close', common.mustCall(() => { + assert(/Received Record/.test(stderr)); + assert(/ClientHello/.test(stderr)); +})); + +// For debugging and observation of actual trace output. +child.stderr.pipe(process.stderr); +child.stdout.pipe(process.stdout); + +child.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); +})); + +function test() { + const { + connect, keys + } = require(fixtures.path('tls-connect')); + + connect({ + client: { + checkServerIdentity: (servername, cert) => { }, + ca: `${keys.agent1.cert}\n${keys.agent6.ca}`, + }, + server: { + cert: keys.agent6.cert, + key: keys.agent6.key, + enableTrace: true, + }, + }, common.mustCall((err, pair, cleanup) => { + pair.client.conn.enableTrace(); + + return cleanup(); + })); +} diff --git a/test/parallel/test-tls-sni-server-client.js b/test/parallel/test-tls-sni-server-client.js index 8ab025667ea68a..79f3601561ee19 100644 --- a/test/parallel/test-tls-sni-server-client.js +++ b/test/parallel/test-tls-sni-server-client.js @@ -54,73 +54,77 @@ const SNIContexts = { } }; -const clientsOptions = [{ - port: undefined, - ca: [loadPEM('ca1-cert')], - servername: 'a.example.com', - rejectUnauthorized: false -}, { - port: undefined, - ca: [loadPEM('ca2-cert')], - servername: 'b.test.com', - rejectUnauthorized: false -}, { - port: undefined, - ca: [loadPEM('ca2-cert')], - servername: 'a.b.test.com', - rejectUnauthorized: false -}, { - port: undefined, - ca: [loadPEM('ca1-cert')], - servername: 'c.wrong.com', - rejectUnauthorized: false -}, { - port: undefined, - ca: [loadPEM('ca1-cert')], - servername: 'chain.example.com', - rejectUnauthorized: false -}]; - -const serverResults = []; -const clientResults = []; - -const server = tls.createServer(serverOptions, function(c) { - serverResults.push(c.servername); - c.end(); -}); - -server.addContext('a.example.com', SNIContexts['a.example.com']); -server.addContext('*.test.com', SNIContexts['asterisk.test.com']); -server.addContext('chain.example.com', SNIContexts['chain.example.com']); - -server.listen(0, startTest); - -function startTest() { - let i = 0; - function start() { - // No options left - if (i === clientsOptions.length) - return server.close(); - - const options = clientsOptions[i++]; - options.port = server.address().port; - const client = tls.connect(options, function() { - clientResults.push( - client.authorizationError && - (client.authorizationError === 'ERR_TLS_CERT_ALTNAME_INVALID')); - - // Continue - start(); +test( + { + ca: [loadPEM('ca1-cert')], + servername: 'a.example.com' + }, + true, + 'a.example.com' +); + +test( + { + ca: [loadPEM('ca2-cert')], + servername: 'b.test.com', + }, + true, + 'b.test.com' +); + +test( + { + ca: [loadPEM('ca2-cert')], + servername: 'a.b.test.com', + }, + false, + 'a.b.test.com' +); + +test( + { + ca: [loadPEM('ca1-cert')], + servername: 'c.wrong.com', + }, + false, + 'c.wrong.com' +); + +test( + { + ca: [loadPEM('ca1-cert')], + servername: 'chain.example.com', + }, + true, + 'chain.example.com' +); + +function test(options, clientResult, serverResult) { + const server = tls.createServer(serverOptions, (c) => { + assert.strictEqual(c.servername, serverResult); + assert.strictEqual(c.authorized, false); + }); + + server.addContext('a.example.com', SNIContexts['a.example.com']); + server.addContext('*.test.com', SNIContexts['asterisk.test.com']); + server.addContext('chain.example.com', SNIContexts['chain.example.com']); + + server.on('tlsClientError', common.mustNotCall()); + + server.listen(0, () => { + const client = tls.connect({ + ...options, + port: server.address().port, + rejectUnauthorized: false + }, () => { + const result = client.authorizationError && + (client.authorizationError === 'ERR_TLS_CERT_ALTNAME_INVALID'); + assert.strictEqual(result, clientResult); + client.end(); }); - } - start(); + client.on('close', common.mustCall(() => { + server.close(); + })); + }); } - -process.on('exit', function() { - assert.deepStrictEqual(serverResults, [ - 'a.example.com', 'b.test.com', 'a.b.test.com', 'c.wrong.com', - 'chain.example.com' - ]); - assert.deepStrictEqual(clientResults, [true, true, false, false, true]); -}); diff --git a/test/parallel/test-util-format.js b/test/parallel/test-util-format.js index 206b66e17c3be0..6e5c50ab406b83 100644 --- a/test/parallel/test-util-format.js +++ b/test/parallel/test-util-format.js @@ -53,7 +53,9 @@ assert.strictEqual(util.format('%d', '42'), '42'); assert.strictEqual(util.format('%d', '42.0'), '42'); assert.strictEqual(util.format('%d', 1.5), '1.5'); assert.strictEqual(util.format('%d', -0.5), '-0.5'); +assert.strictEqual(util.format('%d', -0.0), '-0'); assert.strictEqual(util.format('%d', ''), '0'); +assert.strictEqual(util.format('%d', ' -0.000'), '-0'); assert.strictEqual(util.format('%d', Symbol()), 'NaN'); assert.strictEqual(util.format('%d %d', 42, 43), '42 43'); assert.strictEqual(util.format('%d %d', 42), '42 %d'); @@ -77,7 +79,7 @@ assert.strictEqual(util.format('%i', 42), '42'); assert.strictEqual(util.format('%i', '42'), '42'); assert.strictEqual(util.format('%i', '42.0'), '42'); assert.strictEqual(util.format('%i', 1.5), '1'); -assert.strictEqual(util.format('%i', -0.5), '0'); +assert.strictEqual(util.format('%i', -0.5), '-0'); assert.strictEqual(util.format('%i', ''), 'NaN'); assert.strictEqual(util.format('%i', Symbol()), 'NaN'); assert.strictEqual(util.format('%i %i', 42, 43), '42 43'); @@ -110,6 +112,7 @@ assert.strictEqual(util.format('%f'), '%f'); assert.strictEqual(util.format('%f', 42.0), '42'); assert.strictEqual(util.format('%f', 42), '42'); assert.strictEqual(util.format('%f', '42'), '42'); +assert.strictEqual(util.format('%f', '-0.0'), '-0'); assert.strictEqual(util.format('%f', '42.0'), '42'); assert.strictEqual(util.format('%f', 1.5), '1.5'); assert.strictEqual(util.format('%f', -0.5), '-0.5'); @@ -127,6 +130,8 @@ assert.strictEqual(util.format('%s', null), 'null'); assert.strictEqual(util.format('%s', 'foo'), 'foo'); assert.strictEqual(util.format('%s', 42), '42'); assert.strictEqual(util.format('%s', '42'), '42'); +assert.strictEqual(util.format('%s', -0), '-0'); +assert.strictEqual(util.format('%s', '-0.0'), '-0.0'); assert.strictEqual(util.format('%s %s', 42, 43), '42 43'); assert.strictEqual(util.format('%s %s', 42), '42 %s'); assert.strictEqual(util.format('%s', 42n), '42n'); diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 5ac270f5f84e9a..4ecb69997863b0 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -33,11 +33,51 @@ assert.strictEqual(util.inspect(1), '1'); assert.strictEqual(util.inspect(false), 'false'); assert.strictEqual(util.inspect(''), "''"); assert.strictEqual(util.inspect('hello'), "'hello'"); -assert.strictEqual(util.inspect(function() {}), '[Function]'); +assert.strictEqual(util.inspect(function abc() {}), '[Function: abc]'); assert.strictEqual(util.inspect(() => {}), '[Function]'); -assert.strictEqual(util.inspect(async function() {}), '[AsyncFunction]'); +assert.strictEqual( + util.inspect(async function() {}), + '[AsyncFunction]' +); assert.strictEqual(util.inspect(async () => {}), '[AsyncFunction]'); -assert.strictEqual(util.inspect(function*() {}), '[GeneratorFunction]'); + +// Special function inspection. +{ + const fn = (() => function*() {})(); + assert.strictEqual( + util.inspect(fn), + '[GeneratorFunction]' + ); + Object.setPrototypeOf(fn, Object.getPrototypeOf(async () => {})); + assert.strictEqual( + util.inspect(fn), + '[GeneratorFunction] AsyncFunction' + ); + Object.defineProperty(fn, 'name', { value: 5, configurable: true }); + assert.strictEqual( + util.inspect(fn), + '[GeneratorFunction: 5] AsyncFunction' + ); + Object.defineProperty(fn, Symbol.toStringTag, { + value: 'Foobar', + configurable: true + }); + assert.strictEqual( + util.inspect({ ['5']: fn }), + "{ '5': [GeneratorFunction: 5] AsyncFunction [Foobar] }" + ); + Object.defineProperty(fn, 'name', { value: '5', configurable: true }); + Object.setPrototypeOf(fn, null); + assert.strictEqual( + util.inspect(fn), + '[GeneratorFunction (null prototype): 5] [Foobar]' + ); + assert.strictEqual( + util.inspect({ ['5']: fn }), + "{ '5': [GeneratorFunction (null prototype): 5] [Foobar] }" + ); +} + assert.strictEqual(util.inspect(undefined), 'undefined'); assert.strictEqual(util.inspect(null), 'null'); assert.strictEqual(util.inspect(/foo(bar\n)?/gi), '/foo(bar\\n)?/gi'); @@ -59,8 +99,9 @@ assert.strictEqual(util.inspect({}), '{}'); assert.strictEqual(util.inspect({ a: 1 }), '{ a: 1 }'); assert.strictEqual(util.inspect({ a: function() {} }), '{ a: [Function: a] }'); assert.strictEqual(util.inspect({ a: () => {} }), '{ a: [Function: a] }'); -assert.strictEqual(util.inspect({ a: async function() {} }), - '{ a: [AsyncFunction: a] }'); +// eslint-disable-next-line func-name-matching +assert.strictEqual(util.inspect({ a: async function abc() {} }), + '{ a: [AsyncFunction: abc] }'); assert.strictEqual(util.inspect({ a: async () => {} }), '{ a: [AsyncFunction: a] }'); assert.strictEqual(util.inspect({ a: function*() {} }), @@ -411,7 +452,10 @@ assert.strictEqual( { const value = (() => function() {})(); value.aprop = 42; - assert.strictEqual(util.inspect(value), '[Function] { aprop: 42 }'); + assert.strictEqual( + util.inspect(value), + '[Function] { aprop: 42 }' + ); } // Regular expressions with properties. @@ -1614,7 +1658,7 @@ util.inspect(process); assert.strict.equal(out, expected); } -{ // Test WeakMap +{ // Test WeakMap && WeakSet const obj = {}; const arr = []; const weakMap = new WeakMap([[obj, arr], [arr, obj]]); @@ -1634,16 +1678,16 @@ util.inspect(process); out = util.inspect(weakMap, { maxArrayLength: 1, showHidden: true }); // It is not possible to determine the output reliable. expect = 'WeakMap { [ [length]: 0 ] => {}, ... 1 more item, extra: true }'; - const expectAlt = 'WeakMap { {} => [ [length]: 0 ], ... 1 more item, ' + - 'extra: true }'; + let expectAlt = 'WeakMap { {} => [ [length]: 0 ], ... 1 more item, ' + + 'extra: true }'; assert(out === expect || out === expectAlt, `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`); -} -{ // Test WeakSet - const weakSet = new WeakSet([{}, [1]]); - let out = util.inspect(weakSet, { showHidden: true }); - let expect = 'WeakSet { [ 1, [length]: 1 ], {} }'; + // Test WeakSet + arr.push(1); + const weakSet = new WeakSet([obj, arr]); + out = util.inspect(weakSet, { showHidden: true }); + expect = 'WeakSet { [ 1, [length]: 1 ], {} }'; assert.strictEqual(out, expect); out = util.inspect(weakSet); @@ -1658,10 +1702,12 @@ util.inspect(process); out = util.inspect(weakSet, { maxArrayLength: 1, showHidden: true }); // It is not possible to determine the output reliable. expect = 'WeakSet { {}, ... 1 more item, extra: true }'; - const expectAlt = 'WeakSet { [ 1, [length]: 1 ], ... 1 more item, ' + - 'extra: true }'; + expectAlt = 'WeakSet { [ 1, [length]: 1 ], ... 1 more item, extra: true }'; assert(out === expect || out === expectAlt, `Found: "${out}"\nrather than: "${expect}"\nor: "${expectAlt}"`); + // Keep references to the WeakMap entries, otherwise they could be GCed too + // early. + assert(obj && arr); } { // Test argument objects. @@ -1955,10 +2001,14 @@ assert.strictEqual( let value = (function() { return function() {}; })(); Object.setPrototypeOf(value, null); Object.setPrototypeOf(obj, value); - assert.strictEqual(util.inspect(obj), '<[Function]> { a: true }'); + assert.strictEqual( + util.inspect(obj), + 'Object <[Function (null prototype)]> { a: true }' + ); assert.strictEqual( util.inspect(obj, { colors: true }), - '<\u001b[36m[Function]\u001b[39m> { a: \u001b[33mtrue\u001b[39m }' + 'Object <\u001b[36m[Function (null prototype)]\u001b[39m> ' + + '{ a: \u001b[33mtrue\u001b[39m }' ); obj = { a: true }; @@ -1967,14 +2017,14 @@ assert.strictEqual( Object.setPrototypeOf(obj, value); assert.strictEqual( util.inspect(obj), - '<[Array: null prototype] []> { a: true }' + 'Object <[Array: null prototype] []> { a: true }' ); function StorageObject() {} StorageObject.prototype = Object.create(null); assert.strictEqual( util.inspect(new StorageObject()), - '<[Object: null prototype] {}> {}' + 'StorageObject <[Object: null prototype] {}> {}' ); obj = [1, 2, 3]; @@ -1984,7 +2034,7 @@ assert.strictEqual( Object.setPrototypeOf(obj, Object.create(null)); assert.strictEqual( inspect(obj), - "<[Object: null prototype] {}> { '0': 1, '1': 2, '2': 3 }" + "Array <[Object: null prototype] {}> { '0': 1, '1': 2, '2': 3 }" ); } diff --git a/test/parallel/test-worker-process-cwd.js b/test/parallel/test-worker-process-cwd.js new file mode 100644 index 00000000000000..dec70ac07c8f11 --- /dev/null +++ b/test/parallel/test-worker-process-cwd.js @@ -0,0 +1,44 @@ +'use strict'; +const assert = require('assert'); +const common = require('../common'); +const { Worker, isMainThread, parentPort } = require('worker_threads'); + +// Do not use isMainThread directly, otherwise the test would time out in case +// it's started inside of another worker thread. +if (!process.env.HAS_STARTED_WORKER) { + process.env.HAS_STARTED_WORKER = '1'; + if (!isMainThread) { + common.skip('This test can only run as main thread'); + } + const w = new Worker(__filename); + process.chdir('..'); + w.on('message', common.mustCall((message) => { + assert.strictEqual(message, process.cwd()); + process.chdir('..'); + w.postMessage(process.cwd()); + })); +} else if (!process.env.SECOND_WORKER) { + process.env.SECOND_WORKER = '1'; + const firstCwd = process.cwd(); + const w = new Worker(__filename); + w.on('message', common.mustCall((message) => { + assert.strictEqual(message, process.cwd()); + parentPort.postMessage(firstCwd); + parentPort.onmessage = common.mustCall((obj) => { + const secondCwd = process.cwd(); + assert.strictEqual(secondCwd, obj.data); + assert.notStrictEqual(secondCwd, firstCwd); + w.postMessage(secondCwd); + parentPort.unref(); + }); + })); +} else { + const firstCwd = process.cwd(); + parentPort.postMessage(firstCwd); + parentPort.onmessage = common.mustCall((obj) => { + const secondCwd = process.cwd(); + assert.strictEqual(secondCwd, obj.data); + assert.notStrictEqual(secondCwd, firstCwd); + process.exit(); + }); +} diff --git a/test/report/test-report-uv-handles.js b/test/report/test-report-uv-handles.js index 51677168947bf4..20619204325f41 100644 --- a/test/report/test-report-uv-handles.js +++ b/test/report/test-report-uv-handles.js @@ -85,7 +85,7 @@ if (process.argv[2] === 'child') { const report_msg = 'Report files were written: unexpectedly'; child.stdout.on('data', (chunk) => { stdout += chunk; }); child.on('exit', common.mustCall((code, signal) => { - assert.deepStrictEqual(code, 0, 'Process exited unexpectedly with code' + + assert.deepStrictEqual(code, 0, 'Process exited unexpectedly with code: ' + `${code}`); assert.deepStrictEqual(signal, null, 'Process should have exited cleanly,' + ` but did not: ${signal}`); diff --git a/test/sequential/test-async-wrap-getasyncid.js b/test/sequential/test-async-wrap-getasyncid.js index e3cfd6bef01bc9..9f5c073c9e2d06 100644 --- a/test/sequential/test-async-wrap-getasyncid.js +++ b/test/sequential/test-async-wrap-getasyncid.js @@ -152,7 +152,10 @@ if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check { const { HTTPParser } = require('_http_common'); - testInitialized(new HTTPParser(HTTPParser.REQUEST), 'HTTPParser'); + const parser = new HTTPParser(); + testUninitialized(parser, 'HTTPParser'); + parser.initialize(HTTPParser.REQUEST, {}); + testInitialized(parser, 'HTTPParser'); } diff --git a/test/sequential/test-cpu-prof.js b/test/sequential/test-cpu-prof.js index 726f99b799db31..38be6211e4d23f 100644 --- a/test/sequential/test-cpu-prof.js +++ b/test/sequential/test-cpu-prof.js @@ -3,12 +3,6 @@ // This tests that --cpu-prof, --cpu-prof-dir and --cpu-prof-name works. const common = require('../common'); -if (process.features.debug && process.features.cached_builtins) { - // FIXME(joyeecheung): the profiler crashes when code cache - // is enabled in debug builds. - common.skip('--cpu-prof does not work in debug builds with code cache'); -} - const fixtures = require('../common/fixtures'); common.skipIfInspectorDisabled(); @@ -56,18 +50,43 @@ if (common.isWindows) { FIB = 40; } +// We need to set --cpu-interval to a smaller value to make sure we can +// find our workload in the samples. 50us should be a small enough sampling +// interval for this. +const kCpuProfInterval = 50; const env = { ...process.env, FIB, NODE_DEBUG_NATIVE: 'INSPECTOR_PROFILER' }; +// Test --cpu-prof without --cpu-prof-interval. Here we just verify that +// we manage to generate a profile. +{ + tmpdir.refresh(); + const output = spawnSync(process.execPath, [ + '--cpu-prof', + fixtures.path('workload', 'fibonacci.js'), + ], { + cwd: tmpdir.path, + env + }); + if (output.status !== 0) { + console.log(output.stderr.toString()); + } + assert.strictEqual(output.status, 0); + const profiles = getCpuProfiles(tmpdir.path); + assert.strictEqual(profiles.length, 1); +} + // Outputs CPU profile when event loop is drained. // TODO(joyeecheung): share the fixutres with v8 coverage tests { tmpdir.refresh(); const output = spawnSync(process.execPath, [ '--cpu-prof', + '--cpu-prof-interval', + kCpuProfInterval, fixtures.path('workload', 'fibonacci.js'), ], { cwd: tmpdir.path, @@ -87,6 +106,8 @@ const env = { tmpdir.refresh(); const output = spawnSync(process.execPath, [ '--cpu-prof', + '--cpu-prof-interval', + kCpuProfInterval, fixtures.path('workload', 'fibonacci-exit.js'), ], { cwd: tmpdir.path, @@ -106,6 +127,8 @@ const env = { tmpdir.refresh(); const output = spawnSync(process.execPath, [ '--cpu-prof', + '--cpu-prof-interval', + kCpuProfInterval, fixtures.path('workload', 'fibonacci-sigint.js'), ], { cwd: tmpdir.path, @@ -129,7 +152,10 @@ const env = { fixtures.path('workload', 'fibonacci-worker-argv.js'), ], { cwd: tmpdir.path, - env + env: { + ...process.env, + CPU_PROF_INTERVAL: kCpuProfInterval + } }); if (output.status !== 0) { console.log(output.stderr.toString()); @@ -182,12 +208,35 @@ const env = { `${process.execPath}: --cpu-prof-dir must be used with --cpu-prof`); } +// --cpu-prof-interval without --cpu-prof +{ + tmpdir.refresh(); + const output = spawnSync(process.execPath, [ + '--cpu-prof-interval', + kCpuProfInterval, + fixtures.path('workload', 'fibonacci.js'), + ], { + cwd: tmpdir.path, + env + }); + const stderr = output.stderr.toString().trim(); + if (output.status !== 9) { + console.log(stderr); + } + assert.strictEqual(output.status, 9); + assert.strictEqual( + stderr, + `${process.execPath}: --cpu-prof-interval must be used with --cpu-prof`); +} + // --cpu-prof-name { tmpdir.refresh(); const file = path.join(tmpdir.path, 'test.cpuprofile'); const output = spawnSync(process.execPath, [ '--cpu-prof', + '--cpu-prof-interval', + kCpuProfInterval, '--cpu-prof-name', 'test.cpuprofile', fixtures.path('workload', 'fibonacci.js'), @@ -209,6 +258,8 @@ const env = { tmpdir.refresh(); const output = spawnSync(process.execPath, [ '--cpu-prof', + '--cpu-prof-interval', + kCpuProfInterval, '--cpu-prof-dir', 'prof', fixtures.path('workload', 'fibonacci.js'), @@ -233,6 +284,8 @@ const env = { const dir = path.join(tmpdir.path, 'prof'); const output = spawnSync(process.execPath, [ '--cpu-prof', + '--cpu-prof-interval', + kCpuProfInterval, '--cpu-prof-dir', dir, fixtures.path('workload', 'fibonacci.js'), @@ -257,6 +310,8 @@ const env = { const file = path.join(dir, 'test.cpuprofile'); const output = spawnSync(process.execPath, [ '--cpu-prof', + '--cpu-prof-interval', + kCpuProfInterval, '--cpu-prof-name', 'test.cpuprofile', '--cpu-prof-dir', @@ -280,6 +335,8 @@ const env = { { tmpdir.refresh(); const output = spawnSync(process.execPath, [ + '--cpu-prof-interval', + kCpuProfInterval, '--cpu-prof-dir', 'prof', '--cpu-prof', diff --git a/test/sequential/test-http-regr-gh-2928.js b/test/sequential/test-http-regr-gh-2928.js index 400dc02013325d..5111e234d168f5 100644 --- a/test/sequential/test-http-regr-gh-2928.js +++ b/test/sequential/test-http-regr-gh-2928.js @@ -7,7 +7,6 @@ const common = require('../common'); const assert = require('assert'); const httpCommon = require('_http_common'); const { HTTPParser } = require('_http_common'); -const { AsyncResource } = require('async_hooks'); const net = require('net'); const COUNT = httpCommon.parsers.max + 1; @@ -25,7 +24,7 @@ function execAndClose() { process.stdout.write('.'); const parser = parsers.pop(); - parser.initialize(HTTPParser.RESPONSE, new AsyncResource('ClientRequest')); + parser.initialize(HTTPParser.RESPONSE, {}); const socket = net.connect(common.PORT); socket.on('error', (e) => { diff --git a/tools/eslint-rules/required-modules.js b/tools/eslint-rules/required-modules.js index f22b14caac4183..64b3d748afa630 100644 --- a/tools/eslint-rules/required-modules.js +++ b/tools/eslint-rules/required-modules.js @@ -46,6 +46,10 @@ module.exports = function(context) { * @returns {undefined|String} required module name or undefined */ function getRequiredModuleName(str) { + if (str === '../common/index.mjs') { + return 'common'; + } + const value = path.basename(str); // Check if value is in required modules array diff --git a/tools/license-builder.sh b/tools/license-builder.sh index b29e8435228ea8..d4c39203884df3 100755 --- a/tools/license-builder.sh +++ b/tools/license-builder.sh @@ -30,6 +30,7 @@ fi # Dependencies bundled in distributions addlicense "Acorn" "deps/acorn" "$(cat ${rootdir}/deps/acorn/acorn/LICENSE)" +addlicense "Acorn plugins" "deps/acorn-plugins" "$(cat ${rootdir}/deps/acorn-plugins/acorn-bigint/LICENSE)" addlicense "c-ares" "deps/cares" "$(tail -n +3 ${rootdir}/deps/cares/LICENSE.md)" addlicense "HTTP Parser" "deps/http_parser" "$(cat deps/http_parser/LICENSE-MIT)" if [ -f "${rootdir}/deps/icu/LICENSE" ]; then