diff --git a/.eslintrc.js b/.eslintrc.js index 6a8403d3488a2f..0b4c170813d0a7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,7 +17,7 @@ Module._findPath = (request, paths, isMain) => { if (!r && hacks.includes(request)) { try { return require.resolve(`./tools/node_modules/${request}`); - } catch (err) { + } catch { return require.resolve( `./tools/node_modules/eslint/node_modules/${request}`); } @@ -212,7 +212,7 @@ module.exports = { 'no-unsafe-finally': 'error', 'no-unsafe-negation': 'error', 'no-unused-labels': 'error', - 'no-unused-vars': ['error', { args: 'none' }], + 'no-unused-vars': ['error', { args: 'none', caughtErrors: 'all' }], 'no-use-before-define': ['error', { classes: true, functions: false, diff --git a/.travis.yml b/.travis.yml index 21ec6dab70f994..e496919579b2f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,14 +4,21 @@ cache: ccache os: linux matrix: include: + - name: "First commit message adheres to guidelines at https://goo.gl/p2fr5Q" + if: type = pull_request + language: node_js + node_js: "node" + script: + - if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then + bash -x tools/lint-pr-commit-message.sh ${TRAVIS_PULL_REQUEST}; + fi - name: "Linter" - node_js: "latest" + language: node_js + node_js: "node" env: - NODE=$(which node) script: - make lint - # Lint the first commit in the PR. - - \[ -z "$TRAVIS_COMMIT_RANGE" \] || (echo -e '\nLinting the commit message according to the guidelines at https://goo.gl/p2fr5Q\n' && git log $TRAVIS_COMMIT_RANGE --pretty=format:'%h' --no-merges | tail -1 | xargs npx -q core-validate-commit --no-validate-metadata) - name: "Test Suite" addons: apt: diff --git a/BUILDING.md b/BUILDING.md index 7c5bd632f24ab0..63ddf8e7f4ff2a 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -70,8 +70,7 @@ There are three support tiers: ### Supported platforms The community does not build or test against end-of-life distributions (EoL). -Thus, we do not recommend that you use Node.js on end-of-life or unsupported -platforms in production. +For production applications, run Node.js on supported platforms only. | System | Support type | Version | Architectures | Notes | | ------------ | ------------ | ------------------------------- | ---------------- | ----------------------------- | @@ -96,8 +95,8 @@ platforms in production. by Joyent. SmartOS images >= 16.4 are not supported because GCC 4.8 runtime libraries are not available in their pkgsrc repository -2: Tier 1 support for building on Windows is only on 64 bit - hosts. Support is experimental for 32 bit hosts. +2: Tier 1 support for building on Windows is only on 64-bit + hosts. Support is experimental for 32-bit hosts. 3: On Windows, running Node.js in Windows terminal emulators like `mintty` requires the usage of [winpty](https://github.com/rprichard/winpty) @@ -115,7 +114,7 @@ platforms in production. ### Supported toolchains -Depending on host platform, the selection of toolchains may vary. +Depending on the host platform, the selection of toolchains may vary. #### Unix @@ -127,29 +126,28 @@ Depending on host platform, the selection of toolchains may vary. #### Windows -* Visual Studio 2017 with the Windows 10 SDK on a 64 bit host. +* Visual Studio 2017 with the Windows 10 SDK on a 64-bit host. #### OpenSSL asm support -OpenSSL-1.1.0 requires the following asssembler version for use of asm +OpenSSL-1.1.0 requires the following assembler version for use of asm support on x86_64 and ia32. * gas (GNU assembler) version 2.23 or higher -* xcode version 5.0 or higher +* Xcode version 5.0 or higher * llvm version 3.3 or higher * nasm version 2.10 or higher in Windows -Otherwise `configure` will fail with an error. This can be avoided by -either providing a newer assembler as per the list above or by -using the `--openssl-no-asm` flag. +If compiling without one of the above, use `configure` with the +`--openssl-no-asm` flag. Otherwise, `configure` will fail. The forthcoming OpenSSL-1.1.1 will have different requirements. Please refer to https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_ia32cap.html for details. ## Building Node.js on supported platforms -*Note:* All prerequisites can be easily installed by following -[this bootstrapping guide](https://github.com/nodejs/node/blob/master/tools/bootstrap/README.md). +The [bootstrapping guide](https://github.com/nodejs/node/blob/master/tools/bootstrap/README.md) +explains how to install all prerequisites. ### Unix/macOS @@ -160,7 +158,7 @@ The forthcoming OpenSSL-1.1.1 will have different requirements. Please refer to * Python 2.6 or 2.7 * GNU Make 3.81 or newer -On macOS, you will need to install the `Xcode Command Line Tools` by running +On macOS, install the `Xcode Command Line Tools` by running `xcode-select --install`. Alternatively, if you already have the full Xcode installed, you can find them under the menu `Xcode -> Open Developer Tool -> More Developer Tools...`. This step will install `clang`, `clang++`, and @@ -181,13 +179,9 @@ $ ./configure $ make -j4 ``` -Running `make` with the `-j4` flag will cause it to run 4 compilation jobs -concurrently which may significantly reduce build time. The number after `-j` -can be changed to best suit the number of processor cores on your machine. If -you run into problems running `make` with concurrency, try running it without -the `-j4` flag. See the -[GNU Make Documentation](https://www.gnu.org/software/make/manual/html_node/Parallel.html) -for more information. +The `-j4` option will cause `make` to run 4 simultaneous compilation jobs which +may reduce build time. For more information, see the +[GNU Make Documentation](https://www.gnu.org/software/make/manual/html_node/Parallel.html). Note that the above requires that `python` resolve to Python 2.6 or 2.7 and not a newer version. @@ -365,7 +359,7 @@ These core dumps are useful for debugging when provided with the corresponding original debug binary and system information. Reading the core dump requires `gdb` built on the same platform the core dump -was captured on (i.e. 64 bit `gdb` for `node` built on a 64 bit system, Linux +was captured on (i.e. 64-bit `gdb` for `node` built on a 64-bit system, Linux `gdb` for `node` built on Linux) otherwise you will get errors like `not in executable format: File format not recognized`. @@ -484,7 +478,7 @@ $ ./configure --without-intl $ pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu ``` -If you are cross compiling, your `pkg-config` must be able to supply a path +If you are cross-compiling, your `pkg-config` must be able to supply a path that works for both your host and target environments. #### Build with a specific ICU: @@ -532,7 +526,7 @@ This version of Node.js does not support FIPS. ## Building Node.js with external core modules It is possible to specify one or more JavaScript text files to be bundled in -the binary as builtin modules when building Node.js. +the binary as built-in modules when building Node.js. ### Unix/macOS diff --git a/CHANGELOG.md b/CHANGELOG.md index 6569f47757dca9..7cc40164b3f7b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,5 @@ # Node.js Changelog - - -To make the changelog easier to both use and manage, it has been split into -multiple files organized according to significant major and minor Node.js -release lines. - Select a Node.js version below to view the changelog history: * [Node.js 11](doc/changelogs/CHANGELOG_V11.md) - **Current** @@ -24,6 +18,7 @@ Select a Node.js version below to view the changelog history: Please use the following table to find the changelog for a specific Node.js release. + @@ -33,7 +28,8 @@ release. @@ -28,6 +29,279 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + +## 2018-11-15, Version 11.2.0 (Current), @BridgeAR + +### Notable changes + +* **deps**: + * A new experimental HTTP parser (`llhttp`) is now supported. https://github.com/nodejs/node/pull/24059 +* **timers**: + * Fixed an issue that could cause setTimeout to stop working as expected. https://github.com/nodejs/node/pull/24322 +* **Windows** + * A crashing process will now show the names of stack frames if the node.pdb file is available. https://github.com/nodejs/node/pull/23822 + * Continued effort to improve the installer's new stage that installs + native build tools. https://github.com/nodejs/node/pull/23987, https://github.com/nodejs/node/pull/24348 + * **child_process**: + * On Windows the `windowsHide` option default was restored to `false`. + This means `detached` child processes and GUI apps will once again + start in a new window. https://github.com/nodejs/node/pull/24034 +* **Added new collaborators**: + * [oyyd](https://github.com/oyyd) - Ouyang Yadong. https://github.com/nodejs/node/pull/24300 + * [psmarshall](https://github.com/psmarshall) - Peter Marshall. https://github.com/nodejs/node/pull/24170 + * [shisama](https://github.com/shisama) - Masashi Hirano. https://github.com/nodejs/node/pull/24136 + +### Commits + +* [[`685724b53d`](https://github.com/nodejs/node/commit/685724b53d)] - **assert**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`bb766ae05a`](https://github.com/nodejs/node/commit/bb766ae05a)] - **async_hooks**: add HandleScopes to C++ embedder/addon API (Anna Henningsen) [#24285](https://github.com/nodejs/node/pull/24285) +* [[`ad5c9b4463`](https://github.com/nodejs/node/commit/ad5c9b4463)] - **benchmark**: support more options in startup benchmark (Joyee Cheung) [#24220](https://github.com/nodejs/node/pull/24220) +* [[`d0bf8c2259`](https://github.com/nodejs/node/commit/d0bf8c2259)] - **benchmark**: add dir and withFileTypes option readdir benchmarks (Joyee Cheung) [#24125](https://github.com/nodejs/node/pull/24125) +* [[`40b3ad3eb8`](https://github.com/nodejs/node/commit/40b3ad3eb8)] - **benchmark**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`1f3cb63da3`](https://github.com/nodejs/node/commit/1f3cb63da3)] - **bootstrap**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`fcc25f9ee8`](https://github.com/nodejs/node/commit/fcc25f9ee8)] - **buffer**: fix writeUInt16BE range check (Brian White) [#24208](https://github.com/nodejs/node/pull/24208) +* [[`e4cd255a85`](https://github.com/nodejs/node/commit/e4cd255a85)] - **buffer**: throw exception when creating from non-Node.js Context (Anna Henningsen) [#23938](https://github.com/nodejs/node/pull/23938) +* [[`44ebdbb860`](https://github.com/nodejs/node/commit/44ebdbb860)] - **build**: fix benchmark tests on CI (Rich Trott) [#24307](https://github.com/nodejs/node/pull/24307) +* [[`1c8b4d7c89`](https://github.com/nodejs/node/commit/1c8b4d7c89)] - **build**: disable openssl asm on arm64 for now (Ben Noordhuis) [#24270](https://github.com/nodejs/node/pull/24270) +* [[`0c9d86f58c`](https://github.com/nodejs/node/commit/0c9d86f58c)] - **build**: use BUILDTYPE in bench-addons-build targets (Daniel Bevenius) [#24033](https://github.com/nodejs/node/pull/24033) +* [[`70699ee09b`](https://github.com/nodejs/node/commit/70699ee09b)] - **build**: lint commit message in separate Travis job (Richard Lau) [#24254](https://github.com/nodejs/node/pull/24254) +* [[`2b282e8f20`](https://github.com/nodejs/node/commit/2b282e8f20)] - **build**: move headers out of c++ src section (Daniel Bevenius) [#24124](https://github.com/nodejs/node/pull/24124) +* [[`a8008d1517`](https://github.com/nodejs/node/commit/a8008d1517)] - **build**: only try to find node when it's needed by the target (Joyee Cheung) [#24115](https://github.com/nodejs/node/pull/24115) +* [[`e4bcb97024`](https://github.com/nodejs/node/commit/e4bcb97024)] - **build**: change repo to https protocol in Makefile (mritunjaygoutam12) [#24073](https://github.com/nodejs/node/pull/24073) +* [[`7083b96c49`](https://github.com/nodejs/node/commit/7083b96c49)] - **build**: use latest node on travis (cjihrig) [#24198](https://github.com/nodejs/node/pull/24198) +* [[`99c2a10f7b`](https://github.com/nodejs/node/commit/99c2a10f7b)] - **build**: fix Travis non-PR builds (Richard Lau) [#24093](https://github.com/nodejs/node/pull/24093) +* [[`3de1c5cadd`](https://github.com/nodejs/node/commit/3de1c5cadd)] - **build**: do not lint on non-PR Travis builds (Anna Henningsen) [#24076](https://github.com/nodejs/node/pull/24076) +* [[`762679efec`](https://github.com/nodejs/node/commit/762679efec)] - **build**: make benchmark/napi all prereq order-only (Daniel Bevenius) [#23951](https://github.com/nodejs/node/pull/23951) +* [[`4651cd721d`](https://github.com/nodejs/node/commit/4651cd721d)] - **build**: add -Werror=undefined-inline to clang builds (Refael Ackermann) [#23961](https://github.com/nodejs/node/pull/23961) +* [[`e7133f1e7c`](https://github.com/nodejs/node/commit/e7133f1e7c)] - **build**: configure default v8\_optimized\_debug (Refael Ackermann) [#23704](https://github.com/nodejs/node/pull/23704) +* [[`26c19889a8`](https://github.com/nodejs/node/commit/26c19889a8)] - **build,meta**: don't fail Travis for commit message (Refael Ackermann) [#23739](https://github.com/nodejs/node/pull/23739) +* [[`838fb550c6`](https://github.com/nodejs/node/commit/838fb550c6)] - **build,tools**: update make-v8.sh for s390x (Refael Ackermann) [#23839](https://github.com/nodejs/node/pull/23839) +* [[`c07cce368a`](https://github.com/nodejs/node/commit/c07cce368a)] - ***Revert*** "**child_process**: change windowsHide default to true" (Rich Trott) [#24034](https://github.com/nodejs/node/pull/24034) +* [[`a1c7c1902a`](https://github.com/nodejs/node/commit/a1c7c1902a)] - **child_process**: allow 'http\_parser' monkey patching again (Jimb Esser) [#24006](https://github.com/nodejs/node/pull/24006) +* [[`4af63ee5d9`](https://github.com/nodejs/node/commit/4af63ee5d9)] - **child_process**: handle undefined/null for fork() args (Shobhit Chittora) [#22416](https://github.com/nodejs/node/pull/22416) +* [[`a2c13fac94`](https://github.com/nodejs/node/commit/a2c13fac94)] - **console**: console.timeLog() using the default label (Marie Terrier) [#24286](https://github.com/nodejs/node/pull/24286) +* [[`9e891327b7`](https://github.com/nodejs/node/commit/9e891327b7)] - **console**: cover .assert with single argument (Morgan Roderick) [#24188](https://github.com/nodejs/node/pull/24188) +* [[`2b48c7169a`](https://github.com/nodejs/node/commit/2b48c7169a)] - **crypto**: put legacy \_handle accessors on prototypes (Michaël Zasso) [#24269](https://github.com/nodejs/node/pull/24269) +* [[`f669817a5a`](https://github.com/nodejs/node/commit/f669817a5a)] - **(SEMVER-MINOR)** **crypto**: add support for chacha20-poly1305 for AEAD (chux0519) [#24081](https://github.com/nodejs/node/pull/24081) +* [[`ef69e7bcca`](https://github.com/nodejs/node/commit/ef69e7bcca)] - **deps**: backport 073073b4f1 from upstream V8 (Yang Guo) [#24274](https://github.com/nodejs/node/pull/24274) +* [[`a39493f4aa`](https://github.com/nodejs/node/commit/a39493f4aa)] - **deps**: cherry-pick b87d408 from upstream V8 (Peter Marshall) [#24272](https://github.com/nodejs/node/pull/24272) +* [[`9cefbba5d7`](https://github.com/nodejs/node/commit/9cefbba5d7)] - **deps**: patch V8 to 7.0.276.38 (Michaël Zasso) [#24271](https://github.com/nodejs/node/pull/24271) +* [[`115c57a240`](https://github.com/nodejs/node/commit/115c57a240)] - **deps**: introduce `llhttp` (Fedor Indutny) [#24059](https://github.com/nodejs/node/pull/24059) +* [[`566399ee31`](https://github.com/nodejs/node/commit/566399ee31)] - **deps**: patch V8 to 7.0.276.36 (Michaël Zasso) [#24109](https://github.com/nodejs/node/pull/24109) +* [[`3e1c53fe37`](https://github.com/nodejs/node/commit/3e1c53fe37)] - **deps**: cherry-pick 0483e9a from upstream V8 (Joyee Cheung) [#24125](https://github.com/nodejs/node/pull/24125) +* [[`6b697d4816`](https://github.com/nodejs/node/commit/6b697d4816)] - **deps**: c-ares float, version number patch (Ben Noordhuis) [#23854](https://github.com/nodejs/node/pull/23854) +* [[`07663694b4`](https://github.com/nodejs/node/commit/07663694b4)] - **deps**: upgrade to c-ares v1.15.0 (Ben Noordhuis) [#23854](https://github.com/nodejs/node/pull/23854) +* [[`eaea90b2ee`](https://github.com/nodejs/node/commit/eaea90b2ee)] - **deps**: remove old c-ares configure files (Ben Noordhuis) [#23854](https://github.com/nodejs/node/pull/23854) +* [[`f49b9e9c84`](https://github.com/nodejs/node/commit/f49b9e9c84)] - **deps**: patch V8 to 7.0.276.35 (Michaël Zasso) [#24056](https://github.com/nodejs/node/pull/24056) +* [[`6e4f238344`](https://github.com/nodejs/node/commit/6e4f238344)] - **deps,v8**: cherry-pick dc704497 (Refael Ackermann) [#23985](https://github.com/nodejs/node/pull/23985) +* [[`ef8b5b4094`](https://github.com/nodejs/node/commit/ef8b5b4094)] - **deps,v8**: fix gypfile bug (Refael Ackermann) [#23704](https://github.com/nodejs/node/pull/23704) +* [[`a01e829fb0`](https://github.com/nodejs/node/commit/a01e829fb0)] - **doc**: document http request.finished boolean (Thomas Watson) [#24319](https://github.com/nodejs/node/pull/24319) +* [[`36e4d0c6f0`](https://github.com/nodejs/node/commit/36e4d0c6f0)] - **doc**: document NODE\_TLS\_REJECT\_UNAUTHORIZED (cjihrig) [#24289](https://github.com/nodejs/node/pull/24289) +* [[`fbd0b037ec`](https://github.com/nodejs/node/commit/fbd0b037ec)] - **doc**: clarify issues and pull requests guidance (Rich Trott) [#24316](https://github.com/nodejs/node/pull/24316) +* [[`a993a488fa`](https://github.com/nodejs/node/commit/a993a488fa)] - **doc**: fix comma splices in process.md (Rich Trott) [#24357](https://github.com/nodejs/node/pull/24357) +* [[`e584cc52fc`](https://github.com/nodejs/node/commit/e584cc52fc)] - **doc**: use real protocol names in ALPN example (Sam Roberts) [#24232](https://github.com/nodejs/node/pull/24232) +* [[`7fc910763e`](https://github.com/nodejs/node/commit/7fc910763e)] - **doc**: update core-validate-commit url (Daijiro Wachi) [#24331](https://github.com/nodejs/node/pull/24331) +* [[`39382ed4e1`](https://github.com/nodejs/node/commit/39382ed4e1)] - **doc**: fix echo example programs (Sam Roberts) [#24235](https://github.com/nodejs/node/pull/24235) +* [[`c68b0ae46e`](https://github.com/nodejs/node/commit/c68b0ae46e)] - **doc**: update fs.open() changes record for optional 'flags' (Rod Vagg) [#24240](https://github.com/nodejs/node/pull/24240) +* [[`6b7e69875d`](https://github.com/nodejs/node/commit/6b7e69875d)] - **doc**: add links to Stream section (Dmitry Igrishin) [#24301](https://github.com/nodejs/node/pull/24301) +* [[`82c64d0008`](https://github.com/nodejs/node/commit/82c64d0008)] - **doc**: correct async\_hooks sample outputs (Gerhard Stoebich) [#24050](https://github.com/nodejs/node/pull/24050) +* [[`991d066338`](https://github.com/nodejs/node/commit/991d066338)] - **doc**: add oyyd to collaborators (Ouyang Yadong) [#24300](https://github.com/nodejs/node/pull/24300) +* [[`118d8d0feb`](https://github.com/nodejs/node/commit/118d8d0feb)] - **doc**: edit BUILDING.md (Rich Trott) [#24243](https://github.com/nodejs/node/pull/24243) +* [[`b5b5f9f8bd`](https://github.com/nodejs/node/commit/b5b5f9f8bd)] - **doc**: fix code examples in stream.md (Grant Carthew) [#24112](https://github.com/nodejs/node/pull/24112) +* [[`6ab46b5c47`](https://github.com/nodejs/node/commit/6ab46b5c47)] - **doc**: fix some inconsistent use of hostname (Sam Roberts) [#24199](https://github.com/nodejs/node/pull/24199) +* [[`1b81b348a3`](https://github.com/nodejs/node/commit/1b81b348a3)] - **doc**: describe what tls servername is for (Sam Roberts) [#24236](https://github.com/nodejs/node/pull/24236) +* [[`104b076d3d`](https://github.com/nodejs/node/commit/104b076d3d)] - **doc**: clarify allowed encoding parameter types (Sam Roberts) [#24230](https://github.com/nodejs/node/pull/24230) +* [[`7bcc4ccd8e`](https://github.com/nodejs/node/commit/7bcc4ccd8e)] - **doc**: remove legacy WPT integration guide (Joyee Cheung) [#24035](https://github.com/nodejs/node/pull/24035) +* [[`7cc3b9337f`](https://github.com/nodejs/node/commit/7cc3b9337f)] - **doc**: fix linting errors (cjihrig) [#24229](https://github.com/nodejs/node/pull/24229) +* [[`3ce71f7723`](https://github.com/nodejs/node/commit/3ce71f7723)] - **doc**: wrap GOVERNANCE.md at 80 characters (Rich Trott) [#24094](https://github.com/nodejs/node/pull/24094) +* [[`161be13602`](https://github.com/nodejs/node/commit/161be13602)] - **doc**: add text about error.code stability (Rich Trott) [#24090](https://github.com/nodejs/node/pull/24090) +* [[`2143b56b19`](https://github.com/nodejs/node/commit/2143b56b19)] - **doc**: update System Errors documentation (Rich Trott) [#24090](https://github.com/nodejs/node/pull/24090) +* [[`75ed7ce4a3`](https://github.com/nodejs/node/commit/75ed7ce4a3)] - **doc**: add psmarshall to collaborators (Peter Marshall) [#24170](https://github.com/nodejs/node/pull/24170) +* [[`f9f185a47b`](https://github.com/nodejs/node/commit/f9f185a47b)] - **doc**: add shisama to collaborators (Masashi Hirano) [#24136](https://github.com/nodejs/node/pull/24136) +* [[`d15270507e`](https://github.com/nodejs/node/commit/d15270507e)] - **doc**: implement minor text fixes to path.md (Rich Trott) [#24118](https://github.com/nodejs/node/pull/24118) +* [[`8642eacfff`](https://github.com/nodejs/node/commit/8642eacfff)] - **doc**: inspector security warning for changing host (Сковорода Никита Андреевич) [#23640](https://github.com/nodejs/node/pull/23640) +* [[`5ea48a92b2`](https://github.com/nodejs/node/commit/5ea48a92b2)] - **doc**: fix minor text issues in stream.md (Rich Trott) [#24116](https://github.com/nodejs/node/pull/24116) +* [[`6f54a7ace8`](https://github.com/nodejs/node/commit/6f54a7ace8)] - **doc**: streamline CONTRIBUTING.md (Rich Trott) [#24010](https://github.com/nodejs/node/pull/24010) +* [[`3b1044072c`](https://github.com/nodejs/node/commit/3b1044072c)] - **doc**: add table of contents to release guide (Michaël Zasso) [#24042](https://github.com/nodejs/node/pull/24042) +* [[`667ce42447`](https://github.com/nodejs/node/commit/667ce42447)] - **doc**: add missing comma in net documentation (Rich Trott) [#24074](https://github.com/nodejs/node/pull/24074) +* [[`1d6d384c02`](https://github.com/nodejs/node/commit/1d6d384c02)] - **doc**: correct link to test coverage command (mritunjaygoutam12) [#24049](https://github.com/nodejs/node/pull/24049) +* [[`94f73942ed`](https://github.com/nodejs/node/commit/94f73942ed)] - **doc**: fix socket.connecting description (Anna Henningsen) [#24066](https://github.com/nodejs/node/pull/24066) +* [[`fa84164de4`](https://github.com/nodejs/node/commit/fa84164de4)] - **doc**: add SECURITY.md to readme.md (warnerp18) [#24031](https://github.com/nodejs/node/pull/24031) +* [[`e8078f2693`](https://github.com/nodejs/node/commit/e8078f2693)] - **doc**: edit man page for superfluous "node" usage (Rich Trott) [#24029](https://github.com/nodejs/node/pull/24029) +* [[`a1b75d0cbf`](https://github.com/nodejs/node/commit/a1b75d0cbf)] - **doc**: fix dublication in net.createServer() docs (Ivan Filenko) [#24026](https://github.com/nodejs/node/pull/24026) +* [[`d729f3e198`](https://github.com/nodejs/node/commit/d729f3e198)] - **doc**: correct async\_hooks resource names (Gerhard Stoebich) [#24001](https://github.com/nodejs/node/pull/24001) +* [[`7012f72a12`](https://github.com/nodejs/node/commit/7012f72a12)] - **doc**: address bits of proof reading work (Jagannath Bhat) [#23978](https://github.com/nodejs/node/pull/23978) +* [[`399d64b331`](https://github.com/nodejs/node/commit/399d64b331)] - **doc**: revise COLLABORATOR\_GUIDE.md (Rich Trott) [#23990](https://github.com/nodejs/node/pull/23990) +* [[`879402b422`](https://github.com/nodejs/node/commit/879402b422)] - **doc**: simplify CODE\_OF\_CONDUCT.md (Rich Trott) [#23989](https://github.com/nodejs/node/pull/23989) +* [[`7b7155e90b`](https://github.com/nodejs/node/commit/7b7155e90b)] - **doc**: revise CHANGELOG.md text (Rich Trott) [#23988](https://github.com/nodejs/node/pull/23988) +* [[`b8a71bed02`](https://github.com/nodejs/node/commit/b8a71bed02)] - **doc**: improve COLLABORATOR\_GUIDE (Jagannath Bhat) [#23977](https://github.com/nodejs/node/pull/23977) +* [[`846e450f51`](https://github.com/nodejs/node/commit/846e450f51)] - **doc**: improve BUILDING.md (Jagannath Bhat) [#23976](https://github.com/nodejs/node/pull/23976) +* [[`b182e2e8b2`](https://github.com/nodejs/node/commit/b182e2e8b2)] - **doc**: add types and their corresponding return values (Ouyang Yadong) [#23998](https://github.com/nodejs/node/pull/23998) +* [[`2d84f45d22`](https://github.com/nodejs/node/commit/2d84f45d22)] - **esm**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`5ecfc7cab7`](https://github.com/nodejs/node/commit/5ecfc7cab7)] - **events**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`f49b4fc794`](https://github.com/nodejs/node/commit/f49b4fc794)] - **fs**: replace pushValueToArray with pure C++ API (Joyee Cheung) [#24125](https://github.com/nodejs/node/pull/24125) +* [[`d59dc0d6bf`](https://github.com/nodejs/node/commit/d59dc0d6bf)] - **fs**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`424be28840`](https://github.com/nodejs/node/commit/424be28840)] - **fs**: handle result of access binding directly in fs.existsSync (Joyee Cheung) [#24015](https://github.com/nodejs/node/pull/24015) +* [[`2aa23cd433`](https://github.com/nodejs/node/commit/2aa23cd433)] - **(SEMVER-MINOR)** **fs,net**: standardize `pending` stream property (Anna Henningsen) [#24067](https://github.com/nodejs/node/pull/24067) +* [[`86aa27f85d`](https://github.com/nodejs/node/commit/86aa27f85d)] - **http**: remove pushValueToArray in Parser::CreateHeaders() (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`c2599a14de`](https://github.com/nodejs/node/commit/c2599a14de)] - **http**: remove obsolete function escapeHeaderValue (Lauri Piisang) [#24173](https://github.com/nodejs/node/pull/24173) +* [[`62fefd8aeb`](https://github.com/nodejs/node/commit/62fefd8aeb)] - **http2**: remove pushValueToArray in Http2Session::HandleOriginFrame (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`7ffbb1f55f`](https://github.com/nodejs/node/commit/7ffbb1f55f)] - **http2**: remove pushValueToArray in Http2Session::HandleHeadersFrame (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`4a0f27656d`](https://github.com/nodejs/node/commit/4a0f27656d)] - **(SEMVER-MINOR)** **http2**: add Http2Stream.bufferSize (Ouyang Yadong) [#23711](https://github.com/nodejs/node/pull/23711) +* [[`c7f471ab97`](https://github.com/nodejs/node/commit/c7f471ab97)] - **http2**: improve http2 code a bit (James M Snell) [#23984](https://github.com/nodejs/node/pull/23984) +* [[`4dbcf7ac1f`](https://github.com/nodejs/node/commit/4dbcf7ac1f)] - **inspector**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`5ca0cf7ae6`](https://github.com/nodejs/node/commit/5ca0cf7ae6)] - **lib**: improved conditional check in zlib (Dan Corman) [#24190](https://github.com/nodejs/node/pull/24190) +* [[`d8d93442aa`](https://github.com/nodejs/node/commit/d8d93442aa)] - **lib**: adjust params from uvExceptionWithHostPort (msmichellegar) [#24159](https://github.com/nodejs/node/pull/24159) +* [[`6f80a45528`](https://github.com/nodejs/node/commit/6f80a45528)] - **lib**: combine contructor, tag, Object into a function (Paul Isache) [#24171](https://github.com/nodejs/node/pull/24171) +* [[`1225a0af09`](https://github.com/nodejs/node/commit/1225a0af09)] - **lib**: add crypto dependant modules cannotUseCache (Daniel Bevenius) [#24100](https://github.com/nodejs/node/pull/24100) +* [[`453c96ed2d`](https://github.com/nodejs/node/commit/453c96ed2d)] - **lib**: move process prototype manipulation into setupProcessObject (Joyee Cheung) [#24089](https://github.com/nodejs/node/pull/24089) +* [[`6a6b036042`](https://github.com/nodejs/node/commit/6a6b036042)] - **lib**: move internalBinding whitelisting into loaders.js (Joyee Cheung) [#24088](https://github.com/nodejs/node/pull/24088) +* [[`b4c8158459`](https://github.com/nodejs/node/commit/b4c8158459)] - **lib**: fix grammar error and make it clearer for comments (MaleDong) [#23799](https://github.com/nodejs/node/pull/23799) +* [[`879c0f1f3e`](https://github.com/nodejs/node/commit/879c0f1f3e)] - **lib**: move module exports proxy into a separate method (Joyee Cheung) [#24057](https://github.com/nodejs/node/pull/24057) +* [[`874393bfd0`](https://github.com/nodejs/node/commit/874393bfd0)] - **lib**: remove useless getLibuvNow in internal/timers (ZYSzys) [#23995](https://github.com/nodejs/node/pull/23995) +* [[`7ee0cea028`](https://github.com/nodejs/node/commit/7ee0cea028)] - **lib**: make coverage work for Node.js (Benjamin) [#23941](https://github.com/nodejs/node/pull/23941) +* [[`b3f3ebf3b3`](https://github.com/nodejs/node/commit/b3f3ebf3b3)] - **lib**: repl multiline history support (Anto Aravinth) [#22153](https://github.com/nodejs/node/pull/22153) +* [[`55adc25968`](https://github.com/nodejs/node/commit/55adc25968)] - **(SEMVER-MINOR)** **lib**: enable TypedArray and DataView for the v8 module (Ouyang Yadong) [#23953](https://github.com/nodejs/node/pull/23953) +* [[`5ff1e67ff7`](https://github.com/nodejs/node/commit/5ff1e67ff7)] - **lib**: fix code cache generation (Joyee Cheung) [#23855](https://github.com/nodejs/node/pull/23855) +* [[`164f2444a0`](https://github.com/nodejs/node/commit/164f2444a0)] - **lib**: remove useless cwd in posix.resolve (ZYSzys) [#23902](https://github.com/nodejs/node/pull/23902) +* [[`10156c612d`](https://github.com/nodejs/node/commit/10156c612d)] - **meta,doc**: ping community about new release (Refael Ackermann) [#24064](https://github.com/nodejs/node/pull/24064) +* [[`1dd8191515`](https://github.com/nodejs/node/commit/1dd8191515)] - **(SEMVER-MINOR)** **module**: support multi-dot file extension (Geoffrey Booth) [#23416](https://github.com/nodejs/node/pull/23416) +* [[`72204d114f`](https://github.com/nodejs/node/commit/72204d114f)] - **n-api**: add missing handle scopes (Daniel Bevenius) [#24011](https://github.com/nodejs/node/pull/24011) +* [[`10edc4f186`](https://github.com/nodejs/node/commit/10edc4f186)] - **net**: always invoke after-write callback (Anna Henningsen) [#24291](https://github.com/nodejs/node/pull/24291) +* [[`753f706858`](https://github.com/nodejs/node/commit/753f706858)] - **net**: add comments explaining error check (Steven Gabarro) [#24222](https://github.com/nodejs/node/pull/24222) +* [[`c53117e7ea`](https://github.com/nodejs/node/commit/c53117e7ea)] - **net**: remove unreachable check in internalConnect (Philipp Dunkel) [#24158](https://github.com/nodejs/node/pull/24158) +* [[`74451263a3`](https://github.com/nodejs/node/commit/74451263a3)] - **net**: partially revert "simplify Socket.prototype.\_final" (Anna Henningsen) [#24288](https://github.com/nodejs/node/pull/24288) +* [[`636e4e02a5`](https://github.com/nodejs/node/commit/636e4e02a5)] - **net**: simplify Socket.prototype.\_final (Anna Henningsen) [#24075](https://github.com/nodejs/node/pull/24075) +* [[`cd227eb791`](https://github.com/nodejs/node/commit/cd227eb791)] - **net**: `net.Server.listen()` avoid operations on `null` when fail (Ouyang Yadong) [#23920](https://github.com/nodejs/node/pull/23920) +* [[`293983a112`](https://github.com/nodejs/node/commit/293983a112)] - **os**: do not call into JS to push values to an array in GetCPUInfo (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`ccc3bb73db`](https://github.com/nodejs/node/commit/ccc3bb73db)] - **process**: remove pushValueToArray in GetActiveHandles (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`ba4337d77d`](https://github.com/nodejs/node/commit/ba4337d77d)] - **process**: remove pushValueToArray in GetActiveRequests (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`e5888462f6`](https://github.com/nodejs/node/commit/e5888462f6)] - **process**: remove pushValueToArray in EnvEnumerator (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`52468b33f7`](https://github.com/nodejs/node/commit/52468b33f7)] - **querystring**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`213b6293fc`](https://github.com/nodejs/node/commit/213b6293fc)] - **repl**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`e27f43201c`](https://github.com/nodejs/node/commit/e27f43201c)] - **repl**: use promise#finally (Weijia Wang) [#23971](https://github.com/nodejs/node/pull/23971) +* [[`b7aded3300`](https://github.com/nodejs/node/commit/b7aded3300)] - **src**: compile native modules and their code cache in C++ (Joyee Cheung) [#24221](https://github.com/nodejs/node/pull/24221) +* [[`92a8cbe87a`](https://github.com/nodejs/node/commit/92a8cbe87a)] - **src**: enable detailed source positions in V8 (Yang Guo) [#24274](https://github.com/nodejs/node/pull/24274) +* [[`f8ed673308`](https://github.com/nodejs/node/commit/f8ed673308)] - **src**: remove pushValueToArray and SetupProcessObject (Joyee Cheung) [#24264](https://github.com/nodejs/node/pull/24264) +* [[`7601cdfe8b`](https://github.com/nodejs/node/commit/7601cdfe8b)] - **src**: bundle persistent-to-local methods as class (Gabriel Schulhof) [#24276](https://github.com/nodejs/node/pull/24276) +* [[`f5945c9279`](https://github.com/nodejs/node/commit/f5945c9279)] - **src**: sort internal binding list (cjihrig) [#24292](https://github.com/nodejs/node/pull/24292) +* [[`e1c792919e`](https://github.com/nodejs/node/commit/e1c792919e)] - **src**: fix v8 compiler warnings in src (Daniel Bevenius) [#24246](https://github.com/nodejs/node/pull/24246) +* [[`81f4fb2b3b`](https://github.com/nodejs/node/commit/81f4fb2b3b)] - **src**: reuse std::make\_unique (alyssaq) [#24132](https://github.com/nodejs/node/pull/24132) +* [[`a9053c38ea`](https://github.com/nodejs/node/commit/a9053c38ea)] - **src**: cache the result of GetOptions() in JS land (Joyee Cheung) [#24091](https://github.com/nodejs/node/pull/24091) +* [[`17e80eca95`](https://github.com/nodejs/node/commit/17e80eca95)] - **src**: prefer param function check over args length (Shelley Vohr) [#23835](https://github.com/nodejs/node/pull/23835) +* [[`1cda9b3988`](https://github.com/nodejs/node/commit/1cda9b3988)] - **src**: fix Set() usage in env-inl.h (cjihrig) [#24060](https://github.com/nodejs/node/pull/24060) +* [[`bef1c3b748`](https://github.com/nodejs/node/commit/bef1c3b748)] - **src**: fix Set() usage in node.h (cjihrig) [#24060](https://github.com/nodejs/node/pull/24060) +* [[`2a93882498`](https://github.com/nodejs/node/commit/2a93882498)] - **src**: fix Get() usage in tls\_wrap.cc (cjihrig) [#24060](https://github.com/nodejs/node/pull/24060) +* [[`9437aaad26`](https://github.com/nodejs/node/commit/9437aaad26)] - **src**: fix Get() usage in async\_wrap.cc (cjihrig) [#24060](https://github.com/nodejs/node/pull/24060) +* [[`cb7d9f9980`](https://github.com/nodejs/node/commit/cb7d9f9980)] - **src**: move error handling code into node\_errors.cc (Joyee Cheung) [#24058](https://github.com/nodejs/node/pull/24058) +* [[`fdba226d13`](https://github.com/nodejs/node/commit/fdba226d13)] - **src**: fix compiler warning for debug build (Daniel Bevenius) [#23994](https://github.com/nodejs/node/pull/23994) +* [[`84e5807b1e`](https://github.com/nodejs/node/commit/84e5807b1e)] - **src**: fix CreatePlatform header param mismatch (Shelley Vohr) [#23947](https://github.com/nodejs/node/pull/23947) +* [[`38b0525bc3`](https://github.com/nodejs/node/commit/38b0525bc3)] - **src**: use v8:: for consistency in util (ZYSzys) [#23934](https://github.com/nodejs/node/pull/23934) +* [[`90872c4c6e`](https://github.com/nodejs/node/commit/90872c4c6e)] - **src**: fix fully-static & large-pages combination (Suresh Srinivas) [#23964](https://github.com/nodejs/node/pull/23964) +* [[`063b40edc1`](https://github.com/nodejs/node/commit/063b40edc1)] - **src**: use "constants" string instead of creating new one (Ouyang Yadong) [#23894](https://github.com/nodejs/node/pull/23894) +* [[`24b18645b9`](https://github.com/nodejs/node/commit/24b18645b9)] - **src,win**: informative stack traces (Refael Ackermann) [#23822](https://github.com/nodejs/node/pull/23822) +* [[`13dee430cd`](https://github.com/nodejs/node/commit/13dee430cd)] - **stream**: make `.destroy()` interact better with write queue (Anna Henningsen) [#24062](https://github.com/nodejs/node/pull/24062) +* [[`d6bcf8b98b`](https://github.com/nodejs/node/commit/d6bcf8b98b)] - **(SEMVER-MINOR)** **stream**: add auto-destroy mode (Mathias Buus) [#22795](https://github.com/nodejs/node/pull/22795) +* [[`2593b40f5c`](https://github.com/nodejs/node/commit/2593b40f5c)] - **test**: compare objects not identical by reference (Marie Terrier) [#24189](https://github.com/nodejs/node/pull/24189) +* [[`eeb5cc6305`](https://github.com/nodejs/node/commit/eeb5cc6305)] - **test**: add typeerror for vm/compileFunction params (Dan Corman) [#24179](https://github.com/nodejs/node/pull/24179) +* [[`dc26247e69`](https://github.com/nodejs/node/commit/dc26247e69)] - **test**: deep object to table not covered (Osmond van Hemert) [#24257](https://github.com/nodejs/node/pull/24257) +* [[`29a29f7f97`](https://github.com/nodejs/node/commit/29a29f7f97)] - **test**: add tests for Socket.setNoDelay (James Herrington) [#24250](https://github.com/nodejs/node/pull/24250) +* [[`aa800b097a`](https://github.com/nodejs/node/commit/aa800b097a)] - **test**: assert diff no color (Florin-Daniel BÎLBÎE) [#24181](https://github.com/nodejs/node/pull/24181) +* [[`b6d2819b93`](https://github.com/nodejs/node/commit/b6d2819b93)] - **test**: add process no deprecation (razvanbh) [#24196](https://github.com/nodejs/node/pull/24196) +* [[`dd9864b8d7`](https://github.com/nodejs/node/commit/dd9864b8d7)] - **test**: check for invalid module type in vm.js (alyssaq) [#24161](https://github.com/nodejs/node/pull/24161) +* [[`957ceaabe6`](https://github.com/nodejs/node/commit/957ceaabe6)] - **test**: fix flaky test-vm-timeout-escape-queuemicrotask (Rich Trott) [#24296](https://github.com/nodejs/node/pull/24296) +* [[`89c3388a77`](https://github.com/nodejs/node/commit/89c3388a77)] - **test**: fix arguments order in assertions (Emanuel Kluge) [#24149](https://github.com/nodejs/node/pull/24149) +* [[`ea5d1841af`](https://github.com/nodejs/node/commit/ea5d1841af)] - **test**: remove unused parameters in function definition (Paul Hodgson) [#24268](https://github.com/nodejs/node/pull/24268) +* [[`cb4c2dd33e`](https://github.com/nodejs/node/commit/cb4c2dd33e)] - **test**: esm loader unknown builtin module (Fran Herrero) [#24183](https://github.com/nodejs/node/pull/24183) +* [[`1a86499947`](https://github.com/nodejs/node/commit/1a86499947)] - **test**: fixed order of actual and expected arguments (kiyomizumia) [#24178](https://github.com/nodejs/node/pull/24178) +* [[`77163a9dee`](https://github.com/nodejs/node/commit/77163a9dee)] - **test**: add else and error case for TextDecoder (Lauri Piisang) [#24162](https://github.com/nodejs/node/pull/24162) +* [[`e5e9c6427b`](https://github.com/nodejs/node/commit/e5e9c6427b)] - **test**: dgram socket prints deprecation warnings (Robert Pamely) [#24177](https://github.com/nodejs/node/pull/24177) +* [[`366529654e`](https://github.com/nodejs/node/commit/366529654e)] - **test**: url format path ending hashchar not covered (Osmond van Hemert) [#24259](https://github.com/nodejs/node/pull/24259) +* [[`0a104ef33c`](https://github.com/nodejs/node/commit/0a104ef33c)] - **test**: test add and remove for lib/domain (Petar Dodev) [#24163](https://github.com/nodejs/node/pull/24163) +* [[`fe7ef1ad11`](https://github.com/nodejs/node/commit/fe7ef1ad11)] - **test**: add test for autoDestroy in stream (Daijiro Wachi) [#24127](https://github.com/nodejs/node/pull/24127) +* [[`02e9fa01f3`](https://github.com/nodejs/node/commit/02e9fa01f3)] - **test**: fix args order in process-getactiverequests (Vladyslav Kopylash) [#24186](https://github.com/nodejs/node/pull/24186) +* [[`f805db3620`](https://github.com/nodejs/node/commit/f805db3620)] - **test**: check control characters replacing (Alessandro Gatti) [#24182](https://github.com/nodejs/node/pull/24182) +* [[`75e4f7db40`](https://github.com/nodejs/node/commit/75e4f7db40)] - **test**: fix strictEqual argument order (Martin Kask) [#24153](https://github.com/nodejs/node/pull/24153) +* [[`09a8f4713d`](https://github.com/nodejs/node/commit/09a8f4713d)] - **test**: correct order of args in assert.strictEqual() (Natalie Cluer) [#24157](https://github.com/nodejs/node/pull/24157) +* [[`c83b650a10`](https://github.com/nodejs/node/commit/c83b650a10)] - **test**: add tests for process.initgroups (James Herrington) [#24154](https://github.com/nodejs/node/pull/24154) +* [[`762bb94d72`](https://github.com/nodejs/node/commit/762bb94d72)] - **test**: add test case for completion bash flag (Aivo Paas) [#24168](https://github.com/nodejs/node/pull/24168) +* [[`afcfdec289`](https://github.com/nodejs/node/commit/afcfdec289)] - **test**: add test for deepEqual Float32Array (Yehiyam Livneh) [#24164](https://github.com/nodejs/node/pull/24164) +* [[`b02eed5e3b`](https://github.com/nodejs/node/commit/b02eed5e3b)] - **test**: fix arguments order in assert.strictEqual() (Ulises Santana Suárez) [#24192](https://github.com/nodejs/node/pull/24192) +* [[`768425f21a`](https://github.com/nodejs/node/commit/768425f21a)] - **test**: fix assert.strictEqual argument order (John Mc Quillan) [#24172](https://github.com/nodejs/node/pull/24172) +* [[`26c625c3d2`](https://github.com/nodejs/node/commit/26c625c3d2)] - **test**: fix v8 Set/Get compiler warnings (Daniel Bevenius) [#24246](https://github.com/nodejs/node/pull/24246) +* [[`beb0800ab3`](https://github.com/nodejs/node/commit/beb0800ab3)] - **test**: move benchmark tests out of main test suite (Rich Trott) [#24265](https://github.com/nodejs/node/pull/24265) +* [[`883519679e`](https://github.com/nodejs/node/commit/883519679e)] - **test**: replacing fixture directory with temp (saurabhSiddhu) [#24077](https://github.com/nodejs/node/pull/24077) +* [[`ddbd0e1973`](https://github.com/nodejs/node/commit/ddbd0e1973)] - **test**: increase coverage internal readline (Berry de Witte) [#24150](https://github.com/nodejs/node/pull/24150) +* [[`56cd911cad`](https://github.com/nodejs/node/commit/56cd911cad)] - **test**: use NULL instead of 0 in common.h (Daniel Bevenius) [#24104](https://github.com/nodejs/node/pull/24104) +* [[`a05f2fc46b`](https://github.com/nodejs/node/commit/a05f2fc46b)] - **test**: move test-fs-watch-system-limit from sequential to pummel (Marcus Scott) [#23692](https://github.com/nodejs/node/pull/23692) +* [[`9af7ad592c`](https://github.com/nodejs/node/commit/9af7ad592c)] - **test**: fix uses of deprecated assert.fail with multiple args (ivan.filenko) [#23673](https://github.com/nodejs/node/pull/23673) +* [[`2b0410a3ef`](https://github.com/nodejs/node/commit/2b0410a3ef)] - **test**: use assert.strictEqual instead of assert.equal (ivan.filenko) [#23673](https://github.com/nodejs/node/pull/23673) +* [[`825f0dda5b`](https://github.com/nodejs/node/commit/825f0dda5b)] - **test**: add test for strictDeepEqual (Nikita Malyschkin) [#24197](https://github.com/nodejs/node/pull/24197) +* [[`b16e485910`](https://github.com/nodejs/node/commit/b16e485910)] - **test**: add coverage for systemerror set name (Amer Alimanović) [#24200](https://github.com/nodejs/node/pull/24200) +* [[`bc97b62f35`](https://github.com/nodejs/node/commit/bc97b62f35)] - **test**: fix order of arguments in assert.strictEqual (Alex Seifert) [#24145](https://github.com/nodejs/node/pull/24145) +* [[`4a69d218b6`](https://github.com/nodejs/node/commit/4a69d218b6)] - **test**: add test for 'ERR\_INVALID\_CALLBACK' (razvanbh) [#24224](https://github.com/nodejs/node/pull/24224) +* [[`8b0626c836`](https://github.com/nodejs/node/commit/8b0626c836)] - **test**: add coverage for escape key switch case (Artur Daschevici) [#24194](https://github.com/nodejs/node/pull/24194) +* [[`92d2d7917f`](https://github.com/nodejs/node/commit/92d2d7917f)] - **test**: fix NewFromUtf8 compiler warning (Daniel Bevenius) [#24216](https://github.com/nodejs/node/pull/24216) +* [[`0c4facfbaf`](https://github.com/nodejs/node/commit/0c4facfbaf)] - **test**: change arguments order in strictEqual (Paul Isache) [#24156](https://github.com/nodejs/node/pull/24156) +* [[`2baa59b897`](https://github.com/nodejs/node/commit/2baa59b897)] - **test**: switch order of strictEqual arguments (Jonah Polack) [#24185](https://github.com/nodejs/node/pull/24185) +* [[`c8d8e5cf2c`](https://github.com/nodejs/node/commit/c8d8e5cf2c)] - **test**: fix the arguments order in `assert.strictEqual` (mzucker) [#24227](https://github.com/nodejs/node/pull/24227) +* [[`4245cbbf49`](https://github.com/nodejs/node/commit/4245cbbf49)] - **test**: fix the arguments order in `assert.strictEqual` (mzucker) [#24226](https://github.com/nodejs/node/pull/24226) +* [[`be40fd1e50`](https://github.com/nodejs/node/commit/be40fd1e50)] - **test**: fix order in assert.strictEqual to actual, expected (Kevin Seidel) [#24184](https://github.com/nodejs/node/pull/24184) +* [[`a1f5179e09`](https://github.com/nodejs/node/commit/a1f5179e09)] - **test**: fix arguments order in assert.strictEqual (szabolcsit) [#24143](https://github.com/nodejs/node/pull/24143) +* [[`5510bec3cc`](https://github.com/nodejs/node/commit/5510bec3cc)] - **test**: fix assert argument order (Manish Poddar) [#24160](https://github.com/nodejs/node/pull/24160) +* [[`e46b8edb58`](https://github.com/nodejs/node/commit/e46b8edb58)] - **test**: add error code tests in dgram test (Mark Arranz) [#24215](https://github.com/nodejs/node/pull/24215) +* [[`6076ccf90d`](https://github.com/nodejs/node/commit/6076ccf90d)] - **test**: fix order of arguments in test-delayed-require assertion (reineke-fox) [#24165](https://github.com/nodejs/node/pull/24165) +* [[`989c2aaf83`](https://github.com/nodejs/node/commit/989c2aaf83)] - **test**: fix flaky test-vm-timeout-escape-nexttick (Rich Trott) [#24251](https://github.com/nodejs/node/pull/24251) +* [[`b68734b66a`](https://github.com/nodejs/node/commit/b68734b66a)] - **test**: initialize test/wpt to run URL and console .js tests (Joyee Cheung) [#24035](https://github.com/nodejs/node/pull/24035) +* [[`c973551eca`](https://github.com/nodejs/node/commit/c973551eca)] - **test**: use URL fixtures under test/fixtures/wpt/url/resources (Joyee Cheung) [#24035](https://github.com/nodejs/node/pull/24035) +* [[`3f935d74e0`](https://github.com/nodejs/node/commit/3f935d74e0)] - **test**: remove WPT tests that are now .any.js in the upstream (Joyee Cheung) [#24035](https://github.com/nodejs/node/pull/24035) +* [[`121a3f8855`](https://github.com/nodejs/node/commit/121a3f8855)] - **test**: use git node wpt to pull WPT into test/fixtures (Joyee Cheung) [#24035](https://github.com/nodejs/node/pull/24035) +* [[`317901174c`](https://github.com/nodejs/node/commit/317901174c)] - **test**: fix arguments order in test-fs-write-buffer (razvanbh) [#24155](https://github.com/nodejs/node/pull/24155) +* [[`9b3c2e5054`](https://github.com/nodejs/node/commit/9b3c2e5054)] - **test**: fix argument order in assert.strictEqual() (Clement) [#24147](https://github.com/nodejs/node/pull/24147) +* [[`2d87ce3d8b`](https://github.com/nodejs/node/commit/2d87ce3d8b)] - **test**: switch arguments in strictEqual (Mathieu Pavageau) [#24141](https://github.com/nodejs/node/pull/24141) +* [[`6c8b128fcc`](https://github.com/nodejs/node/commit/6c8b128fcc)] - **test**: fix arguments order (Simona Cotin) [#24151](https://github.com/nodejs/node/pull/24151) +* [[`3d19a04b51`](https://github.com/nodejs/node/commit/3d19a04b51)] - **test**: fixe argument order in assert.strictEqual (Marc Posth) [#24140](https://github.com/nodejs/node/pull/24140) +* [[`a0681b7211`](https://github.com/nodejs/node/commit/a0681b7211)] - **test**: removed extraneous argument 's' (Jackson Chui) [#24213](https://github.com/nodejs/node/pull/24213) +* [[`12429812bc`](https://github.com/nodejs/node/commit/12429812bc)] - **test**: fixing arguments order in `assert.strictEqual()` (G. Carcaci) [#24152](https://github.com/nodejs/node/pull/24152) +* [[`fc494cdb16`](https://github.com/nodejs/node/commit/fc494cdb16)] - **test**: add tests for OutgoingMessage setTimeout (Robin Drexler) [#24148](https://github.com/nodejs/node/pull/24148) +* [[`ce124aca65`](https://github.com/nodejs/node/commit/ce124aca65)] - **test**: swap expected and actual in assert.strictEqual (Florin-Daniel BÎLBÎE) [#24146](https://github.com/nodejs/node/pull/24146) +* [[`737f897b51`](https://github.com/nodejs/node/commit/737f897b51)] - **test**: fix assert parameter order (Roland Broekema) [#24144](https://github.com/nodejs/node/pull/24144) +* [[`d85161cbfd`](https://github.com/nodejs/node/commit/d85161cbfd)] - **test**: change order of assert.strictEqual() (Remy Parzinski) [#24142](https://github.com/nodejs/node/pull/24142) +* [[`fb58ada9dd`](https://github.com/nodejs/node/commit/fb58ada9dd)] - **test**: fix invalid argument order in test-http-expect-continue.js (Morgan Roderick) [#24138](https://github.com/nodejs/node/pull/24138) +* [[`7cc0a46e85`](https://github.com/nodejs/node/commit/7cc0a46e85)] - **test**: strictEqual argument order (actual, expected) (Ahmad Nassri) [#24137](https://github.com/nodejs/node/pull/24137) +* [[`a5ac7b94ea`](https://github.com/nodejs/node/commit/a5ac7b94ea)] - **test**: fixed the arguments order in `assert.strictEqual` (mzucker) [#24135](https://github.com/nodejs/node/pull/24135) +* [[`71545e6284`](https://github.com/nodejs/node/commit/71545e6284)] - **test**: swap the order of arguments (Musa Hamwala) [#24134](https://github.com/nodejs/node/pull/24134) +* [[`a8908f16f7`](https://github.com/nodejs/node/commit/a8908f16f7)] - **test**: fs readfile, swap arguments in strictEqual (Petar Dodev) [#24133](https://github.com/nodejs/node/pull/24133) +* [[`7c04fe07a6`](https://github.com/nodejs/node/commit/7c04fe07a6)] - **test**: fix arguments order (Fran Herrero) [#24131](https://github.com/nodejs/node/pull/24131) +* [[`6f80a5eeda`](https://github.com/nodejs/node/commit/6f80a5eeda)] - **test**: http-client-timeout error assert arguments (Tadhg Creedon) [#24130](https://github.com/nodejs/node/pull/24130) +* [[`415fcded15`](https://github.com/nodejs/node/commit/415fcded15)] - **test**: fix flaky VM timeout test on Raspberry Pi (Rich Trott) [#24238](https://github.com/nodejs/node/pull/24238) +* [[`a2e2c91cfa`](https://github.com/nodejs/node/commit/a2e2c91cfa)] - **test**: disable color formating for test-internal-errors.js (Refael Ackermann) [#24204](https://github.com/nodejs/node/pull/24204) +* [[`a35bcd5ef5`](https://github.com/nodejs/node/commit/a35bcd5ef5)] - **test**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`9bf36bc6c3`](https://github.com/nodejs/node/commit/9bf36bc6c3)] - **test**: add a test for `tls.Socket` with `allowHalfOpen` (Ouyang Yadong) [#23866](https://github.com/nodejs/node/pull/23866) +* [[`8a3836ec72`](https://github.com/nodejs/node/commit/8a3836ec72)] - **test**: add crypto check to test-benchmark-http2 (Daniel Bevenius) [#24096](https://github.com/nodejs/node/pull/24096) +* [[`b86a89b9ad`](https://github.com/nodejs/node/commit/b86a89b9ad)] - **test**: increase --stack\_size test-async-wrap-pop (Daniel Bevenius) [#23996](https://github.com/nodejs/node/pull/23996) +* [[`1b97dbd6b5`](https://github.com/nodejs/node/commit/1b97dbd6b5)] - **test**: assert that invalidcmd throws error code (Jerome Covington) [#23942](https://github.com/nodejs/node/pull/23942) +* [[`63778b7ae1`](https://github.com/nodejs/node/commit/63778b7ae1)] - **test**: fix strictEqual arguments order (Esteban Sotillo) [#23956](https://github.com/nodejs/node/pull/23956) +* [[`dccf4a6c38`](https://github.com/nodejs/node/commit/dccf4a6c38)] - **test**: add property for RangeError in test-buffer-copy (mritunjaygoutam12) [#23968](https://github.com/nodejs/node/pull/23968) +* [[`8bffd90933`](https://github.com/nodejs/node/commit/8bffd90933)] - **test**: fix test-fs-watch-system-limit (Ali Ijaz Sheikh) [#23986](https://github.com/nodejs/node/pull/23986) +* [[`7a2134c414`](https://github.com/nodejs/node/commit/7a2134c414)] - **test**: run code cache test by default and test generator (Joyee Cheung) [#23855](https://github.com/nodejs/node/pull/23855) +* [[`5b9ef11e35`](https://github.com/nodejs/node/commit/5b9ef11e35)] - **timers**: fix priority queue removeAt (Anatoli Papirovski) [#24322](https://github.com/nodejs/node/pull/24322) +* [[`d6f91ba139`](https://github.com/nodejs/node/commit/d6f91ba139)] - **(SEMVER-MINOR)** **tls**: get the local certificate after tls handshake (Sam Roberts) [#24261](https://github.com/nodejs/node/pull/24261) +* [[`ad72e40e5b`](https://github.com/nodejs/node/commit/ad72e40e5b)] - **tools**: update ESLint to 5.9.0 (cjihrig) [#24280](https://github.com/nodejs/node/pull/24280) +* [[`6fdc5d9c9a`](https://github.com/nodejs/node/commit/6fdc5d9c9a)] - **tools**: enable 80-char line length markdown linting (Rich Trott) [#24094](https://github.com/nodejs/node/pull/24094) +* [[`b3c163f11b`](https://github.com/nodejs/node/commit/b3c163f11b)] - **tools**: lint for unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`1541c7f401`](https://github.com/nodejs/node/commit/1541c7f401)] - **tools**: add script to lint first PR commit message (Richard Lau) [#24030](https://github.com/nodejs/node/pull/24030) +* [[`4d7fbc3e0f`](https://github.com/nodejs/node/commit/4d7fbc3e0f)] - **tools**: update alternative docs versions (Richard Lau) [#23980](https://github.com/nodejs/node/pull/23980) +* [[`8de1030a70`](https://github.com/nodejs/node/commit/8de1030a70)] - **tracing**: fix static destruction order issue (Anna Henningsen) [#24123](https://github.com/nodejs/node/pull/24123) +* [[`0063448b04`](https://github.com/nodejs/node/commit/0063448b04)] - **url**: make the context non-enumerable (Joyee Cheung) [#24218](https://github.com/nodejs/node/pull/24218) +* [[`953697a7b8`](https://github.com/nodejs/node/commit/953697a7b8)] - **util**: deleted unreachable code from util.inspect (kiyomizumia) [#24187](https://github.com/nodejs/node/pull/24187) +* [[`fb7c1b3e81`](https://github.com/nodejs/node/commit/fb7c1b3e81)] - **v8_prof_polyfill**: remove unused catch bindings (cjihrig) [#24079](https://github.com/nodejs/node/pull/24079) +* [[`9c15124aa8`](https://github.com/nodejs/node/commit/9c15124aa8)] - **vm**: clarify timeout option in vm (Vladimir de Turckheim) [#23512](https://github.com/nodejs/node/pull/23512) +* [[`2331181410`](https://github.com/nodejs/node/commit/2331181410)] - **vm**: allow `cachedData` to also be TypedArray|DataView (Benjamin Chen) [#22921](https://github.com/nodejs/node/pull/22921) +* [[`4709fe676d`](https://github.com/nodejs/node/commit/4709fe676d)] - **win**: add customization warning to tools script (João Reis) [#24348](https://github.com/nodejs/node/pull/24348) +* [[`57a2b957de`](https://github.com/nodejs/node/commit/57a2b957de)] - **win**: add prompt to tools installation script (João Reis) [#23987](https://github.com/nodejs/node/pull/23987) +* [[`df1ca0fd82`](https://github.com/nodejs/node/commit/df1ca0fd82)] - **win**: clarify Boxstarter behavior on install tools (Rob Reynolds) [#23987](https://github.com/nodejs/node/pull/23987) + ## 2018-11-02, Version 11.1.0 (Current), @targos @@ -338,8 +612,6 @@ * [[`6c7d8b4e12`](https://github.com/nodejs/node/commit/6c7d8b4e12)] - **build**: spawn `make test-ci` with `-j1` (Refael Ackermann) [#23733](https://github.com/nodejs/node/pull/23733) * [[`d548e63123`](https://github.com/nodejs/node/commit/d548e63123)] - **build**: fix `./configure --enable-d8` (Ben Noordhuis) [#23656](https://github.com/nodejs/node/pull/23656) * [[`c9fd435d28`](https://github.com/nodejs/node/commit/c9fd435d28)] - **build**: add .DS\_store to .gitgnore (Marcos Frony) [#23554](https://github.com/nodejs/node/pull/23554) -* [[`9d9f691d26`](https://github.com/nodejs/node/commit/9d9f691d26)] - ***Revert*** "**build**: extract common code from NODE\_EXE/\_G\_EXE" (Daniel Bevenius) [#22458](https://github.com/nodejs/node/pull/22458) -* [[`4e2fa8b0dc`](https://github.com/nodejs/node/commit/4e2fa8b0dc)] - **build**: extract common code from NODE\_EXE/\_G\_EXE (Daniel Bevenius) [#22310](https://github.com/nodejs/node/pull/22310) * [[`a6124892ff`](https://github.com/nodejs/node/commit/a6124892ff)] - **console**: add trace-events for time and count (James M Snell) [#23703](https://github.com/nodejs/node/pull/23703) * [[`a144d64e68`](https://github.com/nodejs/node/commit/a144d64e68)] - **crypto**: migrate to getOptions() (nick-ng) [#23562](https://github.com/nodejs/node/pull/23562) * [[`f4d1d9cb31`](https://github.com/nodejs/node/commit/f4d1d9cb31)] - **crypto**: remove DiffieHellman.initialised\_ (Tobias Nießen) [#23717](https://github.com/nodejs/node/pull/23717) diff --git a/doc/guides/contributing/pull-requests.md b/doc/guides/contributing/pull-requests.md index 15c31cec714614..ea28001b6957d3 100644 --- a/doc/guides/contributing/pull-requests.md +++ b/doc/guides/contributing/pull-requests.md @@ -29,7 +29,7 @@ so that you can make the actual changes. This is where we will start. * [Accept that there are different opinions about what belongs in Node.js](#accept-that-there-are-different-opinions-about-what-belongs-in-nodejs) * [Performance is not everything](#performance-is-not-everything) * [Continuous Integration Testing](#continuous-integration-testing) -* [Additional Notes](#additional-notes) +* [Notes](#notes) * [Commit Squashing](#commit-squashing) * [Getting Approvals for your Pull Request](#getting-approvals-for-your-pull-request) * [CI Testing](#ci-testing) @@ -194,7 +194,7 @@ One of the existing contributors will help get things situated and the contributor landing the Pull Request will ensure that everything follows the project guidelines. -See [core-validate-commit](https://github.com/evanlucas/core-validate-commit) - +See [core-validate-commit](https://github.com/nodejs/core-validate-commit) - A utility that ensures commits follow the commit formatting guidelines. ### Step 5: Rebase @@ -531,7 +531,7 @@ specific platforms or for so-called "flaky" tests to fail ("be red"). It is vital to visually inspect the results of all failed ("red") tests to determine whether the failure was caused by the changes in the Pull Request. -## Additional Notes +## Notes ### Commit Squashing @@ -596,4 +596,4 @@ If you want to know more about the code review and the landing process, see the [https://ci.nodejs.org/]: https://ci.nodejs.org/ [IRC in the #node-dev channel]: https://webchat.freenode.net?channels=node-dev&uio=d4 [Onboarding guide]: ../../onboarding.md -[running tests]: ../../../BUILDING.md#running-tests \ No newline at end of file +[running tests]: ../../../BUILDING.md#running-tests diff --git a/doc/guides/writing-tests.md b/doc/guides/writing-tests.md index 2059a709ff8a95..260dfa236fa615 100644 --- a/doc/guides/writing-tests.md +++ b/doc/guides/writing-tests.md @@ -310,27 +310,7 @@ functions worked correctly with the `beforeExit` event, then it might be named ### Web Platform Tests -Some of the tests for the WHATWG URL implementation (named -`test-whatwg-url-*.js`) are imported from the [Web Platform Tests Project][]. -These imported tests will be wrapped like this: - -```js -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-stringifier.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ - -// Test code - -/* eslint-enable */ -``` - -To improve tests that have been imported this way, please send -a PR to the upstream project first. When the proposed change is merged in -the upstream project, send another PR here to update Node.js accordingly. -Be sure to update the hash in the URL following `WPT Refs:`. +See [`test/wpt`](../../test/wpt/README.md) for more information. ## C++ Unit test @@ -414,14 +394,13 @@ will depend on what is being tested if this is required or not. ### Test Coverage To generate a test coverage report, see the -[Test Coverage section of the Pull Requests guide][]. +[Test Coverage section of the Building guide][]. [ASCII]: http://man7.org/linux/man-pages/man7/ascii.7.html [Google Test]: https://github.com/google/googletest -[Web Platform Tests Project]: https://github.com/w3c/web-platform-tests/tree/master/url [`common` module]: https://github.com/nodejs/node/blob/master/test/common/README.md [all maintained branches]: https://github.com/nodejs/lts [node.green]: http://node.green/ [test fixture]: https://github.com/google/googletest/blob/master/googletest/docs/Primer.md#test-fixtures-using-the-same-data-configuration-for-multiple-tests -[Test Coverage section of the Pull Requests guide]: https://github.com/nodejs/node/blob/master/doc/guides/contributing/pull-requests.md#test-coverage +[Test Coverage section of the Building guide]: https://github.com/nodejs/node/blob/master/BUILDING.md#running-coverage [directory structure overview]: https://github.com/nodejs/node/blob/master/test/README.md#test-directories diff --git a/doc/node.1 b/doc/node.1 index 397b40ed71e3f4..b8144f4ebb5f6c 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -66,7 +66,7 @@ Alias for stdin, analogous to the use of - in other command-line utilities. The executed script is read from stdin, and remaining arguments are passed to the script. . .It Fl - -Indicate the end of node options. +Indicate the end of command-line options. Pass the rest of the arguments to the script. .Pp If no script filename or eval/print script is supplied prior to this, then @@ -246,7 +246,7 @@ Evaluate as JavaScript. . .It Fl h , Fl -help -Print Node.js command line options. +Print command-line options. The output of this option is less detailed than this document. . .It Fl i , Fl -interactive diff --git a/doc/onboarding.md b/doc/onboarding.md index b08aabfff7d74e..133680a8cfb93a 100644 --- a/doc/onboarding.md +++ b/doc/onboarding.md @@ -245,7 +245,7 @@ needs to be pointed out separately during the onboarding. the [summit](https://github.com/nodejs/summit) repository for details. [Code of Conduct]: https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md -[`core-validate-commit`]: https://github.com/evanlucas/core-validate-commit +[`core-validate-commit`]: https://github.com/nodejs/core-validate-commit [`git-node`]: https://github.com/nodejs/node-core-utils/blob/master/docs/git-node.md [`node-core-utils`]: https://github.com/nodejs/node-core-utils [Landing Pull Requests]: https://github.com/nodejs/node/blob/master/COLLABORATOR_GUIDE.md#landing-pull-requests diff --git a/doc/releases.md b/doc/releases.md index 5781a9d5fd490f..ab871c0b2067ff 100644 --- a/doc/releases.md +++ b/doc/releases.md @@ -5,6 +5,34 @@ The intended audience is those who have been authorized by the Node.js Foundation Technical Steering Committee (TSC) to create, promote, and sign official release builds for Node.js, hosted on . +## Table of Contents + +* [Who can make a release?](#who-can-make-a-release) + * [1. Jenkins Release Access](#1-jenkins-release-access) + * [2. Access](#2-nodejsorg-access) + * [3. A Publicly Listed GPG Key](#3-a-publicly-listed-gpg-key) +* [How to create a release](#how-to-create-a-release) + * [0. Pre-release steps](#0-pre-release-steps) + * [1. Update the staging branch](#1-update-the-staging-branch) + * [2. Create a new branch for the release](#2-create-a-new-branch-for-the-release) + * [3. Update `src/node_version.h`](#3-update-srcnode_versionh) + * [4. Update the Changelog](#4-update-the-changelog) + * [5. Create Release Commit](#5-create-release-commit) + * [6. Propose Release on GitHub](#6-propose-release-on-github) + * [7. Ensure that the Release Branch is Stable](#7-ensure-that-the-release-branch-is-stable) + * [8. Produce a Nightly Build _(optional)_](#8-produce-a-nightly-build-optional) + * [9. Produce Release Builds](#9-produce-release-builds) + * [10. Test the Build](#10-test-the-build) + * [11. Tag and Sign the Release Commit](#11-tag-and-sign-the-release-commit) + * [12. Set Up For the Next Release](#12-set-up-for-the-next-release) + * [13. Promote and Sign the Release Builds](#13-promote-and-sign-the-release-builds) + * [14. Check the Release](#14-check-the-release) + * [15. Create a Blog Post](#15-create-a-blog-post) + * [16. Create the release on GitHub](#16-create-the-release-on-github) + * [17. Cleanup](#17-cleanup) + * [18. Announce](#18-announce) + * [19. Celebrate](#19-celebrate) + ## Who can make a release? Release authorization is given by the Node.js TSC. Once authorized, an @@ -553,7 +581,19 @@ This script will use the promoted builds and changelog to generate the post. Run - Changes to `master` on the nodejs.org repo will trigger a new build of nodejs.org so your changes should appear in a few minutes after pushing. -### 16. Announce +### 16. Create the release on GitHub + +- Go to the [New release page](https://github.com/nodejs/node/releases/new). +- Select the tag version you pushed earlier. +- For release title, copy the title from the changelog. +- For the description, copy the rest of the changelog entry. +- Click on the "Publish release" button. + +### 17. Cleanup + +Close your release proposal PR and delete the proposal branch. + +### 18. Announce The nodejs.org website will automatically rebuild and include the new version. To announce the build on Twitter through the official @nodejs account, email @@ -568,17 +608,7 @@ To ensure communication goes out with the timing of the blog post, please allow will be shared with the community in the email to coordinate these announcements. -### 17. Create the release on GitHub - -- Got to the [New release page](https://github.com/nodejs/node/releases/new). -- Select the tag version you pushed earlier. -- For release title, copy the title from the changelog. -- For the description, copy the rest of the changelog entry. -- Click on the "Publish release" button. - -### 18. Cleanup - -Close your release proposal PR and delete the proposal branch. +Ping the IRC ops and the other [Partner Communities] liaisons. ### 19. Celebrate @@ -587,4 +617,5 @@ _In whatever form you do this..._ [CI lockdown procedure]: https://github.com/nodejs/build/blob/master/doc/jenkins-guide.md#restricting-access-for-security-releases [Build issue tracker]: https://github.com/nodejs/build/issues/new [nodejs.org release-post.js script]: https://github.com/nodejs/nodejs.org/blob/master/scripts/release-post.js +[Partner Communities]: https://github.com/nodejs/community-committee/blob/master/PARTNER_COMMUNITIES.md [webchat.freenode.net]: https://webchat.freenode.net/ diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 67d0090d7dabf7..04a36d2be2fde3 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -409,7 +409,7 @@ function processHeader(self, state, key, value, validate) { function storeHeader(self, state, key, value, validate) { if (validate) validateHeaderValue(key, value); - state.header += key + ': ' + escapeHeaderValue(value) + CRLF; + state.header += key + ': ' + value + CRLF; matchHeader(self, state, key, value); } @@ -642,13 +642,6 @@ function connectionCorkNT(msg, conn) { } -function escapeHeaderValue(value) { - // Protect against response splitting. The regex test is there to - // minimize the performance impact in the common case. - return /[\r\n]/.test(value) ? value.replace(/[\r\n]+[ \t]*/g, '') : value; -} - - OutgoingMessage.prototype.addTrailers = function addTrailers(headers) { this._trailer = ''; var keys = Object.keys(headers); @@ -670,7 +663,7 @@ OutgoingMessage.prototype.addTrailers = function addTrailers(headers) { debug('Trailer "%s" contains invalid characters', field); throw new ERR_INVALID_CHAR('trailer content', field); } - this._trailer += field + ': ' + escapeHeaderValue(value) + CRLF; + this._trailer += field + ': ' + value + CRLF; } }; diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 488d10a10b5bbd..2a2122e0e553cd 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -46,6 +46,7 @@ let createReadableStreamAsyncIterator; util.inherits(Readable, Stream); +const { errorOrDestroy } = destroyImpl; const kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; function prependListener(emitter, event, fn) { @@ -117,6 +118,9 @@ function ReadableState(options, stream, isDuplex) { // Should close be emitted on destroy. Defaults to true. this.emitClose = options.emitClose !== false; + // Should .destroy() be called after 'end' (and potentially 'finish') + this.autoDestroy = !!options.autoDestroy; + // has it been destroyed this.destroyed = false; @@ -235,7 +239,7 @@ function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { if (!skipChunkCheck) er = chunkInvalid(state, chunk); if (er) { - stream.emit('error', er); + errorOrDestroy(stream, er); } else if (state.objectMode || chunk && chunk.length > 0) { if (typeof chunk !== 'string' && !state.objectMode && @@ -245,11 +249,11 @@ function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { if (addToFront) { if (state.endEmitted) - stream.emit('error', new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); + errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); else addChunk(stream, state, chunk, true); } else if (state.ended) { - stream.emit('error', new ERR_STREAM_PUSH_AFTER_EOF()); + errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); } else if (state.destroyed) { return false; } else { @@ -581,7 +585,7 @@ function maybeReadMore_(stream, state) { // for virtual (non-string, non-buffer) streams, "length" is somewhat // arbitrary, and perhaps not very meaningful. Readable.prototype._read = function(n) { - this.emit('error', new ERR_METHOD_NOT_IMPLEMENTED('_read()')); + errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()')); }; Readable.prototype.pipe = function(dest, pipeOpts) { @@ -687,7 +691,7 @@ Readable.prototype.pipe = function(dest, pipeOpts) { unpipe(); dest.removeListener('error', onerror); if (EE.listenerCount(dest, 'error') === 0) - dest.emit('error', er); + errorOrDestroy(dest, er); } // Make sure our error handler is attached before userland ones. @@ -1092,5 +1096,14 @@ function endReadableNT(state, stream) { state.endEmitted = true; stream.readable = false; stream.emit('end'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the writable side is ready for autoDestroy as well + const wState = stream._writableState; + if (!wState || (wState.autoDestroy && wState.finished)) { + stream.destroy(); + } + } } } diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 3bad957912b323..d62c95ad800567 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -45,6 +45,8 @@ const { ERR_UNKNOWN_ENCODING } = require('internal/errors').codes; +const { errorOrDestroy } = destroyImpl; + util.inherits(Writable, Stream); function nop() {} @@ -147,6 +149,9 @@ function WritableState(options, stream, isDuplex) { // Should close be emitted on destroy. Defaults to true. this.emitClose = options.emitClose !== false; + // Should .destroy() be called after 'finish' (and potentially 'end') + this.autoDestroy = !!options.autoDestroy; + // count buffered requests this.bufferedRequestCount = 0; @@ -235,14 +240,14 @@ function Writable(options) { // Otherwise people can pipe Writable streams, which is just wrong. Writable.prototype.pipe = function() { - this.emit('error', new ERR_STREAM_CANNOT_PIPE()); + errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); }; function writeAfterEnd(stream, cb) { var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); + errorOrDestroy(stream, er); process.nextTick(cb, er); } @@ -258,7 +263,7 @@ function validChunk(stream, state, chunk, cb) { er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk); } if (er) { - stream.emit('error', er); + errorOrDestroy(stream, er); process.nextTick(cb, er); return false; } @@ -422,13 +427,13 @@ function onwriteError(stream, state, sync, er, cb) { // after error process.nextTick(finishMaybe, stream, state); stream._writableState.errorEmitted = true; - stream.emit('error', er); + errorOrDestroy(stream, er); } else { // the caller expect this to happen before if // it is async cb(er); stream._writableState.errorEmitted = true; - stream.emit('error', er); + errorOrDestroy(stream, er); // this can emit finish, but finish must // always follow error finishMaybe(stream, state); @@ -456,7 +461,7 @@ function onwrite(stream, er) { onwriteError(stream, state, sync, er, cb); else { // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(state); + var finished = needFinish(state) || stream.destroyed; if (!finished && !state.corked && @@ -612,7 +617,7 @@ function callFinal(stream, state) { stream._final((err) => { state.pendingcb--; if (err) { - stream.emit('error', err); + errorOrDestroy(stream, err); } state.prefinished = true; stream.emit('prefinish'); @@ -639,6 +644,15 @@ function finishMaybe(stream, state) { if (state.pendingcb === 0) { state.finished = true; stream.emit('finish'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the readable side is ready for autoDestroy as well + const rState = stream._readableState; + if (!rState || (rState.autoDestroy && rState.endEmitted)) { + stream.destroy(); + } + } } } return need; diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 2a880450677258..843c582b1f3bae 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -213,6 +213,9 @@ exports.createSecureContext = function createSecureContext(options, context) { return c; }; +// Translate some fields from the handle's C-friendly format into more idiomatic +// javascript object representations before passing them back to the user. Can +// be used on any cert object, but changing the name would be semver-major. exports.translatePeerCertificate = function translatePeerCertificate(c) { if (!c) return null; diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index aa8b66b7155b3e..36440ad4eaddf8 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -660,7 +660,17 @@ TLSSocket.prototype.setSession = function(session) { TLSSocket.prototype.getPeerCertificate = function(detailed) { if (this._handle) { return common.translatePeerCertificate( - this._handle.getPeerCertificate(detailed)); + this._handle.getPeerCertificate(detailed)) || {}; + } + + return null; +}; + +TLSSocket.prototype.getCertificate = function() { + if (this._handle) { + // It's not a peer cert, but the formatting is identical. + return common.translatePeerCertificate( + this._handle.getCertificate()) || {}; } return null; diff --git a/lib/assert.js b/lib/assert.js index 9990d0e888e1c5..6963ef41307397 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -315,8 +315,8 @@ function getErrMessage(message, fn) { errorCache.set(identifier, message); return message; - } catch (e) { - // Invalidate cache to prevent trying to read this part again. + } catch { + // Invalidate cache to prevent trying to read this part again. errorCache.set(identifier, undefined); } finally { // Reset limit. diff --git a/lib/child_process.js b/lib/child_process.js index 7ac3a3bcc0a7f3..711764dba7e06e 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -69,6 +69,11 @@ exports.fork = function fork(modulePath /* , args, options */) { args = arguments[pos++]; } + if (pos < arguments.length && + (arguments[pos] === undefined || arguments[pos] === null)) { + pos++; + } + if (pos < arguments.length && arguments[pos] != null) { if (typeof arguments[pos] !== 'object') { throw new ERR_INVALID_ARG_VALUE(`arguments[${pos}]`, arguments[pos]); @@ -219,7 +224,7 @@ exports.execFile = function execFile(file /* , args, options, callback */) { gid: options.gid, uid: options.uid, shell: options.shell, - windowsHide: options.windowsHide !== false, + windowsHide: !!options.windowsHide, windowsVerbatimArguments: !!options.windowsVerbatimArguments }); @@ -539,7 +544,7 @@ var spawn = exports.spawn = function spawn(/* file, args, options */) { file: opts.file, args: opts.args, cwd: options.cwd, - windowsHide: options.windowsHide !== false, + windowsHide: !!options.windowsHide, windowsVerbatimArguments: !!options.windowsVerbatimArguments, detached: !!options.detached, envPairs: opts.envPairs, @@ -573,8 +578,6 @@ function spawnSync(/* file, args, options */) { options.stdio = _validateStdio(options.stdio || 'pipe', true).stdio; - options.windowsHide = options.windowsHide !== false; - if (options.input) { var stdin = options.stdio[0] = util._extend({}, options.stdio[0]); stdin.input = options.input; diff --git a/lib/console.js b/lib/console.js index 96bd1855859809..fe2613c8df9560 100644 --- a/lib/console.js +++ b/lib/console.js @@ -253,7 +253,7 @@ Console.prototype.timeEnd = function timeEnd(label = 'default') { } }; -Console.prototype.timeLog = function timeLog(label, ...data) { +Console.prototype.timeLog = function timeLog(label = 'default', ...data) { // Coerces everything other than Symbol to a string label = `${label}`; timeLogImpl(this, 'timeLog', label, data); @@ -261,7 +261,7 @@ Console.prototype.timeLog = function timeLog(label, ...data) { }; // Returns true if label was not found -function timeLogImpl(self, name, label = 'default', data) { +function timeLogImpl(self, name, label, data) { const time = self._times.get(label); if (!time) { process.emitWarning(`No such label '${label}' for console.${name}()`); diff --git a/lib/crypto.js b/lib/crypto.js index 13987f9e03e230..f6c5b7313b69af 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -35,8 +35,8 @@ const { ERR_CRYPTO_FIPS_UNAVAILABLE } = require('internal/errors').codes; const constants = internalBinding('constants').crypto; -const { getOptions } = internalBinding('options'); -const pendingDeprecation = getOptions('--pending-deprecation'); +const { getOptionValue } = require('internal/options'); +const pendingDeprecation = getOptionValue('--pending-deprecation'); const { fipsMode, fipsForced diff --git a/lib/events.js b/lib/events.js index ff1648d6aa13e7..e59ff3f04dd93b 100644 --- a/lib/events.js +++ b/lib/events.js @@ -160,7 +160,7 @@ EventEmitter.prototype.emit = function emit(type, ...args) { value: enhanceStackTrace.bind(null, er, capture), configurable: true }); - } catch (e) {} + } catch {} // Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. diff --git a/lib/fs.js b/lib/fs.js index 89c005375f450e..a717d794345698 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -209,7 +209,7 @@ function exists(path, callback) { try { fs.access(path, F_OK, suppressedCallback); - } catch (err) { + } catch { return callback(false); } } @@ -228,11 +228,14 @@ Object.defineProperty(exists, internalUtil.promisify.custom, { // TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior function existsSync(path) { try { - fs.accessSync(path, F_OK); - return true; - } catch (e) { + path = toPathIfFileURL(path); + validatePath(path); + } catch { return false; } + const ctx = { path }; + binding.access(pathModule.toNamespacedPath(path), F_OK, undefined, ctx); + return ctx.errno === undefined; } function readFileAfterOpen(err, fd) { @@ -415,7 +418,7 @@ function open(path, flags, mode, callback) { callback = flags; flags = 'r'; mode = 0o666; - } else if (arguments.length === 3) { + } else if (typeof mode === 'function') { callback = mode; mode = 0o666; } @@ -808,7 +811,7 @@ function readdirSync(path, options) { } function fstat(fd, options, callback) { - if (arguments.length < 3) { + if (typeof options === 'function') { callback = options; options = {}; } @@ -819,7 +822,7 @@ function fstat(fd, options, callback) { } function lstat(path, options, callback) { - if (arguments.length < 3) { + if (typeof options === 'function') { callback = options; options = {}; } @@ -832,7 +835,7 @@ function lstat(path, options, callback) { } function stat(path, options, callback) { - if (arguments.length < 3) { + if (typeof options === 'function') { callback = options; options = {}; } diff --git a/lib/internal/bash_completion.js b/lib/internal/bash_completion.js index cb8eab9ceec855..13363e8c4b8c32 100644 --- a/lib/internal/bash_completion.js +++ b/lib/internal/bash_completion.js @@ -1,8 +1,7 @@ 'use strict'; -const { getOptions } = internalBinding('options'); +const { options, aliases } = require('internal/options'); function print(stream) { - const { options, aliases } = getOptions(); const all_opts = [...options.keys(), ...aliases.keys()]; stream.write(`_node_complete() { diff --git a/lib/internal/bootstrap/cache.js b/lib/internal/bootstrap/cache.js index 41fe1e3a914ba0..ff6c4422c1148c 100644 --- a/lib/internal/bootstrap/cache.js +++ b/lib/internal/bootstrap/cache.js @@ -6,21 +6,15 @@ // cannot be tampered with even with --expose-internals const { - NativeModule, internalBinding + NativeModule } = require('internal/bootstrap/loaders'); +const { + source, + compileCodeCache +} = internalBinding('native_module'); +const { hasTracing } = process.binding('config'); -function getCodeCache(id) { - const cached = NativeModule.getCached(id); - if (cached && (cached.loaded || cached.loading)) { - return cached.script.createCachedData(); - } - - // The script has not been compiled and run - NativeModule.require(id); - return getCodeCache(id); -} - -const depsModule = Object.keys(NativeModule._source).filter( +const depsModule = Object.keys(source).filter( (key) => NativeModule.isDepsModule(key) || key.startsWith('internal/deps') ); @@ -42,18 +36,42 @@ const cannotUseCache = [ 'internal/bootstrap/node' ].concat(depsModule); +// Skip modules that cannot be required when they are not +// built into the binary. +if (process.config.variables.v8_enable_inspector !== 1) { + cannotUseCache.push('inspector'); + cannotUseCache.push('internal/util/inspector'); +} +if (!hasTracing) { + cannotUseCache.push('trace_events'); +} +if (!process.versions.openssl) { + cannotUseCache.push('crypto'); + cannotUseCache.push('https'); + cannotUseCache.push('http2'); + cannotUseCache.push('tls'); + cannotUseCache.push('_tls_common'); + cannotUseCache.push('_tls_wrap'); + cannotUseCache.push('internal/crypto/certificate'); + cannotUseCache.push('internal/crypto/cipher'); + cannotUseCache.push('internal/crypto/diffiehellman'); + cannotUseCache.push('internal/crypto/hash'); + cannotUseCache.push('internal/crypto/keygen'); + cannotUseCache.push('internal/crypto/pbkdf2'); + cannotUseCache.push('internal/crypto/random'); + cannotUseCache.push('internal/crypto/scrypt'); + cannotUseCache.push('internal/crypto/sig'); + cannotUseCache.push('internal/crypto/util'); + cannotUseCache.push('internal/http2/core'); + cannotUseCache.push('internal/http2/compat'); + cannotUseCache.push('internal/streams/lazy_transform'); +} + module.exports = { - cachableBuiltins: Object.keys(NativeModule._source).filter( + cachableBuiltins: Object.keys(source).filter( (key) => !cannotUseCache.includes(key) ), - builtinSource: Object.assign({}, NativeModule._source), - getCodeCache, - getSource: NativeModule.getSource, - codeCache: internalBinding('code_cache'), - compiledWithoutCache: NativeModule.compiledWithoutCache, - compiledWithCache: NativeModule.compiledWithCache, - nativeModuleWrap(script) { - return NativeModule.wrap(script); - }, + getSource(id) { return source[id]; }, + getCodeCache: compileCodeCache, cannotUseCache }; diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index dff6ce661a4640..78e1180dde2af2 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -70,12 +70,52 @@ writable: false }); + // internalBindingWhitelist contains the name of internalBinding modules + // that are whitelisted for access via process.binding()... this is used + // to provide a transition path for modules that are being moved over to + // internalBinding. + const internalBindingWhitelist = [ + 'async_wrap', + 'buffer', + 'cares_wrap', + 'constants', + 'contextify', + 'crypto', + 'fs_event_wrap', + 'http_parser', + 'icu', + 'js_stream', + 'natives', + 'pipe_wrap', + 'process_wrap', + 'signal_wrap', + 'spawn_sync', + 'stream_wrap', + 'tcp_wrap', + 'tls_wrap', + 'tty_wrap', + 'udp_wrap', + 'url', + 'util', + 'uv', + 'v8', + 'zlib' + ]; + // We will use a lazy loaded SafeSet in internalBindingWhitelistHas + // for checking existence in this list. + let internalBindingWhitelistSet; + // Set up process.binding() and process._linkedBinding() { const bindingObj = ObjectCreate(null); process.binding = function binding(module) { module = String(module); + // Deprecated specific process.binding() modules, but not all, allow + // selective fallback to internalBinding for the deprecated ones. + if (internalBindingWhitelistHas(module)) { + return internalBinding(module); + } let mod = bindingObj[module]; if (typeof mod !== 'object') { mod = bindingObj[module] = getBinding(module); @@ -109,7 +149,6 @@ // Create this WeakMap in js-land because V8 has no C++ API for WeakMap internalBinding('module_wrap').callbackMap = new WeakMap(); - const { ContextifyScript } = internalBinding('contextify'); // Set up NativeModule function NativeModule(id) { @@ -120,7 +159,6 @@ this.exportKeys = undefined; this.loaded = false; this.loading = false; - this.script = null; // The ContextifyScript of the module } NativeModule._source = getInternalBinding('natives'); @@ -128,12 +166,6 @@ const config = getBinding('config'); - const codeCache = getInternalBinding('code_cache'); - const codeCacheHash = getInternalBinding('code_cache_hash'); - const sourceHash = getInternalBinding('natives_hash'); - const compiledWithoutCache = NativeModule.compiledWithoutCache = []; - const compiledWithCache = NativeModule.compiledWithCache = []; - // Think of this as module.exports in this file even though it is not // written in CommonJS style. const loaderExports = { internalBinding, NativeModule }; @@ -211,8 +243,7 @@ NativeModule.isInternal = function(id) { return id.startsWith('internal/') || - (id === 'worker_threads' && - !internalBinding('options').getOptions('--experimental-worker')); + (id === 'worker_threads' && !config.experimentalWorker); }; } @@ -235,121 +266,80 @@ undefined; }; + // Provide named exports for all builtin libraries so that the libraries + // may be imported in a nicer way for esm users. The default export is left + // as the entire namespace (module.exports) and wrapped in a proxy such + // that APMs and other behavior are still left intact. + NativeModule.prototype.proxifyExports = function() { + this.exportKeys = ObjectKeys(this.exports); + + const update = (property, value) => { + if (this.reflect !== undefined && + ReflectApply(ObjectHasOwnProperty, + this.reflect.exports, [property])) + this.reflect.exports[property].set(value); + }; + + const handler = { + __proto__: null, + defineProperty: (target, prop, descriptor) => { + // Use `Object.defineProperty` instead of `Reflect.defineProperty` + // to throw the appropriate error if something goes wrong. + ObjectDefineProperty(target, prop, descriptor); + if (typeof descriptor.get === 'function' && + !ReflectHas(handler, 'get')) { + handler.get = (target, prop, receiver) => { + const value = ReflectGet(target, prop, receiver); + if (ReflectApply(ObjectHasOwnProperty, target, [prop])) + update(prop, value); + return value; + }; + } + update(prop, getOwn(target, prop)); + return true; + }, + deleteProperty: (target, prop) => { + if (ReflectDeleteProperty(target, prop)) { + update(prop, undefined); + return true; + } + return false; + }, + set: (target, prop, value, receiver) => { + const descriptor = ReflectGetOwnPropertyDescriptor(target, prop); + if (ReflectSet(target, prop, value, receiver)) { + if (descriptor && typeof descriptor.set === 'function') { + for (const key of this.exportKeys) { + update(key, getOwn(target, key, receiver)); + } + } else { + update(prop, getOwn(target, prop, receiver)); + } + return true; + } + return false; + } + }; + + this.exports = new Proxy(this.exports, handler); + }; + + const { compileFunction } = getInternalBinding('native_module'); NativeModule.prototype.compile = function() { const id = this.id; - let source = NativeModule.getSource(id); - source = NativeModule.wrap(source); this.loading = true; try { - // Currently V8 only checks that the length of the source code is the - // same as the code used to generate the hash, so we add an additional - // check here: - // 1. During compile time, when generating node_javascript.cc and - // node_code_cache.cc, we compute and include the hash of the - // (unwrapped) JavaScript source in both. - // 2. At runtime, we check that the hash of the code being compiled - // and the hash of the code used to generate the cache - // (inside the wrapper) is the same. - // This is based on the assumptions: - // 1. `internalBinding('code_cache_hash')` must be in sync with - // `internalBinding('code_cache')` (same C++ file) - // 2. `internalBinding('natives_hash')` must be in sync with - // `internalBinding('natives')` (same C++ file) - // 3. If `internalBinding('natives_hash')` is in sync with - // `internalBinding('natives_hash')`, then the (unwrapped) - // code used to generate `internalBinding('code_cache')` - // should be in sync with the (unwrapped) code in - // `internalBinding('natives')` - // There will be, however, false positives if the wrapper used - // to generate the cache is different from the one used at run time, - // and the length of the wrapper somehow stays the same. - // But that should be rare and can be eased once we make the - // two bootstrappers cached and checked as well. - const cache = codeCacheHash[id] && - (codeCacheHash[id] === sourceHash[id]) ? codeCache[id] : undefined; - - // (code, filename, lineOffset, columnOffset - // cachedData, produceCachedData, parsingContext) - const script = new ContextifyScript( - source, this.filename, 0, 0, - cache, false, undefined - ); - - // This will be used to create code cache in tools/generate_code_cache.js - this.script = script; - - // One of these conditions may be false when any of the inputs - // of the `node_js2c` target in node.gyp is modified. - // FIXME(joyeecheung): Figure out how to resolve the dependency issue. - // When the code cache was introduced we were at a point where refactoring - // node.gyp may not be worth the effort. - if (!cache || script.cachedDataRejected) { - compiledWithoutCache.push(this.id); - } else { - compiledWithCache.push(this.id); - } - - // Arguments: timeout, displayErrors, breakOnSigint - const fn = script.runInThisContext(-1, true, false); const requireFn = this.id.startsWith('internal/deps/') ? NativeModule.requireForDeps : NativeModule.require; + + const fn = compileFunction(id); fn(this.exports, requireFn, this, process, internalBinding); if (config.experimentalModules && !NativeModule.isInternal(this.id)) { - this.exportKeys = ObjectKeys(this.exports); - - const update = (property, value) => { - if (this.reflect !== undefined && - ReflectApply(ObjectHasOwnProperty, - this.reflect.exports, [property])) - this.reflect.exports[property].set(value); - }; - - const handler = { - __proto__: null, - defineProperty: (target, prop, descriptor) => { - // Use `Object.defineProperty` instead of `Reflect.defineProperty` - // to throw the appropriate error if something goes wrong. - ObjectDefineProperty(target, prop, descriptor); - if (typeof descriptor.get === 'function' && - !ReflectHas(handler, 'get')) { - handler.get = (target, prop, receiver) => { - const value = ReflectGet(target, prop, receiver); - if (ReflectApply(ObjectHasOwnProperty, target, [prop])) - update(prop, value); - return value; - }; - } - update(prop, getOwn(target, prop)); - return true; - }, - deleteProperty: (target, prop) => { - if (ReflectDeleteProperty(target, prop)) { - update(prop, undefined); - return true; - } - return false; - }, - set: (target, prop, value, receiver) => { - const descriptor = ReflectGetOwnPropertyDescriptor(target, prop); - if (ReflectSet(target, prop, value, receiver)) { - if (descriptor && typeof descriptor.set === 'function') { - for (const key of this.exportKeys) { - update(key, getOwn(target, key, receiver)); - } - } else { - update(prop, getOwn(target, prop, receiver)); - } - return true; - } - return false; - } - }; - - this.exports = new Proxy(this.exports, handler); + this.proxifyExports(); } this.loaded = true; @@ -362,6 +352,20 @@ NativeModule._cache[this.id] = this; }; + // coverage must be turned on early, so that we can collect + // it for Node.js' own internal libraries. + if (process.env.NODE_V8_COVERAGE) { + NativeModule.require('internal/process/coverage').setup(); + } + + function internalBindingWhitelistHas(name) { + if (!internalBindingWhitelistSet) { + const { SafeSet } = NativeModule.require('internal/safe_globals'); + internalBindingWhitelistSet = new SafeSet(internalBindingWhitelist); + } + return internalBindingWhitelistSet.has(name); + } + // This will be passed to the bootstrapNodeJSCore function in // bootstrap/node.js. return loaderExports; diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 1ba427a572e3f7..85bfc688b391c0 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -17,7 +17,7 @@ // avoid retaining a reference to the bootstrap // object. { _setupTraceCategoryState, - _setupProcessObject, _setupNextTick, + _setupNextTick, _setupPromises, _chdir, _cpuUsage, _hrtime, _hrtimeBigInt, _memoryUsage, _rawDebug, @@ -30,13 +30,6 @@ const isMainThread = internalBinding('worker').threadId === 0; function startup() { - const EventEmitter = NativeModule.require('events'); - - const origProcProto = Object.getPrototypeOf(process); - Object.setPrototypeOf(origProcProto, EventEmitter.prototype); - - EventEmitter.call(process); - setupTraceCategoryState(); setupProcessObject(); @@ -103,21 +96,20 @@ NativeModule.require('internal/process/write-coverage').setup(); if (process.env.NODE_V8_COVERAGE) { - const { resolve } = NativeModule.require('path'); - process.env.NODE_V8_COVERAGE = resolve(process.env.NODE_V8_COVERAGE); - NativeModule.require('internal/process/coverage').setup(); + NativeModule.require('internal/process/coverage').setupExitHooks(); } if (process.config.variables.v8_enable_inspector) { NativeModule.require('internal/inspector_async_hook').setup(); } - const { getOptions } = internalBinding('options'); - const helpOption = getOptions('--help'); - const completionBashOption = getOptions('--completion-bash'); - const experimentalModulesOption = getOptions('--experimental-modules'); - const experimentalVMModulesOption = getOptions('--experimental-vm-modules'); - const experimentalWorkerOption = getOptions('--experimental-worker'); + const { getOptionValue } = NativeModule.require('internal/options'); + const helpOption = getOptionValue('--help'); + const completionBashOption = getOptionValue('--completion-bash'); + const experimentalModulesOption = getOptionValue('--experimental-modules'); + const experimentalVMModulesOption = + getOptionValue('--experimental-vm-modules'); + const experimentalWorkerOption = getOptionValue('--experimental-worker'); if (helpOption) { NativeModule.require('internal/print_help').print(process.stdout); return; @@ -380,53 +372,10 @@ } function setupProcessObject() { - _setupProcessObject(pushValueToArray); - - function pushValueToArray() { - for (var i = 0; i < arguments.length; i++) - this.push(arguments[i]); - } - - // Deprecated specific process.binding() modules, but not all, allow - // selective fallback to internalBinding for the deprecated ones. - const { SafeSet } = NativeModule.require('internal/safe_globals'); - const processBinding = process.binding; - // internalBindingWhitelist contains the name of internalBinding modules - // that are whitelisted for access via process.binding()... this is used - // to provide a transition path for modules that are being moved over to - // internalBinding. - const internalBindingWhitelist = - new SafeSet([ - 'cares_wrap', - 'fs_event_wrap', - 'icu', - 'udp_wrap', - 'uv', - 'pipe_wrap', - 'http_parser', - 'process_wrap', - 'v8', - 'tty_wrap', - 'stream_wrap', - 'signal_wrap', - 'crypto', - 'contextify', - 'tcp_wrap', - 'tls_wrap', - 'util', - 'async_wrap', - 'url', - 'spawn_sync', - 'js_stream', - 'zlib', - 'buffer', - 'natives', - 'constants']); - process.binding = function binding(name) { - return internalBindingWhitelist.has(name) ? - internalBinding(name) : - processBinding(name); - }; + const EventEmitter = NativeModule.require('events'); + const origProcProto = Object.getPrototypeOf(process); + Object.setPrototypeOf(origProcProto, EventEmitter.prototype); + EventEmitter.call(process); } function setupGlobalVariables() { @@ -687,7 +636,7 @@ function tryGetCwd(path) { try { return process.cwd(); - } catch (ex) { + } catch { // getcwd(3) can fail if the current working directory has been deleted. // Fall back to the directory name of the (absolute) executable path. // It's not really correct but what are the alternatives? @@ -766,10 +715,9 @@ const get = () => { const { - getOptions, envSettings: { kAllowedInEnvironment } } = internalBinding('options'); - const { options, aliases } = getOptions(); + const { options, aliases } = NativeModule.require('internal/options'); const allowedNodeEnvironmentFlags = []; for (const [name, info] of options) { diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index 61bdced4d63a58..137ca64142bf62 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -667,7 +667,7 @@ function writeU_Int16BE(buf, value, offset, min, max) { } function writeUInt16BE(value, offset = 0) { - return writeU_Int16BE(this, value, offset, 0, 0xffffffff); + return writeU_Int16BE(this, value, offset, 0, 0xffff); } function writeIntLE(value, offset, byteLength) { diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 5723611cd12f6d..d3953f5b6ec616 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -38,8 +38,6 @@ const { owner_symbol } = require('internal/async_hooks').symbols; const { convertToValidSignal } = require('internal/util'); const { isArrayBufferView } = require('internal/util/types'); const spawn_sync = internalBinding('spawn_sync'); -const { HTTPParser } = internalBinding('http_parser'); -const { freeParser } = require('_http_common'); const { kStateSymbol } = require('internal/dgram'); const { @@ -57,6 +55,10 @@ const { SocketListSend, SocketListReceive } = SocketList; // Lazy loaded for startup performance. let StringDecoder; +// Lazy loaded for startup performance and to allow monkey patching of +// internalBinding('http_parser').HTTPParser. +let freeParser; +let HTTPParser; const MAX_HANDLE_RETRANSMISSIONS = 3; @@ -121,6 +123,12 @@ const handleConversion = { handle.onread = nop; socket._handle = null; socket.setTimeout(0); + + if (freeParser === undefined) + freeParser = require('_http_common').freeParser; + if (HTTPParser === undefined) + HTTPParser = internalBinding('http_parser').HTTPParser; + // In case of an HTTP connection socket, release the associated // resources if (socket.parser && socket.parser instanceof HTTPParser) { diff --git a/lib/internal/crypto/cipher.js b/lib/internal/crypto/cipher.js index a2e973ed849f10..a3f28c183a46b7 100644 --- a/lib/internal/crypto/cipher.js +++ b/lib/internal/crypto/cipher.js @@ -74,7 +74,7 @@ function getUIntOption(options, key) { function createCipherBase(cipher, credential, options, decipher, iv) { const authTagLength = getUIntOption(options, 'authTagLength'); - legacyNativeHandle(this, new CipherBase(decipher)); + this[kHandle] = new CipherBase(decipher); if (iv === undefined) { this[kHandle].init(cipher, credential, authTagLength); } else { @@ -219,6 +219,8 @@ Cipher.prototype.setAAD = function setAAD(aadbuf, options) { return this; }; +legacyNativeHandle(Cipher); + function Cipheriv(cipher, key, iv, options) { if (!(this instanceof Cipheriv)) return new Cipheriv(cipher, key, iv, options); @@ -254,6 +256,7 @@ function addCipherPrototypeFunctions(constructor) { inherits(Cipheriv, LazyTransform); addCipherPrototypeFunctions(Cipheriv); +legacyNativeHandle(Cipheriv); function Decipher(cipher, password, options) { if (!(this instanceof Decipher)) @@ -264,6 +267,7 @@ function Decipher(cipher, password, options) { inherits(Decipher, LazyTransform); addCipherPrototypeFunctions(Decipher); +legacyNativeHandle(Decipher); function Decipheriv(cipher, key, iv, options) { @@ -275,6 +279,7 @@ function Decipheriv(cipher, key, iv, options) { inherits(Decipheriv, LazyTransform); addCipherPrototypeFunctions(Decipheriv); +legacyNativeHandle(Decipheriv); module.exports = { Cipher, diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js index 4f5bcbad972b26..81204cfda3e676 100644 --- a/lib/internal/crypto/diffiehellman.js +++ b/lib/internal/crypto/diffiehellman.js @@ -61,7 +61,7 @@ function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) { else if (typeof generator !== 'number') generator = toBuf(generator, genEncoding); - legacyNativeHandle(this, new _DiffieHellman(sizeOrKey, generator)); + this[kHandle] = new _DiffieHellman(sizeOrKey, generator); Object.defineProperty(this, 'verifyError', { enumerable: true, value: this[kHandle].verifyError, @@ -73,7 +73,7 @@ function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) { function DiffieHellmanGroup(name) { if (!(this instanceof DiffieHellmanGroup)) return new DiffieHellmanGroup(name); - legacyNativeHandle(this, new _DiffieHellmanGroup(name)); + this[kHandle] = new _DiffieHellmanGroup(name); Object.defineProperty(this, 'verifyError', { enumerable: true, value: this[kHandle].verifyError, @@ -165,13 +165,16 @@ DiffieHellman.prototype.setPrivateKey = function setPrivateKey(key, encoding) { return this; }; +legacyNativeHandle(DiffieHellman); +legacyNativeHandle(DiffieHellmanGroup); + function ECDH(curve) { if (!(this instanceof ECDH)) return new ECDH(curve); validateString(curve, 'curve'); - legacyNativeHandle(this, new _ECDH(curve)); + this[kHandle] = new _ECDH(curve); } ECDH.prototype.computeSecret = DiffieHellman.prototype.computeSecret; @@ -192,6 +195,8 @@ ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) { return encode(key, encoding); }; +legacyNativeHandle(ECDH); + ECDH.convertKey = function convertKey(key, curve, inEnc, outEnc, format) { if (typeof key !== 'string' && !isArrayBufferView(key)) { throw new ERR_INVALID_ARG_TYPE( diff --git a/lib/internal/crypto/hash.js b/lib/internal/crypto/hash.js index 308c16f9a88b93..6803d8fa954e73 100644 --- a/lib/internal/crypto/hash.js +++ b/lib/internal/crypto/hash.js @@ -32,7 +32,7 @@ function Hash(algorithm, options) { if (!(this instanceof Hash)) return new Hash(algorithm, options); validateString(algorithm, 'algorithm'); - legacyNativeHandle(this, new _Hash(algorithm)); + this[kHandle] = new _Hash(algorithm); this[kState] = { [kFinalized]: false }; @@ -81,6 +81,8 @@ Hash.prototype.digest = function digest(outputEncoding) { return ret; }; +legacyNativeHandle(Hash); + function Hmac(hmac, key, options) { if (!(this instanceof Hmac)) @@ -90,7 +92,7 @@ function Hmac(hmac, key, options) { throw new ERR_INVALID_ARG_TYPE('key', ['string', 'TypedArray', 'DataView'], key); } - legacyNativeHandle(this, new _Hmac()); + this[kHandle] = new _Hmac(); this[kHandle].init(hmac, toBuf(key)); this[kState] = { [kFinalized]: false @@ -122,6 +124,8 @@ Hmac.prototype.digest = function digest(outputEncoding) { Hmac.prototype._flush = Hash.prototype._flush; Hmac.prototype._transform = Hash.prototype._transform; +legacyNativeHandle(Hmac); + module.exports = { Hash, Hmac diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index 43033345afa545..9f02c866739f24 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -24,7 +24,7 @@ function Sign(algorithm, options) { if (!(this instanceof Sign)) return new Sign(algorithm, options); validateString(algorithm, 'algorithm'); - legacyNativeHandle(this, new _Sign()); + this[kHandle] = new _Sign(); this[kHandle].init(algorithm); Writable.call(this, options); @@ -45,6 +45,8 @@ Sign.prototype.update = function update(data, encoding) { return this; }; +legacyNativeHandle(Sign); + function getPadding(options) { return getIntOption('padding', RSA_PKCS1_PADDING, options); } @@ -93,7 +95,7 @@ function Verify(algorithm, options) { if (!(this instanceof Verify)) return new Verify(algorithm, options); validateString(algorithm, 'algorithm'); - legacyNativeHandle(this, new _Verify()); + this[kHandle] = new _Verify(); this[kHandle].init(algorithm); Writable.call(this, options); @@ -121,6 +123,8 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { return this[kHandle].verify(key, signature, rsaPadding, pssSaltLength); }; +legacyNativeHandle(Verify); + module.exports = { Sign, Verify diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index ff5bfce4a76a49..6746f2a66c818a 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -30,15 +30,14 @@ const { const kHandle = Symbol('kHandle'); -function legacyNativeHandle(obj, handle) { - obj[kHandle] = handle; - Object.defineProperty(obj, '_handle', { - get: deprecate(() => handle, - `${obj.constructor.name}._handle is deprecated. Use the ` + - 'public API instead.', 'DEP0117'), - set: deprecate((h) => obj[kHandle] = handle = h, - `${obj.constructor.name}._handle is deprecated. Use the ` + - 'public API instead.', 'DEP0117'), +function legacyNativeHandle(clazz) { + Object.defineProperty(clazz.prototype, '_handle', { + get: deprecate(function() { return this[kHandle]; }, + `${clazz.name}._handle is deprecated. Use the public API ` + + 'instead.', 'DEP0117'), + set: deprecate(function(h) { this[kHandle] = h; }, + `${clazz.name}._handle is deprecated. Use the public API ` + + 'instead.', 'DEP0117'), enumerable: false }); } diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 044303be5a560d..5fec67d6c721af 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -294,10 +294,9 @@ function uvException(ctx) { * @param {string} syscall * @param {string} address * @param {number} [port] - * @param {string} [additional] * @returns {Error} */ -function uvExceptionWithHostPort(err, syscall, address, port, additional) { +function uvExceptionWithHostPort(err, syscall, address, port) { const [ code, uvmsg ] = errmap.get(err); const message = `${syscall} ${code}: ${uvmsg}`; let details = ''; @@ -307,9 +306,6 @@ function uvExceptionWithHostPort(err, syscall, address, port, additional) { } else if (address) { details = ` ${address}`; } - if (additional) { - details += ` - Local (${additional})`; - } // eslint-disable-next-line no-restricted-syntax const ex = new Error(`${message}${details}`); diff --git a/lib/internal/fs/streams.js b/lib/internal/fs/streams.js index a2ae1c9787d288..8c9ed35f81c2f4 100644 --- a/lib/internal/fs/streams.js +++ b/lib/internal/fs/streams.js @@ -228,6 +228,11 @@ ReadStream.prototype.close = function(cb) { this.destroy(null, cb); }; +Object.defineProperty(ReadStream.prototype, 'pending', { + get() { return this.fd === null; }, + configurable: true +}); + function WriteStream(path, options) { if (!(this instanceof WriteStream)) return new WriteStream(path, options); @@ -394,6 +399,11 @@ WriteStream.prototype.close = function(cb) { // There is no shutdown() for files. WriteStream.prototype.destroySoon = WriteStream.prototype.end; +Object.defineProperty(WriteStream.prototype, 'pending', { + get() { return this.fd === null; }, + configurable: true +}); + module.exports = { ReadStream, WriteStream diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index ded26644c590d5..5253be1b393460 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -1689,6 +1689,12 @@ class Http2Stream extends Duplex { return `Http2Stream ${util.format(obj)}`; } + get bufferSize() { + // `bufferSize` properties of `net.Socket` are `undefined` when + // their `_handle` are falsy. Here we avoid the behavior. + return this[kState].writeQueueSize + this.writableLength; + } + get endAfterHeaders() { return this[kState].endAfterHeaders; } @@ -1823,7 +1829,7 @@ class Http2Stream extends Duplex { _final(cb) { const handle = this[kHandle]; - if (this[kID] === undefined) { + if (this.pending) { this.once('ready', () => this._final(cb)); } else if (handle !== undefined) { debug(`Http2Stream ${this[kID]} [Http2Session ` + diff --git a/lib/internal/http2/util.js b/lib/internal/http2/util.js index 94dc1198ea1060..c8701af616f327 100644 --- a/lib/internal/http2/util.js +++ b/lib/internal/http2/util.js @@ -430,14 +430,20 @@ function mapToHeaders(map, let count = 0; const keys = Object.keys(map); const singles = new Set(); - for (var i = 0; i < keys.length; i++) { - let key = keys[i]; - let value = map[key]; + let i; + let isArray; + let key; + let value; + let isSingleValueHeader; + let err; + for (i = 0; i < keys.length; i++) { + key = keys[i]; + value = map[key]; if (value === undefined || key === '') continue; key = key.toLowerCase(); - const isSingleValueHeader = kSingleValueHeaders.has(key); - let isArray = Array.isArray(value); + isSingleValueHeader = kSingleValueHeaders.has(key); + isArray = Array.isArray(value); if (isArray) { switch (value.length) { case 0: @@ -459,26 +465,26 @@ function mapToHeaders(map, singles.add(key); } if (key[0] === ':') { - const err = assertValuePseudoHeader(key); + err = assertValuePseudoHeader(key); if (err !== undefined) return err; ret = `${key}\0${value}\0${ret}`; count++; - } else { - if (isIllegalConnectionSpecificHeader(key, value)) { - return new ERR_HTTP2_INVALID_CONNECTION_HEADERS(key); - } - if (isArray) { - for (var k = 0; k < value.length; k++) { - const val = String(value[k]); - ret += `${key}\0${val}\0`; - } - count += value.length; - } else { - ret += `${key}\0${value}\0`; - count++; + continue; + } + if (isIllegalConnectionSpecificHeader(key, value)) { + return new ERR_HTTP2_INVALID_CONNECTION_HEADERS(key); + } + if (isArray) { + for (var k = 0; k < value.length; k++) { + const val = String(value[k]); + ret += `${key}\0${val}\0`; } + count += value.length; + continue; } + ret += `${key}\0${value}\0`; + count++; } return [ret, count]; diff --git a/lib/internal/modules/cjs/helpers.js b/lib/internal/modules/cjs/helpers.js index cda94987fad210..b08e97b29c5c8d 100644 --- a/lib/internal/modules/cjs/helpers.js +++ b/lib/internal/modules/cjs/helpers.js @@ -9,7 +9,7 @@ const { CHAR_HASH, } = require('internal/constants'); -const { getOptions } = internalBinding('options'); +const { getOptionValue } = require('internal/options'); // Invoke with makeRequireFunction(module) where |module| is the Module object // to use as the context for the require() function. @@ -107,7 +107,7 @@ const builtinLibs = [ 'v8', 'vm', 'zlib' ]; -if (getOptions('--experimental-worker')) { +if (getOptionValue('--experimental-worker')) { builtinLibs.push('worker_threads'); builtinLibs.sort(); } diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 975c688edab3d7..506bae4b7870e4 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -41,10 +41,10 @@ const { stripBOM, stripShebang } = require('internal/modules/cjs/helpers'); -const options = internalBinding('options'); -const preserveSymlinks = options.getOptions('--preserve-symlinks'); -const preserveSymlinksMain = options.getOptions('--preserve-symlinks-main'); -const experimentalModules = options.getOptions('--experimental-modules'); +const { getOptionValue } = require('internal/options'); +const preserveSymlinks = getOptionValue('--preserve-symlinks'); +const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); +const experimentalModules = getOptionValue('--experimental-modules'); const { ERR_INVALID_ARG_TYPE, @@ -219,6 +219,22 @@ function tryExtensions(p, exts, isMain) { return false; } +// find the longest (possibly multi-dot) extension registered in +// Module._extensions +function findLongestRegisteredExtension(filename) { + const name = path.basename(filename); + let currentExtension; + let index; + let startIndex = 0; + while ((index = name.indexOf('.', startIndex)) !== -1) { + startIndex = index + 1; + if (index === 0) continue; // Skip dotfiles like .gitignore + currentExtension = name.slice(index); + if (Module._extensions[currentExtension]) return currentExtension; + } + return '.js'; +} + var warned = false; Module._findPath = function(request, paths, isMain) { if (path.isAbsolute(request)) { @@ -600,8 +616,7 @@ Module.prototype.load = function(filename) { this.filename = filename; this.paths = Module._nodeModulePaths(path.dirname(filename)); - var extension = path.extname(filename) || '.js'; - if (!Module._extensions[extension]) extension = '.js'; + var extension = findLongestRegisteredExtension(filename); Module._extensions[extension](this, filename); this.loaded = true; diff --git a/lib/internal/modules/esm/default_resolve.js b/lib/internal/modules/esm/default_resolve.js index 7654ca91129325..9aa54d09a1b07c 100644 --- a/lib/internal/modules/esm/default_resolve.js +++ b/lib/internal/modules/esm/default_resolve.js @@ -6,9 +6,9 @@ const internalFS = require('internal/fs/utils'); const { NativeModule } = require('internal/bootstrap/loaders'); const { extname } = require('path'); const { realpathSync } = require('fs'); -const { getOptions } = internalBinding('options'); -const preserveSymlinks = getOptions('--preserve-symlinks'); -const preserveSymlinksMain = getOptions('--preserve-symlinks-main'); +const { getOptionValue } = require('internal/options'); +const preserveSymlinks = getOptionValue('--preserve-symlinks'); +const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); const { ERR_MISSING_MODULE, ERR_MODULE_RESOLUTION_LEGACY, diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 89f40939e7a4f3..60f1e31f94e86e 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -80,7 +80,7 @@ class Loader { if (this._resolve !== defaultResolve) { try { new URL(url); - } catch (e) { + } catch { throw new ERR_INVALID_RETURN_PROPERTY( 'url', 'loader resolve', 'url', url ); diff --git a/lib/internal/options.js b/lib/internal/options.js new file mode 100644 index 00000000000000..e494787b96c088 --- /dev/null +++ b/lib/internal/options.js @@ -0,0 +1,18 @@ +'use strict'; + +const { getOptions } = internalBinding('options'); +const { options, aliases } = getOptions(); + +function getOptionValue(option) { + const result = options.get(option); + if (!result) { + return undefined; + } + return result.value; +} + +module.exports = { + options, + aliases, + getOptionValue +}; diff --git a/lib/internal/print_help.js b/lib/internal/print_help.js index 8acc9271b19188..d9ab3c1ad84e90 100644 --- a/lib/internal/print_help.js +++ b/lib/internal/print_help.js @@ -1,5 +1,6 @@ 'use strict'; -const { getOptions, types } = internalBinding('options'); + +const { types } = internalBinding('options'); const typeLookup = []; for (const key of Object.keys(types)) @@ -132,7 +133,7 @@ function format({ options, aliases = new Map(), firstColumn, secondColumn }) { } function print(stream) { - const { options, aliases } = getOptions(); + const { options, aliases } = require('internal/options'); // Use 75 % of the available width, and at least 70 characters. const width = Math.max(70, (stream.columns || 0) * 0.75); diff --git a/lib/internal/priority_queue.js b/lib/internal/priority_queue.js index 2f1db934b43cc8..ec8bbaea412761 100644 --- a/lib/internal/priority_queue.js +++ b/lib/internal/priority_queue.js @@ -28,25 +28,13 @@ module.exports = class PriorityQueue { insert(value) { const heap = this[kHeap]; - let pos = ++this[kSize]; + const pos = ++this[kSize]; + heap[pos] = value; if (heap.length === pos) heap.length *= 2; - const compare = this[kCompare]; - const setPosition = this[kSetPosition]; - while (pos > 1) { - const parent = heap[pos / 2 | 0]; - if (compare(parent, value) <= 0) - break; - heap[pos] = parent; - if (setPosition !== undefined) - setPosition(parent, pos); - pos = pos / 2 | 0; - } - heap[pos] = value; - if (setPosition !== undefined) - setPosition(value, pos); + this.percolateUp(pos); } peek() { @@ -77,18 +65,37 @@ module.exports = class PriorityQueue { setPosition(item, pos); } + percolateUp(pos) { + const heap = this[kHeap]; + const compare = this[kCompare]; + const setPosition = this[kSetPosition]; + const item = heap[pos]; + + while (pos > 1) { + const parent = heap[pos / 2 | 0]; + if (compare(parent, item) <= 0) + break; + heap[pos] = parent; + if (setPosition !== undefined) + setPosition(parent, pos); + pos = pos / 2 | 0; + } + heap[pos] = item; + if (setPosition !== undefined) + setPosition(item, pos); + } + removeAt(pos) { const heap = this[kHeap]; const size = --this[kSize]; heap[pos] = heap[size + 1]; heap[size + 1] = undefined; - if (size > 0) { - // If not removing the last item, update the shifted item's position. - if (pos <= size && this[kSetPosition] !== undefined) - this[kSetPosition](heap[pos], pos); - - this.percolateDown(1); + if (size > 0 && pos <= size) { + if (pos > 1 && this[kCompare](heap[pos / 2 | 0], heap[pos]) > 0) + this.percolateUp(pos); + else + this.percolateDown(pos); } } diff --git a/lib/internal/process/coverage.js b/lib/internal/process/coverage.js index df45285baaee02..9c9b2b47119ea7 100644 --- a/lib/internal/process/coverage.js +++ b/lib/internal/process/coverage.js @@ -1,23 +1,19 @@ 'use strict'; -const path = require('path'); -const { mkdirSync, writeFileSync } = require('fs'); -const hasInspector = process.config.variables.v8_enable_inspector === 1; -let inspector = null; -if (hasInspector) inspector = require('inspector'); - -let session; +let coverageConnection = null; +let coverageDirectory; function writeCoverage() { - if (!session) { + if (!coverageConnection && coverageDirectory) { return; } + const { join } = require('path'); + const { mkdirSync, writeFileSync } = require('fs'); const { threadId } = require('internal/worker'); const filename = `coverage-${process.pid}-${Date.now()}-${threadId}.json`; try { - // TODO(bcoe): switch to mkdirp once #22302 is addressed. - mkdirSync(process.env.NODE_V8_COVERAGE); + mkdirSync(coverageDirectory, { recursive: true }); } catch (err) { if (err.code !== 'EEXIST') { console.error(err); @@ -25,41 +21,73 @@ function writeCoverage() { } } - const target = path.join(process.env.NODE_V8_COVERAGE, filename); - + const target = join(coverageDirectory, filename); try { - session.post('Profiler.takePreciseCoverage', (err, coverageInfo) => { - if (err) return console.error(err); - try { - writeFileSync(target, JSON.stringify(coverageInfo)); - } catch (err) { - console.error(err); - } - }); + disableAllAsyncHooks(); + let msg; + coverageConnection._coverageCallback = function(_msg) { + msg = _msg; + }; + coverageConnection.dispatch(JSON.stringify({ + id: 3, + method: 'Profiler.takePreciseCoverage' + })); + const coverageInfo = JSON.parse(msg).result; + writeFileSync(target, JSON.stringify(coverageInfo)); } catch (err) { console.error(err); } finally { - session.disconnect(); - session = null; + coverageConnection.disconnect(); + coverageConnection = null; } } +function disableAllAsyncHooks() { + const { getHookArrays } = require('internal/async_hooks'); + const [hooks_array] = getHookArrays(); + hooks_array.forEach((hook) => { hook.disable(); }); +} + exports.writeCoverage = writeCoverage; function setup() { - if (!hasInspector) { - console.warn('coverage currently only supported in main thread'); + const { Connection } = process.binding('inspector'); + if (!Connection) { + console.warn('inspector not enabled'); return; } - session = new inspector.Session(); - session.connect(); - session.post('Profiler.enable'); - session.post('Profiler.startPreciseCoverage', { callCount: true, - detailed: true }); + coverageConnection = new Connection((res) => { + if (coverageConnection._coverageCallback) { + coverageConnection._coverageCallback(res); + } + }); + coverageConnection.dispatch(JSON.stringify({ + id: 1, + method: 'Profiler.enable' + })); + coverageConnection.dispatch(JSON.stringify({ + id: 2, + method: 'Profiler.startPreciseCoverage', + params: { + callCount: true, + detailed: true + } + })); - const reallyReallyExit = process.reallyExit; + try { + const { resolve } = require('path'); + coverageDirectory = process.env.NODE_V8_COVERAGE = + resolve(process.env.NODE_V8_COVERAGE); + } catch (err) { + console.error(err); + } +} +exports.setup = setup; + +function setupExitHooks() { + const reallyReallyExit = process.reallyExit; process.reallyExit = function(code) { writeCoverage(); reallyReallyExit(code); @@ -68,4 +96,4 @@ function setup() { process.on('exit', writeCoverage); } -exports.setup = setup; +exports.setupExitHooks = setupExitHooks; diff --git a/lib/internal/process/esm_loader.js b/lib/internal/process/esm_loader.js index 72d39a69600d88..f81053a1c3c3ad 100644 --- a/lib/internal/process/esm_loader.js +++ b/lib/internal/process/esm_loader.js @@ -48,7 +48,7 @@ exports.ESMLoader = undefined; exports.setup = function() { let ESMLoader = new Loader(); const loaderPromise = (async () => { - const userLoader = internalBinding('options').getOptions('--loader'); + const userLoader = require('internal/options').getOptionValue('--loader'); if (userLoader) { const hooks = await ESMLoader.import( userLoader, pathToFileURL(`${process.cwd()}/`).href); diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js index 3a0383cc3cea70..ce9d2545e45022 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -82,7 +82,25 @@ function emitErrorNT(self, err) { self.emit('error', err); } +function errorOrDestroy(stream, err) { + // We have tests that rely on errors being emitted + // in the same tick, so changing this is semver major. + // For now when you opt-in to autoDestroy we allow + // the error to be emitted nextTick. In a future + // semver major update we should change the default to this. + + const rState = stream._readableState; + const wState = stream._writableState; + + if ((rState && rState.autoDestroy) || (wState && wState.autoDestroy)) + stream.destroy(err); + else + stream.emit('error', err); +} + + module.exports = { destroy, - undestroy + undestroy, + errorOrDestroy }; diff --git a/lib/internal/timers.js b/lib/internal/timers.js index 5c96b38ee6e00d..3bfa1f03775fe1 100644 --- a/lib/internal/timers.js +++ b/lib/internal/timers.js @@ -32,8 +32,7 @@ module.exports = { kRefed, initAsyncResource, setUnrefTimeout, - validateTimerDuration, - getLibuvNow: internalBinding('timers').getLibuvNow, + validateTimerDuration }; var timers; diff --git a/lib/internal/url.js b/lib/internal/url.js index 518c745b41e760..693f082aed6137 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -245,7 +245,14 @@ function onParseError(flags, input) { // Reused by URL constructor and URL#href setter. function parse(url, input, base) { const base_context = base ? base[context] : undefined; - url[context] = new URLContext(); + // In the URL#href setter + if (!url[context]) { + Object.defineProperty(url, context, { + enumerable: false, + configurable: false, + value: new URLContext() + }); + } _parse(input.trim(), -1, base_context, undefined, onParseComplete.bind(url), onParseError); } @@ -1437,7 +1444,11 @@ function toPathIfFileURL(fileURLOrPath) { } function NativeURL(ctx) { - this[context] = ctx; + Object.defineProperty(this, context, { + enumerable: false, + configurable: false, + value: ctx + }); } NativeURL.prototype = URL.prototype; diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 4cff372b330ec1..bd35c4bb3b80f4 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -297,9 +297,8 @@ function strEscape(str) { last = i + 1; } } - if (last === 0) { - result = str; - } else if (last !== i) { + + if (last !== i) { result += str.slice(last); } return addQuotes(result, singleQuote); @@ -400,6 +399,10 @@ function getKeys(value, showHidden) { return keys; } +function getCtxStyle(constructor, tag) { + return constructor || tag || 'Object'; +} + function formatProxy(ctx, proxy, recurseTimes) { if (recurseTimes != null) { if (recurseTimes < 0) @@ -741,7 +744,7 @@ function formatRaw(ctx, value, recurseTimes) { if (recurseTimes != null) { if (recurseTimes < 0) - return ctx.stylize(`[${constructor || tag || 'Object'}]`, 'special'); + return ctx.stylize(`[${getCtxStyle(constructor, tag)}]`, 'special'); recurseTimes -= 1; } @@ -793,7 +796,7 @@ function handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl) { ctx.seen.pop(); ctx.indentationLvl = indentationLvl; return ctx.stylize( - `[${constructor || tag || 'Object'}: Inspection interrupted ` + + `[${getCtxStyle(constructor, tag)}: Inspection interrupted ` + 'prematurely. Maximum call stack size exceeded.]', 'special' ); diff --git a/lib/internal/util/inspector.js b/lib/internal/util/inspector.js index 634d3302333584..7d22fdc80eccc1 100644 --- a/lib/internal/util/inspector.js +++ b/lib/internal/util/inspector.js @@ -15,7 +15,7 @@ function sendInspectorCommand(cb, onError) { } finally { session.disconnect(); } - } catch (e) { + } catch { return onError(); } } diff --git a/lib/internal/v8_prof_polyfill.js b/lib/internal/v8_prof_polyfill.js index 43ccc0e5d8bfac..59e1b8947eed55 100644 --- a/lib/internal/v8_prof_polyfill.js +++ b/lib/internal/v8_prof_polyfill.js @@ -140,7 +140,7 @@ function macCppfiltNm(out) { filtered = cp.spawnSync('c++filt', [ '-p' , '-i' ], { input: entries.join('\n') }).stdout.toString(); - } catch (e) { + } catch { return out; } diff --git a/lib/net.js b/lib/net.js index 33ce1f74eb2fba..9b139d28597b5c 100644 --- a/lib/net.js +++ b/lib/net.js @@ -264,9 +264,16 @@ function Socket(options) { const { fd } = options; let err; + // createHandle will throw ERR_INVALID_FD_TYPE if `fd` is not + // a valid `PIPE` or `TCP` descriptor this._handle = createHandle(fd, false); err = this._handle.open(fd); + + // While difficult to fabricate, in some architectures + // `open` may return an error code for valid file descriptors + // which cannot be opened. This is difficult to test as most + // un-openable fds will throw on `createHandle` if (err) throw errnoException(err, 'open'); @@ -336,40 +343,31 @@ Socket.prototype._unrefTimer = function _unrefTimer() { }; -function shutdownSocket(self, callback) { - var req = new ShutdownWrap(); - req.oncomplete = afterShutdown; - req.handle = self._handle; - req.callback = callback; - return self._handle.shutdown(req); -} - // the user has called .end(), and all the bytes have been // sent out to the other side. Socket.prototype._final = function(cb) { // If still connecting - defer handling `_final` until 'connect' will happen - if (this.connecting) { + if (this.pending) { debug('_final: not yet connected'); return this.once('connect', () => this._final(cb)); } + // TODO(addaleax): This should not be necessary. if (!this.readable || this._readableState.ended) { - debug('_final: ended, destroy', this._readableState); cb(); return this.destroy(); } - debug('_final: not ended, call shutdown()'); + if (!this._handle) + return cb(); - // otherwise, just shutdown, or destroy() if not possible - if (!this._handle || !this._handle.shutdown) { - cb(); - return this.destroy(); - } + debug('_final: not ended, call shutdown()'); - var err = defaultTriggerAsyncIdScope( - this[async_id_symbol], shutdownSocket, this, cb - ); + var req = new ShutdownWrap(); + req.oncomplete = afterShutdown; + req.handle = this._handle; + req.callback = cb; + var err = this._handle.shutdown(req); if (err) return this.destroy(errnoException(err, 'shutdown')); @@ -388,7 +386,7 @@ function afterShutdown(status, handle) { if (self.destroyed) return; - if (self._readableState.ended) { + if (!self.readable || self._readableState.ended) { debug('readableState ended, destroying'); self.destroy(); } @@ -494,6 +492,13 @@ Object.defineProperty(Socket.prototype, '_connecting', { } }); +Object.defineProperty(Socket.prototype, 'pending', { + get() { + return !this._handle || this.connecting; + }, + configurable: true +}); + Object.defineProperty(Socket.prototype, 'readyState', { get: function() { @@ -785,6 +790,8 @@ function afterWrite(status, handle, err) { // callback may come after call to destroy. if (self.destroyed) { debug('afterWrite destroyed'); + if (this.callback) + this.callback(null); return; } @@ -839,12 +846,9 @@ function internalConnect( if (addressType === 4) { localAddress = localAddress || '0.0.0.0'; err = self._handle.bind(localAddress, localPort); - } else if (addressType === 6) { + } else { // addressType === 6 localAddress = localAddress || '::'; err = self._handle.bind6(localAddress, localPort); - } else { - self.destroy(new ERR_INVALID_ADDRESS_FAMILY(addressType)); - return; } debug('binding to localAddress: %s and localPort: %d (addressType: %d)', localAddress, localPort, addressType); @@ -1435,6 +1439,13 @@ Server.prototype.listen = function(...args) { backlog = options.backlog || backlogFromArgs; listenInCluster(this, pipeName, -1, -1, backlog, undefined, options.exclusive); + + if (!this._handle) { + // Failed and an error shall be emitted in the next tick. + // Therefore, we directly return. + return this; + } + let mode = 0; if (options.readableAll === true) mode |= PipeConstants.UV_READABLE; diff --git a/lib/os.js b/lib/os.js index 797201c4b5e732..2c806908eeac98 100644 --- a/lib/os.js +++ b/lib/os.js @@ -21,7 +21,7 @@ 'use strict'; -const { pushValToArrayMax, safeGetenv } = internalBinding('util'); +const { safeGetenv } = internalBinding('util'); const constants = internalBinding('constants').os; const { deprecate } = require('internal/util'); const isWindows = process.platform === 'win32'; @@ -82,31 +82,29 @@ const getNetworkInterfacesDepMsg = 'os.getNetworkInterfaces is deprecated. Use os.networkInterfaces instead.'; const avgValues = new Float64Array(3); -const cpuValues = new Float64Array(6 * pushValToArrayMax); function loadavg() { getLoadAvg(avgValues); return [avgValues[0], avgValues[1], avgValues[2]]; } -function addCPUInfo() { - for (var i = 0, c = 0; i < arguments.length; ++i, c += 6) { - this[this.length] = { - model: arguments[i], - speed: cpuValues[c], +function cpus() { + const data = getCPUs(); + const result = []; + for (var i = 0; i < data.length; i += 7) { + result.push({ + model: data[i], + speed: data[i + 1], times: { - user: cpuValues[c + 1], - nice: cpuValues[c + 2], - sys: cpuValues[c + 3], - idle: cpuValues[c + 4], - irq: cpuValues[c + 5] + user: data[i + 2], + nice: data[i + 3], + sys: data[i + 4], + idle: data[i + 5], + irq: data[i + 6] } - }; + }); } -} - -function cpus() { - return getCPUs(addCPUInfo, cpuValues, []); + return result; } function arch() { diff --git a/lib/path.js b/lib/path.js index c8d92f14af04de..798682ca0f1a6b 100644 --- a/lib/path.js +++ b/lib/path.js @@ -1073,16 +1073,13 @@ const posix = { resolve: function resolve() { var resolvedPath = ''; var resolvedAbsolute = false; - var cwd; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { var path; if (i >= 0) path = arguments[i]; else { - if (cwd === undefined) - cwd = process.cwd(); - path = cwd; + path = process.cwd(); } assertPath(path); diff --git a/lib/querystring.js b/lib/querystring.js index 3a4d09bf78e848..7e4ab5e894120d 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -448,7 +448,7 @@ function parse(qs, sep, eq, options) { function decodeStr(s, decoder) { try { return decoder(s); - } catch (e) { + } catch { return QueryString.unescape(s, true); } } diff --git a/lib/readline.js b/lib/readline.js index 4eeefb227ca746..f22d84f1a0df77 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -217,6 +217,7 @@ function Interface(input, output, completer, terminal) { // Current line this.line = ''; + this.multiline = ''; this._setRawMode(true); this.terminal = true; @@ -327,6 +328,7 @@ Interface.prototype._addHistory = function() { if (dupIndex !== -1) this.history.splice(dupIndex, 1); } + this.multiline += this.line; this.history.unshift(this.line); // Only store so many @@ -337,6 +339,29 @@ Interface.prototype._addHistory = function() { return this.history[0]; }; +// Called when a multiline is seen by the repl +Interface.prototype.undoHistory = function() { + if (this.terminal) { + this.history.shift(); + } +}; + +// If it's a multiline code, then add history +// accordingly. +Interface.prototype.multilineHistory = function() { + // check if we got a multiline code + if (this.multiline !== '' && this.terminal) { + const dupIndex = this.history.indexOf(this.multiline); + if (dupIndex !== -1) this.history.splice(dupIndex, 1); + // Remove the last entered line as multiline + // already contains them. + this.history.shift(); + this.history.unshift(this.multiline); + } + + // clear the multiline buffer + this.multiline = ''; +}; Interface.prototype._refreshLine = function() { // line length diff --git a/lib/repl.js b/lib/repl.js index dafbd20d500383..3391a94396db11 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -70,7 +70,7 @@ const { ERR_SCRIPT_EXECUTION_INTERRUPTED } = require('internal/errors').codes; const { sendInspectorCommand } = require('internal/util/inspector'); -const experimentalREPLAwait = internalBinding('options').getOptions( +const experimentalREPLAwait = require('internal/options').getOptionValue( '--experimental-repl-await' ); const { isRecoverableError } = require('internal/repl/recoverable'); @@ -108,7 +108,7 @@ const kContextId = Symbol('contextId'); try { // Hack for require.resolve("./relative") to work properly. module.filename = path.resolve('repl'); -} catch (e) { +} catch { // path.resolve('repl') fails when the current working directory has been // deleted. Fall back to the directory name of the (absolute) executable // path. It's not really correct but what are the alternatives? @@ -126,8 +126,9 @@ function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } -// Can overridden with custom print functions, such as `probe` or `eyes.js`. -// This is the default "writer" value if none is passed in the REPL options. +// This is the default "writer" value, if none is passed in the REPL options, +// and it can be overridden by custom print functions, such as `probe` or +// `eyes.js`. const writer = exports.writer = (obj) => util.inspect(obj, writer.options); writer.options = Object.assign({}, util.inspect.defaultOptions, @@ -376,18 +377,8 @@ function REPLServer(prompt, } promise.then((result) => { - // Remove prioritized SIGINT listener if it was not called. - // TODO(TimothyGu): Use Promise.prototype.finally when it becomes - // available. - prioritizedSigintQueue.delete(sigintListener); - finishExecution(undefined, result); - unpause(); }, (err) => { - // Remove prioritized SIGINT listener if it was not called. - prioritizedSigintQueue.delete(sigintListener); - - unpause(); if (err && process.domain) { debug('not recoverable, send to domain'); process.domain.emit('error', err); @@ -395,6 +386,10 @@ function REPLServer(prompt, return; } finishExecution(err); + }).finally(() => { + // Remove prioritized SIGINT listener if it was not called. + prioritizedSigintQueue.delete(sigintListener); + unpause(); }); } } @@ -779,6 +774,7 @@ exports.start = function(prompt, REPLServer.prototype.clearBufferedCommand = function clearBufferedCommand() { this[kBufferedCommandSymbol] = ''; + REPLServer.super_.prototype.multilineHistory.call(this); }; REPLServer.prototype.close = function close() { @@ -893,6 +889,7 @@ REPLServer.prototype.displayPrompt = function(preserveCursor) { const len = this.lines.level.length ? this.lines.level.length - 1 : 0; const levelInd = '..'.repeat(len); prompt += levelInd + ' '; + REPLServer.super_.prototype.undoHistory.call(this); } // Do not overwrite `_initialPrompt` here @@ -1054,7 +1051,7 @@ function complete(line, callback) { dir = path.resolve(paths[i], subdir); try { files = fs.readdirSync(dir); - } catch (e) { + } catch { continue; } for (f = 0; f < files.length; f++) { @@ -1068,14 +1065,14 @@ function complete(line, callback) { abs = path.resolve(dir, name); try { isDirectory = fs.statSync(abs).isDirectory(); - } catch (e) { + } catch { continue; } if (isDirectory) { group.push(subdir + name + '/'); try { subfiles = fs.readdirSync(abs); - } catch (e) { + } catch { continue; } for (s = 0; s < subfiles.length; s++) { @@ -1157,13 +1154,13 @@ function complete(line, callback) { }); } } else { - const evalExpr = `try { ${expr} } catch (e) {}`; + const evalExpr = `try { ${expr} } catch {}`; this.eval(evalExpr, this.context, 'repl', (e, obj) => { if (obj != null) { if (typeof obj === 'object' || typeof obj === 'function') { try { memberGroups.push(filteredOwnPropertyNames.call(this, obj)); - } catch (ex) { + } catch { // Probably a Proxy object without `getOwnPropertyNames` trap. // We simply ignore it here, as we don't want to break the // autocompletion. Fixes the bug @@ -1188,7 +1185,7 @@ function complete(line, callback) { break; } } - } catch (e) {} + } catch {} } if (memberGroups.length) { @@ -1461,7 +1458,7 @@ function defineDefaultCommands(repl) { try { fs.writeFileSync(file, this.lines.join('\n') + '\n'); this.outputStream.write('Session saved to: ' + file + '\n'); - } catch (e) { + } catch { this.outputStream.write('Failed to save: ' + file + '\n'); } this.displayPrompt(); diff --git a/lib/stream.js b/lib/stream.js index f7e47df73145be..dfe61aaf09d95d 100644 --- a/lib/stream.js +++ b/lib/stream.js @@ -54,7 +54,7 @@ try { // readable-stream. Stream._isUint8Array = process.binding('util').isUint8Array; } -} catch (e) { +} catch (e) { // eslint-disable-line no-unused-vars } if (!Stream._isUint8Array) { @@ -74,7 +74,7 @@ if (version[0] === 0 && version[1] < 12) { chunk.byteOffset, chunk.byteLength); }; - } catch (e) { + } catch (e) { // eslint-disable-line no-unused-vars } if (!Stream._uint8ArrayToBuffer) { diff --git a/lib/vm.js b/lib/vm.js index 1bb948fa550531..0cccd284bfc758 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -32,7 +32,7 @@ const { ERR_INVALID_ARG_TYPE, ERR_VM_MODULE_NOT_MODULE, } = require('internal/errors').codes; -const { isModuleNamespaceObject, isUint8Array } = require('util').types; +const { isModuleNamespaceObject, isArrayBufferView } = require('util').types; const { validateInt32, validateUint32 } = require('internal/validators'); const kParsingContext = Symbol('script parsing context'); @@ -64,9 +64,12 @@ class Script extends ContextifyScript { } validateInt32(lineOffset, 'options.lineOffset'); validateInt32(columnOffset, 'options.columnOffset'); - if (cachedData !== undefined && !isUint8Array(cachedData)) { - throw new ERR_INVALID_ARG_TYPE('options.cachedData', - ['Buffer', 'Uint8Array'], cachedData); + if (cachedData !== undefined && !isArrayBufferView(cachedData)) { + throw new ERR_INVALID_ARG_TYPE( + 'options.cachedData', + ['Buffer', 'TypedArray', 'DataView'], + cachedData + ); } if (typeof produceCachedData !== 'boolean') { throw new ERR_INVALID_ARG_TYPE('options.produceCachedData', 'boolean', @@ -346,10 +349,10 @@ function compileFunction(code, params, options = {}) { } validateUint32(columnOffset, 'options.columnOffset'); validateUint32(lineOffset, 'options.lineOffset'); - if (cachedData !== undefined && !isUint8Array(cachedData)) { + if (cachedData !== undefined && !isArrayBufferView(cachedData)) { throw new ERR_INVALID_ARG_TYPE( 'options.cachedData', - 'Uint8Array', + ['Buffer', 'TypedArray', 'DataView'], cachedData ); } @@ -415,7 +418,7 @@ module.exports = { compileFunction, }; -if (internalBinding('options').getOptions('--experimental-vm-modules')) { +if (require('internal/options').getOptionValue('--experimental-vm-modules')) { const { SourceTextModule } = require('internal/vm/source_text_module'); module.exports.SourceTextModule = SourceTextModule; } diff --git a/lib/zlib.js b/lib/zlib.js index c833afff14f4b9..559f6c2d5f3056 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -350,8 +350,7 @@ Object.defineProperty(Zlib.prototype, 'bytesRead', { // `params()` function should not happen while a write is currently in progress // on the threadpool. function paramsAfterFlushCallback(level, strategy, callback) { - if (!this._handle) - assert(false, 'zlib binding closed'); + assert(this._handle, 'zlib binding closed'); this._handle.params(level, strategy); if (!this._hadError) { this._level = level; @@ -507,8 +506,8 @@ function processChunkSync(self, chunk, flushFlag) { else buffers.push(out); nread += out.byteLength; - } else if (have < 0) { - assert(false, 'have should not go down'); + } else { + assert(have === 0, 'have should not go down'); } // exhausted the output buffer, or used all the input create a new one. @@ -545,8 +544,7 @@ function processChunkSync(self, chunk, flushFlag) { function processChunk(self, chunk, flushFlag, cb) { var handle = self._handle; - if (!handle) - assert(false, 'zlib binding closed'); + assert(handle, 'zlib binding closed'); handle.buffer = chunk; handle.cb = cb; @@ -593,8 +591,8 @@ function processCallback() { var out = self._outBuffer.slice(self._outOffset, self._outOffset + have); self._outOffset += have; self.push(out); - } else if (have < 0) { - assert(false, 'have should not go down'); + } else { + assert(have === 0, 'have should not go down'); } if (self.destroyed) { diff --git a/node.gyp b/node.gyp index 13c21e33ee88d4..5b68281de45790 100644 --- a/node.gyp +++ b/node.gyp @@ -12,6 +12,7 @@ 'force_dynamic_crt%': 0, 'node_module_version%': '', 'node_shared_zlib%': 'false', + 'node_experimental_http_parser%': 'false', 'node_shared_http_parser%': 'false', 'node_shared_cares%': 'false', 'node_shared_libuv%': 'false', @@ -133,6 +134,7 @@ 'lib/internal/modules/esm/translators.js', 'lib/internal/safe_globals.js', 'lib/internal/net.js', + 'lib/internal/options.js', 'lib/internal/print_help.js', 'lib/internal/priority_queue.js', 'lib/internal/process/esm_loader.js', @@ -336,15 +338,13 @@ 'src/module_wrap.cc', 'src/node.cc', 'src/node_api.cc', - 'src/node_api.h', - 'src/node_api_types.h', 'src/node_buffer.cc', 'src/node_config.cc', 'src/node_constants.cc', 'src/node_contextify.cc', 'src/node_domain.cc', 'src/node_encoding.cc', - 'src/node_errors.h', + 'src/node_errors.cc', 'src/node_file.cc', 'src/node_http2.cc', 'src/node_http_parser.cc', @@ -402,10 +402,13 @@ 'src/js_stream.h', 'src/module_wrap.h', 'src/node.h', + 'src/node_api.h', + 'src/node_api_types.h', 'src/node_buffer.h', 'src/node_code_cache.h', 'src/node_constants.h', 'src/node_contextify.h', + 'src/node_errors.h', 'src/node_file.h', 'src/node_http2.h', 'src/node_http2_state.h', @@ -413,6 +416,8 @@ 'src/node_javascript.h', 'src/node_messaging.h', 'src/node_mutex.h', + 'src/node_native_module.h', + 'src/node_native_module.cc', 'src/node_options.h', 'src/node_options-inl.h', 'src/node_perf.h', diff --git a/node.gypi b/node.gypi index 0b27e6ad2c1ac4..fdf81b7465b906 100644 --- a/node.gypi +++ b/node.gypi @@ -32,9 +32,13 @@ '-Wendif-labels', '-W', '-Wno-unused-parameter', + '-Werror=undefined-inline', ], }, 'conditions': [ + ['clang==1', { + 'cflags': [ '-Werror=undefined-inline', ] + }], [ 'node_shared=="false"', { 'msvs_settings': { 'VCManifestTool': { @@ -159,9 +163,14 @@ ], }], - [ 'node_shared_http_parser=="false"', { - 'dependencies': [ 'deps/http_parser/http_parser.gyp:http_parser' ], - }], + [ 'node_experimental_http_parser=="true"', { + 'defines': [ 'NODE_EXPERIMENTAL_HTTP' ], + 'dependencies': [ 'deps/llhttp/llhttp.gyp:llhttp' ], + }, { + 'conditions': [ [ 'node_shared_http_parser=="false"', { + 'dependencies': [ 'deps/http_parser/http_parser.gyp:http_parser' ], + } ] ], + } ], [ 'node_shared_cares=="false"', { 'dependencies': [ 'deps/cares/cares.gyp:cares' ], diff --git a/src/async_wrap.cc b/src/async_wrap.cc index 29bd64f2c5e3fe..f3bd59d4ac30bc 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -21,9 +21,10 @@ #include "async_wrap-inl.h" #include "env-inl.h" +#include "node_errors.h" #include "node_internals.h" -#include "util-inl.h" #include "tracing/traced_value.h" +#include "util-inl.h" #include "v8.h" #include "v8-profiler.h" @@ -357,9 +358,15 @@ void AsyncWrap::WeakCallback(const v8::WeakCallbackInfo& info) { HandleScope scope(info.GetIsolate()); std::unique_ptr p{info.GetParameter()}; - Local prop_bag = PersistentToLocal(info.GetIsolate(), p->propBag); + Local prop_bag = PersistentToLocal::Default(info.GetIsolate(), + p->propBag); + Local val; + + if (!prop_bag->Get(p->env->context(), p->env->destroyed_string()) + .ToLocal(&val)) { + return; + } - Local val = prop_bag->Get(p->env->destroyed_string()); if (val->IsFalse()) { AsyncWrap::EmitDestroy(p->env, p->asyncId); } @@ -699,6 +706,8 @@ MaybeLocal AsyncWrap::MakeCallback(const Local cb, async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { + // Environment::GetCurrent() allocates a Local<> handle. + v8::HandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); if (env == nullptr) return -1; return env->execution_async_id(); @@ -706,6 +715,8 @@ async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) { + // Environment::GetCurrent() allocates a Local<> handle. + v8::HandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); if (env == nullptr) return -1; return env->trigger_async_id(); @@ -716,6 +727,7 @@ async_context EmitAsyncInit(Isolate* isolate, Local resource, const char* name, async_id trigger_async_id) { + v8::HandleScope handle_scope(isolate); Local type = String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized) .ToLocalChecked(); @@ -726,6 +738,7 @@ async_context EmitAsyncInit(Isolate* isolate, Local resource, v8::Local name, async_id trigger_async_id) { + v8::HandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); CHECK_NOT_NULL(env); @@ -746,6 +759,8 @@ async_context EmitAsyncInit(Isolate* isolate, } void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) { + // Environment::GetCurrent() allocates a Local<> handle. + v8::HandleScope handle_scope(isolate); AsyncWrap::EmitDestroy( Environment::GetCurrent(isolate), asyncContext.async_id); } diff --git a/src/base_object-inl.h b/src/base_object-inl.h index 8c8fa1699c3069..0b8fbb8520c283 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -62,7 +62,7 @@ Persistent& BaseObject::persistent() { v8::Local BaseObject::object() const { - return PersistentToLocal(env_->isolate(), persistent_handle_); + return PersistentToLocal::Default(env_->isolate(), persistent_handle_); } v8::Local BaseObject::object(v8::Isolate* isolate) const { diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index d6a8d3854ad6ff..c40b855b9939ca 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -26,12 +26,6 @@ using v8::PromiseRejectMessage; using v8::String; using v8::Value; -void SetupProcessObject(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - CHECK(args[0]->IsFunction()); - env->set_push_values_to_array_function(args[0].As()); -} - void RunMicrotasks(const FunctionCallbackInfo& args) { args.GetIsolate()->RunMicrotasks(); } @@ -142,7 +136,6 @@ void SetupPromises(const FunctionCallbackInfo& args) { void SetupBootstrapObject(Environment* env, Local bootstrapper) { BOOTSTRAP_METHOD(_setupTraceCategoryState, SetupTraceCategoryState); - BOOTSTRAP_METHOD(_setupProcessObject, SetupProcessObject); BOOTSTRAP_METHOD(_setupNextTick, SetupNextTick); BOOTSTRAP_METHOD(_setupPromises, SetupPromises); BOOTSTRAP_METHOD(_chdir, Chdir); diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index d9f6485edfb507..8cc2339872b553 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -1848,7 +1848,7 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { continue; Local s = OneByteString(env->isolate(), ip); - results->Set(n, s); + results->Set(env->context(), n, s).FromJust(); n++; } }; @@ -2049,10 +2049,12 @@ void GetServers(const FunctionCallbackInfo& args) { CHECK_EQ(err, 0); Local ret = Array::New(env->isolate(), 2); - ret->Set(0, OneByteString(env->isolate(), ip)); - ret->Set(1, Integer::New(env->isolate(), cur->udp_port)); + ret->Set(env->context(), 0, OneByteString(env->isolate(), ip)).FromJust(); + ret->Set(env->context(), + 1, + Integer::New(env->isolate(), cur->udp_port)).FromJust(); - server_array->Set(i, ret); + server_array->Set(env->context(), i, ret).FromJust(); } ares_free_data(servers); @@ -2175,16 +2177,19 @@ void Initialize(Local target, env->SetMethod(target, "strerror", StrError); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"), - Integer::New(env->isolate(), AF_INET)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"), - Integer::New(env->isolate(), AF_INET6)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_UNSPEC"), - Integer::New(env->isolate(), AF_UNSPEC)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_ADDRCONFIG"), - Integer::New(env->isolate(), AI_ADDRCONFIG)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_V4MAPPED"), - Integer::New(env->isolate(), AI_V4MAPPED)); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"), + Integer::New(env->isolate(), AF_INET)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"), + Integer::New(env->isolate(), AF_INET6)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), + "AF_UNSPEC"), + Integer::New(env->isolate(), AF_UNSPEC)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), + "AI_ADDRCONFIG"), + Integer::New(env->isolate(), AI_ADDRCONFIG)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), + "AI_V4MAPPED"), + Integer::New(env->isolate(), AI_V4MAPPED)).FromJust(); Local aiw = BaseObject::MakeLazilyInitializedJSTemplate(env); @@ -2192,7 +2197,9 @@ void Initialize(Local target, Local addrInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"); aiw->SetClassName(addrInfoWrapString); - target->Set(addrInfoWrapString, aiw->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + addrInfoWrapString, + aiw->GetFunction(context).ToLocalChecked()).FromJust(); Local niw = BaseObject::MakeLazilyInitializedJSTemplate(env); @@ -2200,7 +2207,9 @@ void Initialize(Local target, Local nameInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"); niw->SetClassName(nameInfoWrapString); - target->Set(nameInfoWrapString, niw->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + nameInfoWrapString, + niw->GetFunction(context).ToLocalChecked()).FromJust(); Local qrw = BaseObject::MakeLazilyInitializedJSTemplate(env); @@ -2208,7 +2217,9 @@ void Initialize(Local target, Local queryWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"); qrw->SetClassName(queryWrapString); - target->Set(queryWrapString, qrw->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + queryWrapString, + qrw->GetFunction(context).ToLocalChecked()).FromJust(); Local channel_wrap = env->NewFunctionTemplate(ChannelWrap::New); @@ -2235,8 +2246,8 @@ void Initialize(Local target, Local channelWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "ChannelWrap"); channel_wrap->SetClassName(channelWrapString); - target->Set(channelWrapString, - channel_wrap->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), channelWrapString, + channel_wrap->GetFunction(context).ToLocalChecked()).FromJust(); } } // anonymous namespace diff --git a/src/debug_utils.cc b/src/debug_utils.cc index a24c51de39cf2d..77ea219bfc880a 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -100,35 +100,104 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext { USE(SymInitialize(current_process_, nullptr, true)); } - ~Win32SymbolDebuggingContext() { + ~Win32SymbolDebuggingContext() override { USE(SymCleanup(current_process_)); } - SymbolInfo LookupSymbol(void* address) override { - // Ref: https://msdn.microsoft.com/en-en/library/windows/desktop/ms680578(v=vs.85).aspx - char info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; - SYMBOL_INFO* info = reinterpret_cast(info_buf); - char demangled[MAX_SYM_NAME]; + using NameAndDisplacement = std::pair; + NameAndDisplacement WrappedSymFromAddr(DWORD64 dwAddress) const { + // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address + // Patches: + // Use `fprintf(stderr, ` instead of `printf` + // `sym.filename = pSymbol->Name` on success + // `current_process_` instead of `hProcess. + DWORD64 dwDisplacement = 0; + // Patch: made into arg - DWORD64 dwAddress = SOME_ADDRESS; + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + const auto pSymbol = reinterpret_cast(buffer); + + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + if (SymFromAddr(current_process_, dwAddress, &dwDisplacement, pSymbol)) { + // SymFromAddr returned success + return NameAndDisplacement(pSymbol->Name, dwDisplacement); + } else { + // SymFromAddr failed + const DWORD error = GetLastError(); // "eat" the error anyway +#ifdef DEBUG + fprintf(stderr, "SymFromAddr returned error : %lu\n", error); +#endif + } + // End MSDN code - info->MaxNameLen = MAX_SYM_NAME; - info->SizeOfStruct = sizeof(SYMBOL_INFO); + return NameAndDisplacement(); + } - SymbolInfo ret; - const bool have_info = SymFromAddr(current_process_, - reinterpret_cast(address), - nullptr, - info); - if (have_info && strlen(info->Name) == 0) { - if (UnDecorateSymbolName(info->Name, - demangled, - sizeof(demangled), - UNDNAME_COMPLETE)) { - ret.name = demangled; - } else { - ret.name = info->Name; - } + SymbolInfo WrappedGetLine(DWORD64 dwAddress) const { + SymbolInfo sym{}; + + // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address + // Patches: + // Use `fprintf(stderr, ` instead of `printf`. + // Assign values to `sym` on success. + // `current_process_` instead of `hProcess. + + // Patch: made into arg - DWORD64 dwAddress; + DWORD dwDisplacement; + IMAGEHLP_LINE64 line; + + SymSetOptions(SYMOPT_LOAD_LINES); + + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + // Patch: made into arg - dwAddress = 0x1000000; + + if (SymGetLineFromAddr64(current_process_, dwAddress, + &dwDisplacement, &line)) { + // SymGetLineFromAddr64 returned success + sym.filename = line.FileName; + sym.line = line.LineNumber; + } else { + // SymGetLineFromAddr64 failed + const DWORD error = GetLastError(); // "eat" the error anyway +#ifdef DEBUG + fprintf(stderr, "SymGetLineFromAddr64 returned error : %lu\n", error); +#endif + } + // End MSDN code + + return sym; + } + + // Fills the SymbolInfo::name of the io/out argument `sym` + std::string WrappedUnDecorateSymbolName(const char* name) const { + // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-undecorated-symbol-names + // Patches: + // Use `fprintf(stderr, ` instead of `printf`. + // return `szUndName` instead of `printf` on success + char szUndName[MAX_SYM_NAME]; + if (UnDecorateSymbolName(name, szUndName, sizeof(szUndName), + UNDNAME_COMPLETE)) { + // UnDecorateSymbolName returned success + return szUndName; + } else { + // UnDecorateSymbolName failed + const DWORD error = GetLastError(); // "eat" the error anyway +#ifdef DEBUG + fprintf(stderr, "UnDecorateSymbolName returned error %lu\n", error); +#endif } + return nullptr; + } + SymbolInfo LookupSymbol(void* address) override { + const DWORD64 dw_address = reinterpret_cast(address); + SymbolInfo ret = WrappedGetLine(dw_address); + std::tie(ret.name, ret.dis) = WrappedSymFromAddr(dw_address); + if (!ret.name.empty()) { + ret.name = WrappedUnDecorateSymbolName(ret.name.c_str()); + } return ret; } @@ -145,6 +214,13 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext { return CaptureStackBackTrace(0, count, frames, nullptr); } + Win32SymbolDebuggingContext(const Win32SymbolDebuggingContext&) = delete; + Win32SymbolDebuggingContext(Win32SymbolDebuggingContext&&) = delete; + Win32SymbolDebuggingContext operator=(const Win32SymbolDebuggingContext&) + = delete; + Win32SymbolDebuggingContext operator=(Win32SymbolDebuggingContext&&) + = delete; + private: HANDLE current_process_; }; @@ -158,13 +234,18 @@ NativeSymbolDebuggingContext::New() { #endif // __POSIX__ std::string NativeSymbolDebuggingContext::SymbolInfo::Display() const { - std::string ret = name; + std::ostringstream oss; + oss << name; + if (dis != 0) { + oss << "+" << dis; + } if (!filename.empty()) { - ret += " ["; - ret += filename; - ret += ']'; + oss << " [" << filename << ']'; + } + if (line != 0) { + oss << ":L" << line; } - return ret; + return oss.str(); } void DumpBacktrace(FILE* fp) { @@ -173,8 +254,8 @@ void DumpBacktrace(FILE* fp) { const int size = sym_ctx->GetStackTrace(frames, arraysize(frames)); for (int i = 1; i < size; i += 1) { void* frame = frames[i]; - fprintf(fp, "%2d: %p %s\n", - i, frame, sym_ctx->LookupSymbol(frame).Display().c_str()); + NativeSymbolDebuggingContext::SymbolInfo s = sym_ctx->LookupSymbol(frame); + fprintf(fp, "%2d: %p %s\n", i, frame, s.Display().c_str()); } } diff --git a/src/debug_utils.h b/src/debug_utils.h index 2fd9e7dab7f8f4..c6c8e03b51fd64 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -6,6 +6,7 @@ #include "async_wrap.h" #include "env.h" #include +#include // Use FORCE_INLINE on functions that have a debug-category-enabled check first // and then ideally only a single function call following it, to maintain @@ -93,14 +94,25 @@ class NativeSymbolDebuggingContext { public: std::string name; std::string filename; + size_t line = 0; + size_t dis = 0; std::string Display() const; }; + NativeSymbolDebuggingContext() = default; virtual ~NativeSymbolDebuggingContext() {} - virtual SymbolInfo LookupSymbol(void* address) { return { "", "" }; } + + virtual SymbolInfo LookupSymbol(void* address) { return {}; } virtual bool IsMapped(void* address) { return false; } virtual int GetStackTrace(void** frames, int count) { return 0; } + + NativeSymbolDebuggingContext(const NativeSymbolDebuggingContext&) = delete; + NativeSymbolDebuggingContext(NativeSymbolDebuggingContext&&) = delete; + NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&) + = delete; + NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&) + = delete; }; // Variant of `uv_loop_close` that tries to be as helpful as possible diff --git a/src/env-inl.h b/src/env-inl.h index da8ca222b3361f..70a8e052258531 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -740,7 +740,7 @@ inline void Environment::SetMethod(v8::Local that, const v8::NewStringType type = v8::NewStringType::kInternalized; v8::Local name_string = v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); - that->Set(name_string, function); + that->Set(context, name_string, function).FromJust(); function->SetName(name_string); // NODE_SET_METHOD() compatibility. } @@ -760,7 +760,7 @@ inline void Environment::SetMethodNoSideEffect(v8::Local that, const v8::NewStringType type = v8::NewStringType::kInternalized; v8::Local name_string = v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); - that->Set(name_string, function); + that->Set(context, name_string, function).FromJust(); function->SetName(name_string); // NODE_SET_METHOD() compatibility. } @@ -899,7 +899,7 @@ void Environment::ForEachBaseObject(T&& iterator) { #define V(PropertyName, TypeName) \ inline v8::Local Environment::PropertyName() const { \ - return StrongPersistentToLocal(PropertyName ## _); \ + return PersistentToLocal::Strong(PropertyName ## _); \ } \ inline void Environment::set_ ## PropertyName(v8::Local value) { \ PropertyName ## _.Reset(isolate(), value); \ diff --git a/src/env.cc b/src/env.cc index 9d8fd967a406a6..727d13b98b13a1 100644 --- a/src/env.cc +++ b/src/env.cc @@ -746,7 +746,9 @@ void CollectExceptionInfo(Environment* env, const char* message, const char* path, const char* dest) { - obj->Set(env->errno_string(), v8::Integer::New(env->isolate(), errorno)); + obj->Set(env->context(), + env->errno_string(), + v8::Integer::New(env->isolate(), errorno)).FromJust(); obj->Set(env->context(), env->code_string(), OneByteString(env->isolate(), err_string)).FromJust(); diff --git a/src/env.h b/src/env.h index eed9b8cd172d67..d58990567b0b0d 100644 --- a/src/env.h +++ b/src/env.h @@ -82,12 +82,6 @@ struct PackageConfig { }; } // namespace loader -// The number of items passed to push_values_to_array_function has diminishing -// returns around 8. This should be used at all call sites using said function. -#ifndef NODE_PUSH_VAL_TO_ARRAY_MAX -#define NODE_PUSH_VAL_TO_ARRAY_MAX 8 -#endif - // PER_ISOLATE_* macros: We have a lot of per-isolate properties // and adding and maintaining their getters and setters by hand would be // difficult so let's make the preprocessor generate them for us. @@ -121,248 +115,258 @@ struct PackageConfig { // Strings are per-isolate primitives but Environment proxies them // for the sake of convenience. Strings should be ASCII-only. -#define PER_ISOLATE_STRING_PROPERTIES(V) \ - V(address_string, "address") \ - V(aliases_string, "aliases") \ - V(args_string, "args") \ - V(async_ids_stack_string, "async_ids_stack") \ - V(buffer_string, "buffer") \ - V(bytes_parsed_string, "bytesParsed") \ - V(bytes_read_string, "bytesRead") \ - V(bytes_written_string, "bytesWritten") \ - V(cached_data_string, "cachedData") \ - V(cached_data_produced_string, "cachedDataProduced") \ - V(cached_data_rejected_string, "cachedDataRejected") \ - V(change_string, "change") \ - V(channel_string, "channel") \ - V(chunks_sent_since_last_write_string, "chunksSentSinceLastWrite") \ - V(constants_string, "constants") \ - V(oncertcb_string, "oncertcb") \ - V(code_string, "code") \ - V(cwd_string, "cwd") \ - V(dest_string, "dest") \ - V(destroyed_string, "destroyed") \ - V(detached_string, "detached") \ - V(dns_a_string, "A") \ - V(dns_aaaa_string, "AAAA") \ - V(dns_cname_string, "CNAME") \ - V(dns_mx_string, "MX") \ - V(dns_naptr_string, "NAPTR") \ - V(dns_ns_string, "NS") \ - V(dns_ptr_string, "PTR") \ - V(dns_soa_string, "SOA") \ - V(dns_srv_string, "SRV") \ - V(dns_txt_string, "TXT") \ - V(duration_string, "duration") \ - V(emit_warning_string, "emitWarning") \ - V(exchange_string, "exchange") \ - V(encoding_string, "encoding") \ - V(entries_string, "entries") \ - V(entry_type_string, "entryType") \ - V(env_pairs_string, "envPairs") \ - V(env_var_settings_string, "envVarSettings") \ - V(errno_string, "errno") \ - V(error_string, "error") \ - V(exit_code_string, "exitCode") \ - V(expire_string, "expire") \ - V(exponent_string, "exponent") \ - V(exports_string, "exports") \ - V(ext_key_usage_string, "ext_key_usage") \ - V(external_stream_string, "_externalStream") \ - V(family_string, "family") \ - V(fatal_exception_string, "_fatalException") \ - V(fd_string, "fd") \ - V(file_string, "file") \ - V(fingerprint_string, "fingerprint") \ - V(fingerprint256_string, "fingerprint256") \ - V(flags_string, "flags") \ - V(fragment_string, "fragment") \ - V(get_data_clone_error_string, "_getDataCloneError") \ - V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \ - V(gid_string, "gid") \ - V(handle_string, "handle") \ - V(help_text_string, "helpText") \ - V(homedir_string, "homedir") \ - V(host_string, "host") \ - V(hostmaster_string, "hostmaster") \ - V(ignore_string, "ignore") \ - V(infoaccess_string, "infoAccess") \ - V(inherit_string, "inherit") \ - V(input_string, "input") \ - V(internal_string, "internal") \ - V(ipv4_string, "IPv4") \ - V(ipv6_string, "IPv6") \ - V(isclosing_string, "isClosing") \ - V(issuer_string, "issuer") \ - V(issuercert_string, "issuerCertificate") \ - V(kill_signal_string, "killSignal") \ - V(kind_string, "kind") \ - V(mac_string, "mac") \ - V(main_string, "main") \ - V(max_buffer_string, "maxBuffer") \ - V(message_string, "message") \ - V(message_port_string, "messagePort") \ - V(message_port_constructor_string, "MessagePort") \ - V(minttl_string, "minttl") \ - V(modulus_string, "modulus") \ - V(name_string, "name") \ - V(netmask_string, "netmask") \ - V(nsname_string, "nsname") \ - V(ocsp_request_string, "OCSPRequest") \ - V(onaltsvc_string, "onaltsvc") \ - V(onchange_string, "onchange") \ - V(onclienthello_string, "onclienthello") \ - V(oncomplete_string, "oncomplete") \ - V(onconnection_string, "onconnection") \ - V(ondone_string, "ondone") \ - V(onerror_string, "onerror") \ - V(onexit_string, "onexit") \ - V(onframeerror_string, "onframeerror") \ - V(ongetpadding_string, "ongetpadding") \ - V(onhandshakedone_string, "onhandshakedone") \ - V(onhandshakestart_string, "onhandshakestart") \ - V(onheaders_string, "onheaders") \ - V(onmessage_string, "onmessage") \ - V(onnewsession_string, "onnewsession") \ - V(onocspresponse_string, "onocspresponse") \ - V(ongoawaydata_string, "ongoawaydata") \ - V(onorigin_string, "onorigin") \ - V(onpriority_string, "onpriority") \ - V(onread_string, "onread") \ - V(onreadstart_string, "onreadstart") \ - V(onreadstop_string, "onreadstop") \ - V(onping_string, "onping") \ - V(onsettings_string, "onsettings") \ - V(onshutdown_string, "onshutdown") \ - V(onsignal_string, "onsignal") \ - V(onstreamclose_string, "onstreamclose") \ - V(ontrailers_string, "ontrailers") \ - V(onunpipe_string, "onunpipe") \ - V(onwrite_string, "onwrite") \ - V(openssl_error_stack, "opensslErrorStack") \ - V(options_string, "options") \ - V(output_string, "output") \ - V(order_string, "order") \ - V(parse_error_string, "Parse Error") \ - V(password_string, "password") \ - V(path_string, "path") \ - V(pending_handle_string, "pendingHandle") \ - V(pid_string, "pid") \ - V(pipe_string, "pipe") \ - V(pipe_target_string, "pipeTarget") \ - V(pipe_source_string, "pipeSource") \ - V(port_string, "port") \ - V(port1_string, "port1") \ - V(port2_string, "port2") \ - V(preference_string, "preference") \ - V(priority_string, "priority") \ - V(promise_string, "promise") \ - V(pubkey_string, "pubkey") \ - V(query_string, "query") \ - V(raw_string, "raw") \ - V(read_host_object_string, "_readHostObject") \ - V(readable_string, "readable") \ - V(refresh_string, "refresh") \ - V(regexp_string, "regexp") \ - V(rename_string, "rename") \ - V(replacement_string, "replacement") \ - V(retry_string, "retry") \ - V(scheme_string, "scheme") \ - V(serial_string, "serial") \ - V(scopeid_string, "scopeid") \ - V(serial_number_string, "serialNumber") \ - V(service_string, "service") \ - V(servername_string, "servername") \ - V(session_id_string, "sessionId") \ - V(shell_string, "shell") \ - V(signal_string, "signal") \ - V(sink_string, "sink") \ - V(size_string, "size") \ - V(sni_context_err_string, "Invalid SNI context") \ - V(sni_context_string, "sni_context") \ - V(source_string, "source") \ - V(stack_string, "stack") \ - V(start_time_string, "startTime") \ - V(status_string, "status") \ - V(stdio_string, "stdio") \ - V(subject_string, "subject") \ - V(subjectaltname_string, "subjectaltname") \ - V(syscall_string, "syscall") \ - V(thread_id_string, "threadId") \ - V(ticketkeycallback_string, "onticketkeycallback") \ - V(timeout_string, "timeout") \ - V(tls_ticket_string, "tlsTicket") \ - V(ttl_string, "ttl") \ - V(type_string, "type") \ - V(uid_string, "uid") \ - V(unknown_string, "") \ - V(url_string, "url") \ - V(username_string, "username") \ - V(valid_from_string, "valid_from") \ - V(valid_to_string, "valid_to") \ - V(value_string, "value") \ - V(verify_error_string, "verifyError") \ - V(version_string, "version") \ - V(weight_string, "weight") \ - V(windows_hide_string, "windowsHide") \ - V(windows_verbatim_arguments_string, "windowsVerbatimArguments") \ - V(wrap_string, "wrap") \ - V(writable_string, "writable") \ - V(write_host_object_string, "_writeHostObject") \ - V(write_queue_size_string, "writeQueueSize") \ - V(x_forwarded_string, "x-forwarded-for") \ +#define PER_ISOLATE_STRING_PROPERTIES(V) \ + V(address_string, "address") \ + V(aliases_string, "aliases") \ + V(args_string, "args") \ + V(async_ids_stack_string, "async_ids_stack") \ + V(buffer_string, "buffer") \ + V(bytes_parsed_string, "bytesParsed") \ + V(bytes_read_string, "bytesRead") \ + V(bytes_written_string, "bytesWritten") \ + V(cached_data_string, "cachedData") \ + V(cached_data_produced_string, "cachedDataProduced") \ + V(cached_data_rejected_string, "cachedDataRejected") \ + V(change_string, "change") \ + V(channel_string, "channel") \ + V(chunks_sent_since_last_write_string, "chunksSentSinceLastWrite") \ + V(constants_string, "constants") \ + V(oncertcb_string, "oncertcb") \ + V(code_string, "code") \ + V(cwd_string, "cwd") \ + V(dest_string, "dest") \ + V(destroyed_string, "destroyed") \ + V(detached_string, "detached") \ + V(dns_a_string, "A") \ + V(dns_aaaa_string, "AAAA") \ + V(dns_cname_string, "CNAME") \ + V(dns_mx_string, "MX") \ + V(dns_naptr_string, "NAPTR") \ + V(dns_ns_string, "NS") \ + V(dns_ptr_string, "PTR") \ + V(dns_soa_string, "SOA") \ + V(dns_srv_string, "SRV") \ + V(dns_txt_string, "TXT") \ + V(duration_string, "duration") \ + V(emit_warning_string, "emitWarning") \ + V(exchange_string, "exchange") \ + V(encoding_string, "encoding") \ + V(entries_string, "entries") \ + V(entry_type_string, "entryType") \ + V(env_pairs_string, "envPairs") \ + V(env_var_settings_string, "envVarSettings") \ + V(errno_string, "errno") \ + V(error_string, "error") \ + V(exit_code_string, "exitCode") \ + V(expire_string, "expire") \ + V(exponent_string, "exponent") \ + V(exports_string, "exports") \ + V(ext_key_usage_string, "ext_key_usage") \ + V(external_stream_string, "_externalStream") \ + V(family_string, "family") \ + V(fatal_exception_string, "_fatalException") \ + V(fd_string, "fd") \ + V(file_string, "file") \ + V(fingerprint_string, "fingerprint") \ + V(fingerprint256_string, "fingerprint256") \ + V(flags_string, "flags") \ + V(fragment_string, "fragment") \ + V(get_data_clone_error_string, "_getDataCloneError") \ + V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \ + V(gid_string, "gid") \ + V(handle_string, "handle") \ + V(help_text_string, "helpText") \ + V(homedir_string, "homedir") \ + V(host_string, "host") \ + V(hostmaster_string, "hostmaster") \ + V(ignore_string, "ignore") \ + V(infoaccess_string, "infoAccess") \ + V(inherit_string, "inherit") \ + V(input_string, "input") \ + V(internal_string, "internal") \ + V(internal_binding_string, "internalBinding") \ + V(ipv4_string, "IPv4") \ + V(ipv6_string, "IPv6") \ + V(isclosing_string, "isClosing") \ + V(issuer_string, "issuer") \ + V(issuercert_string, "issuerCertificate") \ + V(kill_signal_string, "killSignal") \ + V(kind_string, "kind") \ + V(mac_string, "mac") \ + V(main_string, "main") \ + V(max_buffer_string, "maxBuffer") \ + V(message_string, "message") \ + V(message_port_string, "messagePort") \ + V(message_port_constructor_string, "MessagePort") \ + V(minttl_string, "minttl") \ + V(module_string, "module") \ + V(modulus_string, "modulus") \ + V(name_string, "name") \ + V(netmask_string, "netmask") \ + V(nsname_string, "nsname") \ + V(ocsp_request_string, "OCSPRequest") \ + V(onaltsvc_string, "onaltsvc") \ + V(onchange_string, "onchange") \ + V(onclienthello_string, "onclienthello") \ + V(oncomplete_string, "oncomplete") \ + V(onconnection_string, "onconnection") \ + V(ondone_string, "ondone") \ + V(onerror_string, "onerror") \ + V(onexit_string, "onexit") \ + V(onframeerror_string, "onframeerror") \ + V(ongetpadding_string, "ongetpadding") \ + V(onhandshakedone_string, "onhandshakedone") \ + V(onhandshakestart_string, "onhandshakestart") \ + V(onheaders_string, "onheaders") \ + V(onmessage_string, "onmessage") \ + V(onnewsession_string, "onnewsession") \ + V(onocspresponse_string, "onocspresponse") \ + V(ongoawaydata_string, "ongoawaydata") \ + V(onorigin_string, "onorigin") \ + V(onpriority_string, "onpriority") \ + V(onread_string, "onread") \ + V(onreadstart_string, "onreadstart") \ + V(onreadstop_string, "onreadstop") \ + V(onping_string, "onping") \ + V(onsettings_string, "onsettings") \ + V(onshutdown_string, "onshutdown") \ + V(onsignal_string, "onsignal") \ + V(onstreamclose_string, "onstreamclose") \ + V(ontrailers_string, "ontrailers") \ + V(onunpipe_string, "onunpipe") \ + V(onwrite_string, "onwrite") \ + V(openssl_error_stack, "opensslErrorStack") \ + V(options_string, "options") \ + V(output_string, "output") \ + V(order_string, "order") \ + V(parse_error_string, "Parse Error") \ + V(password_string, "password") \ + V(path_string, "path") \ + V(pending_handle_string, "pendingHandle") \ + V(pid_string, "pid") \ + V(pipe_string, "pipe") \ + V(pipe_target_string, "pipeTarget") \ + V(pipe_source_string, "pipeSource") \ + V(port_string, "port") \ + V(port1_string, "port1") \ + V(port2_string, "port2") \ + V(preference_string, "preference") \ + V(priority_string, "priority") \ + V(process_string, "process") \ + V(promise_string, "promise") \ + V(pubkey_string, "pubkey") \ + V(query_string, "query") \ + V(raw_string, "raw") \ + V(read_host_object_string, "_readHostObject") \ + V(readable_string, "readable") \ + V(reason_string, "reason") \ + V(refresh_string, "refresh") \ + V(regexp_string, "regexp") \ + V(rename_string, "rename") \ + V(replacement_string, "replacement") \ + V(require_string, "require") \ + V(retry_string, "retry") \ + V(scheme_string, "scheme") \ + V(serial_string, "serial") \ + V(scopeid_string, "scopeid") \ + V(serial_number_string, "serialNumber") \ + V(service_string, "service") \ + V(servername_string, "servername") \ + V(session_id_string, "sessionId") \ + V(shell_string, "shell") \ + V(signal_string, "signal") \ + V(sink_string, "sink") \ + V(size_string, "size") \ + V(sni_context_err_string, "Invalid SNI context") \ + V(sni_context_string, "sni_context") \ + V(source_string, "source") \ + V(stack_string, "stack") \ + V(start_time_string, "startTime") \ + V(status_string, "status") \ + V(stdio_string, "stdio") \ + V(subject_string, "subject") \ + V(subjectaltname_string, "subjectaltname") \ + V(syscall_string, "syscall") \ + V(thread_id_string, "threadId") \ + V(ticketkeycallback_string, "onticketkeycallback") \ + V(timeout_string, "timeout") \ + V(tls_ticket_string, "tlsTicket") \ + V(ttl_string, "ttl") \ + V(type_string, "type") \ + V(uid_string, "uid") \ + V(unknown_string, "") \ + V(url_string, "url") \ + V(username_string, "username") \ + V(valid_from_string, "valid_from") \ + V(valid_to_string, "valid_to") \ + V(value_string, "value") \ + V(verify_error_string, "verifyError") \ + V(version_string, "version") \ + V(weight_string, "weight") \ + V(windows_hide_string, "windowsHide") \ + V(windows_verbatim_arguments_string, "windowsVerbatimArguments") \ + V(wrap_string, "wrap") \ + V(writable_string, "writable") \ + V(write_host_object_string, "_writeHostObject") \ + V(write_queue_size_string, "writeQueueSize") \ + V(x_forwarded_string, "x-forwarded-for") \ V(zero_return_string, "ZERO_RETURN") -#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ - V(as_external, v8::External) \ - V(async_hooks_after_function, v8::Function) \ - V(async_hooks_before_function, v8::Function) \ - V(async_hooks_binding, v8::Object) \ - V(async_hooks_destroy_function, v8::Function) \ - V(async_hooks_init_function, v8::Function) \ - V(async_hooks_promise_resolve_function, v8::Function) \ - V(async_wrap_object_ctor_template, v8::FunctionTemplate) \ - V(async_wrap_ctor_template, v8::FunctionTemplate) \ - V(buffer_prototype_object, v8::Object) \ - V(context, v8::Context) \ - V(domain_callback, v8::Function) \ - V(domexception_function, v8::Function) \ - V(fdclose_constructor_template, v8::ObjectTemplate) \ - V(fd_constructor_template, v8::ObjectTemplate) \ - V(filehandlereadwrap_template, v8::ObjectTemplate) \ - V(fsreqpromise_constructor_template, v8::ObjectTemplate) \ - V(fs_use_promises_symbol, v8::Symbol) \ - V(handle_wrap_ctor_template, v8::FunctionTemplate) \ - V(host_import_module_dynamically_callback, v8::Function) \ - V(host_initialize_import_meta_object_callback, v8::Function) \ - V(http2ping_constructor_template, v8::ObjectTemplate) \ - V(http2settings_constructor_template, v8::ObjectTemplate) \ - V(http2stream_constructor_template, v8::ObjectTemplate) \ - V(immediate_callback_function, v8::Function) \ - V(inspector_console_api_object, v8::Object) \ - V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \ - V(message_port, v8::Object) \ - V(message_port_constructor_template, v8::FunctionTemplate) \ - V(pipe_constructor_template, v8::FunctionTemplate) \ - V(performance_entry_callback, v8::Function) \ - V(performance_entry_template, v8::Function) \ - V(process_object, v8::Object) \ - V(promise_handler_function, v8::Function) \ - V(promise_wrap_template, v8::ObjectTemplate) \ - V(push_values_to_array_function, v8::Function) \ - V(sab_lifetimepartner_constructor_template, v8::FunctionTemplate) \ - V(script_context_constructor_template, v8::FunctionTemplate) \ - V(script_data_constructor_function, v8::Function) \ - V(secure_context_constructor_template, v8::FunctionTemplate) \ - V(shutdown_wrap_template, v8::ObjectTemplate) \ - V(tcp_constructor_template, v8::FunctionTemplate) \ - V(tick_callback_function, v8::Function) \ - V(timers_callback_function, v8::Function) \ - V(tls_wrap_constructor_function, v8::Function) \ - V(trace_category_state_function, v8::Function) \ - V(tty_constructor_template, v8::FunctionTemplate) \ - V(udp_constructor_function, v8::Function) \ - V(url_constructor_function, v8::Function) \ +#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \ + V(as_external, v8::External) \ + V(async_hooks_after_function, v8::Function) \ + V(async_hooks_before_function, v8::Function) \ + V(async_hooks_binding, v8::Object) \ + V(async_hooks_destroy_function, v8::Function) \ + V(async_hooks_init_function, v8::Function) \ + V(async_hooks_promise_resolve_function, v8::Function) \ + V(async_wrap_object_ctor_template, v8::FunctionTemplate) \ + V(async_wrap_ctor_template, v8::FunctionTemplate) \ + V(buffer_prototype_object, v8::Object) \ + V(context, v8::Context) \ + V(domain_callback, v8::Function) \ + V(domexception_function, v8::Function) \ + V(fdclose_constructor_template, v8::ObjectTemplate) \ + V(fd_constructor_template, v8::ObjectTemplate) \ + V(filehandlereadwrap_template, v8::ObjectTemplate) \ + V(fsreqpromise_constructor_template, v8::ObjectTemplate) \ + V(fs_use_promises_symbol, v8::Symbol) \ + V(handle_wrap_ctor_template, v8::FunctionTemplate) \ + V(host_import_module_dynamically_callback, v8::Function) \ + V(host_initialize_import_meta_object_callback, v8::Function) \ + V(http2ping_constructor_template, v8::ObjectTemplate) \ + V(http2settings_constructor_template, v8::ObjectTemplate) \ + V(http2stream_constructor_template, v8::ObjectTemplate) \ + V(immediate_callback_function, v8::Function) \ + V(inspector_console_api_object, v8::Object) \ + V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \ + V(message_port, v8::Object) \ + V(message_port_constructor_template, v8::FunctionTemplate) \ + V(native_modules_code_cache, v8::Object) \ + V(native_modules_code_cache_hash, v8::Object) \ + V(native_modules_source, v8::Object) \ + V(native_modules_source_hash, v8::Object) \ + V(native_modules_with_cache, v8::Set) \ + V(native_modules_without_cache, v8::Set) \ + V(pipe_constructor_template, v8::FunctionTemplate) \ + V(performance_entry_callback, v8::Function) \ + V(performance_entry_template, v8::Function) \ + V(process_object, v8::Object) \ + V(promise_handler_function, v8::Function) \ + V(promise_wrap_template, v8::ObjectTemplate) \ + V(sab_lifetimepartner_constructor_template, v8::FunctionTemplate) \ + V(script_context_constructor_template, v8::FunctionTemplate) \ + V(script_data_constructor_function, v8::Function) \ + V(secure_context_constructor_template, v8::FunctionTemplate) \ + V(shutdown_wrap_template, v8::ObjectTemplate) \ + V(tcp_constructor_template, v8::FunctionTemplate) \ + V(tick_callback_function, v8::Function) \ + V(timers_callback_function, v8::Function) \ + V(tls_wrap_constructor_function, v8::Function) \ + V(trace_category_state_function, v8::Function) \ + V(tty_constructor_template, v8::FunctionTemplate) \ + V(udp_constructor_function, v8::Function) \ + V(url_constructor_function, v8::Function) \ V(write_wrap_template, v8::ObjectTemplate) class Environment; diff --git a/src/exceptions.cc b/src/exceptions.cc index 98c87603dd9be3..7bbee45467ff35 100644 --- a/src/exceptions.cc +++ b/src/exceptions.cc @@ -51,15 +51,19 @@ Local ErrnoException(Isolate* isolate, e = Exception::Error(cons); Local obj = e.As(); - obj->Set(env->errno_string(), Integer::New(isolate, errorno)); - obj->Set(env->code_string(), estring); + obj->Set(env->context(), + env->errno_string(), + Integer::New(isolate, errorno)).FromJust(); + obj->Set(env->context(), env->code_string(), estring).FromJust(); if (path_string.IsEmpty() == false) { - obj->Set(env->path_string(), path_string); + obj->Set(env->context(), env->path_string(), path_string).FromJust(); } if (syscall != nullptr) { - obj->Set(env->syscall_string(), OneByteString(isolate, syscall)); + obj->Set(env->context(), + env->syscall_string(), + OneByteString(isolate, syscall)).FromJust(); } return e; @@ -132,13 +136,15 @@ Local UVException(Isolate* isolate, Exception::Error(js_msg)->ToObject(isolate->GetCurrentContext()) .ToLocalChecked(); - e->Set(env->errno_string(), Integer::New(isolate, errorno)); - e->Set(env->code_string(), js_code); - e->Set(env->syscall_string(), js_syscall); + e->Set(env->context(), + env->errno_string(), + Integer::New(isolate, errorno)).FromJust(); + e->Set(env->context(), env->code_string(), js_code).FromJust(); + e->Set(env->context(), env->syscall_string(), js_syscall).FromJust(); if (!js_path.IsEmpty()) - e->Set(env->path_string(), js_path); + e->Set(env->context(), env->path_string(), js_path).FromJust(); if (!js_dest.IsEmpty()) - e->Set(env->dest_string(), js_dest); + e->Set(env->context(), env->dest_string(), js_dest).FromJust(); return e; } diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index 739794665b2cfe..057445776a5255 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -119,7 +119,9 @@ void FSEventWrap::Initialize(Local target, Local(), static_cast(ReadOnly | DontDelete | v8::DontEnum)); - target->Set(fsevent_string, t->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + fsevent_string, + t->GetFunction(context).ToLocalChecked()).FromJust(); } diff --git a/src/heap_utils.cc b/src/heap_utils.cc index 72ad33c99a1e80..d1e3fad0980280 100644 --- a/src/heap_utils.cc +++ b/src/heap_utils.cc @@ -26,7 +26,7 @@ class JSGraphJSNode : public EmbedderGraph::Node { const char* Name() override { return ""; } size_t SizeInBytes() override { return 0; } bool IsEmbedderNode() override { return false; } - Local JSValue() { return StrongPersistentToLocal(persistent_); } + Local JSValue() { return PersistentToLocal::Strong(persistent_); } int IdentityHash() { Local v = JSValue(); diff --git a/src/http_parser_adaptor.h b/src/http_parser_adaptor.h new file mode 100644 index 00000000000000..6d786bd09519b5 --- /dev/null +++ b/src/http_parser_adaptor.h @@ -0,0 +1,24 @@ +#ifndef SRC_HTTP_PARSER_ADAPTOR_H_ +#define SRC_HTTP_PARSER_ADAPTOR_H_ + +#ifdef NODE_EXPERIMENTAL_HTTP +# include "llhttp.h" + +typedef llhttp_type_t parser_type_t; +typedef llhttp_errno_t parser_errno_t; +typedef llhttp_settings_t parser_settings_t; +typedef llhttp_t parser_t; + +#else /* !NODE_EXPERIMENTAL_HTTP */ +# include "http_parser.h" + +typedef enum http_parser_type parser_type_t; +typedef enum http_errno parser_errno_t; +typedef http_parser_settings parser_settings_t; +typedef http_parser parser_t; + +#define HPE_USER HPE_UNKNOWN + +#endif /* NODE_EXPERIMENTAL_HTTP */ + +#endif /* SRC_HTTP_PARSER_ADAPTOR_H_ */ diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index ebb7b7d5bc3e72..e0ee24a7f0c215 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -1,12 +1,13 @@ #include "inspector_agent.h" -#include "inspector_io.h" #include "inspector/main_thread_interface.h" #include "inspector/node_string.h" #include "inspector/tracing_agent.h" #include "inspector/worker_agent.h" #include "inspector/worker_inspector.h" +#include "inspector_io.h" #include "node/inspector/protocol/Protocol.h" +#include "node_errors.h" #include "node_internals.h" #include "node_url.h" #include "v8-inspector.h" @@ -474,11 +475,9 @@ class NodeInspectorClient : public V8InspectorClient { bool prevent_shutdown) { events_dispatched_ = true; int session_id = next_session_id_++; - // TODO(addaleax): Revert back to using make_unique once we get issues - // with CI resolved (i.e. revert the patch that added this comment). - channels_[session_id].reset( - new ChannelImpl(env_, client_, getWorkerManager(), - std::move(delegate), prevent_shutdown)); + channels_[session_id] = + std::make_unique(env_, client_, getWorkerManager(), + std::move(delegate), prevent_shutdown); return session_id; } diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc index dc36359b5c927c..8c2d0a5a22da28 100644 --- a/src/inspector_socket.cc +++ b/src/inspector_socket.cc @@ -1,6 +1,6 @@ #include "inspector_socket.h" -#include "http_parser.h" +#include "http_parser_adaptor.h" #include "util-inl.h" #define NODE_WANT_INTERNALS 1 @@ -433,8 +433,13 @@ class HttpHandler : public ProtocolHandler { explicit HttpHandler(InspectorSocket* inspector, TcpHolder::Pointer tcp) : ProtocolHandler(inspector, std::move(tcp)), parsing_value_(false) { +#ifdef NODE_EXPERIMENTAL_HTTP + llhttp_init(&parser_, HTTP_REQUEST, &parser_settings); + llhttp_settings_init(&parser_settings); +#else /* !NODE_EXPERIMENTAL_HTTP */ http_parser_init(&parser_, HTTP_REQUEST); http_parser_settings_init(&parser_settings); +#endif /* NODE_EXPERIMENTAL_HTTP */ parser_settings.on_header_field = OnHeaderField; parser_settings.on_header_value = OnHeaderValue; parser_settings.on_message_complete = OnMessageComplete; @@ -478,9 +483,20 @@ class HttpHandler : public ProtocolHandler { } void OnData(std::vector* data) override { + parser_errno_t err; +#ifdef NODE_EXPERIMENTAL_HTTP + err = llhttp_execute(&parser_, data->data(), data->size()); + + if (err == HPE_PAUSED_UPGRADE) { + err = HPE_OK; + llhttp_resume_after_upgrade(&parser_); + } +#else /* !NODE_EXPERIMENTAL_HTTP */ http_parser_execute(&parser_, &parser_settings, data->data(), data->size()); + err = HTTP_PARSER_ERRNO(&parser_); +#endif /* NODE_EXPERIMENTAL_HTTP */ data->clear(); - if (parser_.http_errno != HPE_OK) { + if (err != HPE_OK) { CancelHandshake(); } // Event handling may delete *this @@ -517,14 +533,14 @@ class HttpHandler : public ProtocolHandler { handler->inspector()->SwitchProtocol(nullptr); } - static int OnHeaderValue(http_parser* parser, const char* at, size_t length) { + static int OnHeaderValue(parser_t* parser, const char* at, size_t length) { HttpHandler* handler = From(parser); handler->parsing_value_ = true; handler->headers_[handler->current_header_].append(at, length); return 0; } - static int OnHeaderField(http_parser* parser, const char* at, size_t length) { + static int OnHeaderField(parser_t* parser, const char* at, size_t length) { HttpHandler* handler = From(parser); if (handler->parsing_value_) { handler->parsing_value_ = false; @@ -534,17 +550,17 @@ class HttpHandler : public ProtocolHandler { return 0; } - static int OnPath(http_parser* parser, const char* at, size_t length) { + static int OnPath(parser_t* parser, const char* at, size_t length) { HttpHandler* handler = From(parser); handler->path_.append(at, length); return 0; } - static HttpHandler* From(http_parser* parser) { + static HttpHandler* From(parser_t* parser) { return node::ContainerOf(&HttpHandler::parser_, parser); } - static int OnMessageComplete(http_parser* parser) { + static int OnMessageComplete(parser_t* parser) { // Event needs to be fired after the parser is done. HttpHandler* handler = From(parser); handler->events_.push_back( @@ -581,8 +597,8 @@ class HttpHandler : public ProtocolHandler { } bool parsing_value_; - http_parser parser_; - http_parser_settings parser_settings; + parser_t parser_; + parser_settings_t parser_settings; std::vector events_; std::string current_header_; std::map headers_; diff --git a/src/js_stream.cc b/src/js_stream.cc index 99ea7d870b8afb..2d07b11b636ef9 100644 --- a/src/js_stream.cc +++ b/src/js_stream.cc @@ -118,7 +118,7 @@ int JSStream::DoWrite(WriteWrap* w, Local buf; for (size_t i = 0; i < count; i++) { buf = Buffer::Copy(env(), bufs[i].base, bufs[i].len).ToLocalChecked(); - bufs_arr->Set(i, buf); + bufs_arr->Set(env()->context(), i, buf).FromJust(); } Local argv[] = { @@ -210,7 +210,9 @@ void JSStream::Initialize(Local target, env->SetProtoMethod(t, "emitEOF", EmitEOF); StreamBase::AddMethods(env, t); - target->Set(jsStreamString, t->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + jsStreamString, + t->GetFunction(context).ToLocalChecked()).FromJust(); } } // namespace node diff --git a/src/large_pages/ld.implicit.script b/src/large_pages/ld.implicit.script index ad7ce1b2e2e5cf..7f12e4bd7df9e5 100644 --- a/src/large_pages/ld.implicit.script +++ b/src/large_pages/ld.implicit.script @@ -1,8 +1,10 @@ SECTIONS { - .lpstub : { *(.lpstub) } + .lpstub : { + *libc.a:*(.text .text.*) + *(.lpstub) + } } PROVIDE (__nodetext = .); PROVIDE (_nodetext = .); PROVIDE (nodetext = .); INSERT BEFORE .text; - diff --git a/src/memory_tracker.h b/src/memory_tracker.h index 17992792128809..11dd2be7af35c9 100644 --- a/src/memory_tracker.h +++ b/src/memory_tracker.h @@ -69,7 +69,7 @@ class NodeBIO; * // a BaseObject or an AsyncWrap class * bool IsRootNode() const override { return !wrapped_.IsWeak(); } * v8::Local WrappedObject() const override { - * return node::PersistentToLocal(wrapped_); + * return node::PersistentToLocal::Default(wrapped_); * } * private: * AnotherRetainerClass another_retainer_; diff --git a/src/module_wrap.cc b/src/module_wrap.cc index ebe84fd1ec569d..5443b2e07dc856 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -837,8 +837,8 @@ void ModuleWrap::Initialize(Local target, env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers", GetStaticDependencySpecifiers); - target->Set(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"), - tpl->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"), + tpl->GetFunction(context).ToLocalChecked()).FromJust(); env->SetMethod(target, "resolve", Resolve); env->SetMethod(target, "setImportModuleDynamicallyCallback", diff --git a/src/node.cc b/src/node.cc index a71ae26ef6ff0a..4c84f781707b01 100644 --- a/src/node.cc +++ b/src/node.cc @@ -21,14 +21,15 @@ #include "node_buffer.h" #include "node_constants.h" +#include "node_context_data.h" +#include "node_errors.h" +#include "node_internals.h" #include "node_javascript.h" -#include "node_code_cache.h" +#include "node_native_module.h" +#include "node_perf.h" #include "node_platform.h" -#include "node_version.h" -#include "node_internals.h" #include "node_revert.h" -#include "node_perf.h" -#include "node_context_data.h" +#include "node_version.h" #include "tracing/traced_value.h" #if HAVE_OPENSSL @@ -51,7 +52,11 @@ #include "async_wrap-inl.h" #include "env-inl.h" #include "handle_wrap.h" -#include "http_parser.h" +#ifdef NODE_EXPERIMENTAL_HTTP +# include "llhttp.h" +#else /* !NODE_EXPERIMENTAL_HTTP */ +# include "http_parser.h" +#endif /* NODE_EXPERIMENTAL_HTTP */ #include "nghttp2/nghttp2ver.h" #include "req_wrap-inl.h" #include "string_bytes.h" @@ -125,6 +130,7 @@ typedef int mode_t; namespace node { +using native_module::NativeModule; using options_parser::kAllowedInEnvironment; using options_parser::kDisallowedInEnvironment; using v8::Array; @@ -177,6 +183,22 @@ static node_module* modlist_internal; static node_module* modlist_linked; static node_module* modlist_addon; +#ifdef NODE_EXPERIMENTAL_HTTP +static const char llhttp_version[] = + NODE_STRINGIFY(LLHTTP_VERSION_MAJOR) + "." + NODE_STRINGIFY(LLHTTP_VERSION_MINOR) + "." + NODE_STRINGIFY(LLHTTP_VERSION_PATCH); +#else /* !NODE_EXPERIMENTAL_HTTP */ +static const char http_parser_version[] = + NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) + "." + NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) + "." + NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH); +#endif /* NODE_EXPERIMENTAL_HTTP */ + // Bit flag used to track security reverts (see node_revert.h) unsigned int reverted = 0; @@ -215,17 +237,15 @@ class NodeTraceStateObserver : auto trace_process = tracing::TracedValue::Create(); trace_process->BeginDictionary("versions"); - const char http_parser_version[] = - NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) - "." - NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) - "." - NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH); +#ifdef NODE_EXPERIMENTAL_HTTP + trace_process->SetString("llhttp", llhttp_version); +#else /* !NODE_EXPERIMENTAL_HTTP */ + trace_process->SetString("http_parser", http_parser_version); +#endif /* NODE_EXPERIMENTAL_HTTP */ const char node_napi_version[] = NODE_STRINGIFY(NAPI_VERSION); const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION); - trace_process->SetString("http_parser", http_parser_version); trace_process->SetString("node", NODE_VERSION_STRING); trace_process->SetString("v8", V8::GetVersion()); trace_process->SetString("uv", uv_version_string()); @@ -383,41 +403,6 @@ static struct { static const unsigned kMaxSignal = 32; #endif -void PrintErrorString(const char* format, ...) { - va_list ap; - va_start(ap, format); -#ifdef _WIN32 - HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); - - // Check if stderr is something other than a tty/console - if (stderr_handle == INVALID_HANDLE_VALUE || - stderr_handle == nullptr || - uv_guess_handle(_fileno(stderr)) != UV_TTY) { - vfprintf(stderr, format, ap); - va_end(ap); - return; - } - - // Fill in any placeholders - int n = _vscprintf(format, ap); - std::vector out(n + 1); - vsprintf(out.data(), format, ap); - - // Get required wide buffer size - n = MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, nullptr, 0); - - std::vector wbuf(n); - MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, wbuf.data(), n); - - // Don't include the null character in the output - CHECK_GT(n, 0); - WriteConsoleW(stderr_handle, wbuf.data(), n - 1, nullptr, nullptr); -#else - vfprintf(stderr, format, ap); -#endif - va_end(ap); -} - const char* signo_string(int signo) { #define SIGNO_CASE(e) case e: return #e; switch (signo) { @@ -701,7 +686,8 @@ MaybeLocal MakeCallback(Isolate* isolate, int argc, Local argv[], async_context asyncContext) { - Local callback_v = recv->Get(symbol); + Local callback_v = recv->Get(isolate->GetCurrentContext(), + symbol).ToLocalChecked(); if (callback_v.IsEmpty()) return Local(); if (!callback_v->IsFunction()) return Local(); Local callback = callback_v.As(); @@ -773,223 +759,6 @@ Local MakeCallback(Isolate* isolate, .FromMaybe(Local())); } -bool IsExceptionDecorated(Environment* env, Local er) { - if (!er.IsEmpty() && er->IsObject()) { - Local err_obj = er.As(); - auto maybe_value = - err_obj->GetPrivate(env->context(), env->decorated_private_symbol()); - Local decorated; - return maybe_value.ToLocal(&decorated) && decorated->IsTrue(); - } - return false; -} - -void AppendExceptionLine(Environment* env, - Local er, - Local message, - enum ErrorHandlingMode mode) { - if (message.IsEmpty()) - return; - - HandleScope scope(env->isolate()); - Local err_obj; - if (!er.IsEmpty() && er->IsObject()) { - err_obj = er.As(); - } - - // Print (filename):(line number): (message). - ScriptOrigin origin = message->GetScriptOrigin(); - node::Utf8Value filename(env->isolate(), message->GetScriptResourceName()); - const char* filename_string = *filename; - int linenum = message->GetLineNumber(env->context()).FromJust(); - // Print line of source code. - MaybeLocal source_line_maybe = message->GetSourceLine(env->context()); - node::Utf8Value sourceline(env->isolate(), - source_line_maybe.ToLocalChecked()); - const char* sourceline_string = *sourceline; - if (strstr(sourceline_string, "node-do-not-add-exception-line") != nullptr) - return; - - // Because of how node modules work, all scripts are wrapped with a - // "function (module, exports, __filename, ...) {" - // to provide script local variables. - // - // When reporting errors on the first line of a script, this wrapper - // function is leaked to the user. There used to be a hack here to - // truncate off the first 62 characters, but it caused numerous other - // problems when vm.runIn*Context() methods were used for non-module - // code. - // - // If we ever decide to re-instate such a hack, the following steps - // must be taken: - // - // 1. Pass a flag around to say "this code was wrapped" - // 2. Update the stack frame output so that it is also correct. - // - // It would probably be simpler to add a line rather than add some - // number of characters to the first line, since V8 truncates the - // sourceline to 78 characters, and we end up not providing very much - // useful debugging info to the user if we remove 62 characters. - - int script_start = - (linenum - origin.ResourceLineOffset()->Value()) == 1 ? - origin.ResourceColumnOffset()->Value() : 0; - int start = message->GetStartColumn(env->context()).FromMaybe(0); - int end = message->GetEndColumn(env->context()).FromMaybe(0); - if (start >= script_start) { - CHECK_GE(end, start); - start -= script_start; - end -= script_start; - } - - char arrow[1024]; - int max_off = sizeof(arrow) - 2; - - int off = snprintf(arrow, - sizeof(arrow), - "%s:%i\n%s\n", - filename_string, - linenum, - sourceline_string); - CHECK_GE(off, 0); - if (off > max_off) { - off = max_off; - } - - // Print wavy underline (GetUnderline is deprecated). - for (int i = 0; i < start; i++) { - if (sourceline_string[i] == '\0' || off >= max_off) { - break; - } - CHECK_LT(off, max_off); - arrow[off++] = (sourceline_string[i] == '\t') ? '\t' : ' '; - } - for (int i = start; i < end; i++) { - if (sourceline_string[i] == '\0' || off >= max_off) { - break; - } - CHECK_LT(off, max_off); - arrow[off++] = '^'; - } - CHECK_LE(off, max_off); - arrow[off] = '\n'; - arrow[off + 1] = '\0'; - - Local arrow_str = String::NewFromUtf8(env->isolate(), arrow, - NewStringType::kNormal).ToLocalChecked(); - - const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty(); - // If allocating arrow_str failed, print it out. There's not much else to do. - // If it's not an error, but something needs to be printed out because - // it's a fatal exception, also print it out from here. - // Otherwise, the arrow property will be attached to the object and handled - // by the caller. - if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) { - if (env->printed_error()) - return; - Mutex::ScopedLock lock(process_mutex); - env->set_printed_error(true); - - uv_tty_reset_mode(); - PrintErrorString("\n%s", arrow); - return; - } - - CHECK(err_obj->SetPrivate( - env->context(), - env->arrow_message_private_symbol(), - arrow_str).FromMaybe(false)); -} - - -void ReportException(Environment* env, - Local er, - Local message) { - CHECK(!er.IsEmpty()); - HandleScope scope(env->isolate()); - - if (message.IsEmpty()) - message = Exception::CreateMessage(env->isolate(), er); - - AppendExceptionLine(env, er, message, FATAL_ERROR); - - Local trace_value; - Local arrow; - const bool decorated = IsExceptionDecorated(env, er); - - if (er->IsUndefined() || er->IsNull()) { - trace_value = Undefined(env->isolate()); - } else { - Local err_obj = er->ToObject(env->context()).ToLocalChecked(); - - trace_value = err_obj->Get(env->stack_string()); - arrow = - err_obj->GetPrivate( - env->context(), - env->arrow_message_private_symbol()).ToLocalChecked(); - } - - node::Utf8Value trace(env->isolate(), trace_value); - - // range errors have a trace member set to undefined - if (trace.length() > 0 && !trace_value->IsUndefined()) { - if (arrow.IsEmpty() || !arrow->IsString() || decorated) { - PrintErrorString("%s\n", *trace); - } else { - node::Utf8Value arrow_string(env->isolate(), arrow); - PrintErrorString("%s\n%s\n", *arrow_string, *trace); - } - } else { - // this really only happens for RangeErrors, since they're the only - // kind that won't have all this info in the trace, or when non-Error - // objects are thrown manually. - Local message; - Local name; - - if (er->IsObject()) { - Local err_obj = er.As(); - message = err_obj->Get(env->message_string()); - name = err_obj->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "name")); - } - - if (message.IsEmpty() || - message->IsUndefined() || - name.IsEmpty() || - name->IsUndefined()) { - // Not an error object. Just print as-is. - String::Utf8Value message(env->isolate(), er); - - PrintErrorString("%s\n", *message ? *message : - ""); - } else { - node::Utf8Value name_string(env->isolate(), name); - node::Utf8Value message_string(env->isolate(), message); - - if (arrow.IsEmpty() || !arrow->IsString() || decorated) { - PrintErrorString("%s: %s\n", *name_string, *message_string); - } else { - node::Utf8Value arrow_string(env->isolate(), arrow); - PrintErrorString("%s\n%s: %s\n", - *arrow_string, - *name_string, - *message_string); - } - } - } - - fflush(stderr); - -#if HAVE_INSPECTOR - env->inspector_agent()->FatalException(er, message); -#endif -} - - -static void ReportException(Environment* env, const TryCatch& try_catch) { - ReportException(env, try_catch.Exception(), try_catch.Message()); -} - - // Executes a str within the current v8 context. static MaybeLocal ExecuteString(Environment* env, Local source, @@ -1002,6 +771,7 @@ static MaybeLocal ExecuteString(Environment* env, try_catch.SetVerbose(false); ScriptOrigin origin(filename); + MaybeLocal + + diff --git a/test/fixtures/wpt/console/console-countReset-logging-manual.html b/test/fixtures/wpt/console/console-countReset-logging-manual.html new file mode 100644 index 00000000000000..7fe01f50edbfa1 --- /dev/null +++ b/test/fixtures/wpt/console/console-countReset-logging-manual.html @@ -0,0 +1,47 @@ + + + +Console Count Reset - Logging Manual Test + + + + + +

Open the console inside the developer tools. It should contain entries whose contents are:

+

default: 1

+

default: 1

+

default: 1

+

default: 1

+

default: 1

+

default: 1

+

default: 1

+

default: 1

+

a label: 1

+

a label: 1

+

[some warning message indicating that a count for label "b" does not exist]

+ + + + diff --git a/test/parallel/test-whatwg-console-is-a-namespace.js b/test/fixtures/wpt/console/console-is-a-namespace.any.js similarity index 58% rename from test/parallel/test-whatwg-console-is-a-namespace.js rename to test/fixtures/wpt/console/console-is-a-namespace.any.js index fb28e751a322af..a4aae7ffce8ac8 100644 --- a/test/parallel/test-whatwg-console-is-a-namespace.js +++ b/test/fixtures/wpt/console/console-is-a-namespace.any.js @@ -1,20 +1,4 @@ -'use strict'; - -require('../common'); - -const { test, assert_equals, assert_true, assert_false } = - require('../common/wpt'); - -const self = global; - -/* eslint-disable quotes, max-len */ - -/* The following tests should not be modified as they are copied */ -/* WPT Refs: - https://github.com/w3c/web-platform-tests/blob/40e451c/console/console-is-a-namespace.any.js - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ - +"use strict"; // https://heycam.github.io/webidl/#es-namespaces // https://console.spec.whatwg.org/#console-namespace @@ -38,10 +22,6 @@ test(() => { const prototype1 = Object.getPrototypeOf(console); const prototype2 = Object.getPrototypeOf(prototype1); - // This got commented out from the original test because in Node.js all - // functions are declared on the prototype. - // assert_equals(Object.getOwnPropertyNames(prototype1).length, 0, "The [[Prototype]] must have no properties"); + assert_equals(Object.getOwnPropertyNames(prototype1).length, 0, "The [[Prototype]] must have no properties"); assert_equals(prototype2, Object.prototype, "The [[Prototype]]'s [[Prototype]] must be %ObjectPrototype%"); }, "The prototype chain must be correct"); - -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-console-label-conversion.js b/test/fixtures/wpt/console/console-label-conversion.any.js similarity index 64% rename from test/parallel/test-whatwg-console-label-conversion.js rename to test/fixtures/wpt/console/console-label-conversion.any.js index 9131a0c175d11c..1fb269d4061c61 100644 --- a/test/parallel/test-whatwg-console-label-conversion.js +++ b/test/fixtures/wpt/console/console-label-conversion.any.js @@ -1,18 +1,4 @@ -'use strict'; - -require('../common'); - -const { test, assert_true, assert_throws } = - require('../common/wpt'); - -/* eslint-disable max-len, object-curly-spacing */ - -/* The following tests should not be modified as they are copied */ -/* WPT Refs: - https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/console/console-label-conversion.any.js - License: https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/LICENSE.md -*/ - +"use strict"; // https://console.spec.whatwg/org/#counting // https://console.spec.whatwg/org/#timing @@ -41,5 +27,3 @@ for (const method of methods) { }, `${method} must re-throw any exceptions thrown by label.toString() conversion`); }, `console.${method}() throws exceptions generated by erroneous label.toString() conversion`); } - -/* eslint-enable */ diff --git a/test/fixtures/wpt/console/console-number-format-specifiers-symbol-manual.html b/test/fixtures/wpt/console/console-number-format-specifiers-symbol-manual.html new file mode 100644 index 00000000000000..f77b84e51595f3 --- /dev/null +++ b/test/fixtures/wpt/console/console-number-format-specifiers-symbol-manual.html @@ -0,0 +1,26 @@ + + + +Console Number Format Specifiers on Symbols + + + + + +

Open the console inside the developer tools. It should contain 15 entries, each of which are:

+

NaN

+ + + + diff --git a/test/fixtures/wpt/console/console-string-format-specifier-symbol-manual.html b/test/fixtures/wpt/console/console-string-format-specifier-symbol-manual.html new file mode 100644 index 00000000000000..3a1b93f7352174 --- /dev/null +++ b/test/fixtures/wpt/console/console-string-format-specifier-symbol-manual.html @@ -0,0 +1,23 @@ + + + +Console String Format Specifier on Symbols + + + + + +

Open the console inside the developer tools. It should contain five entries, each of which are:

+

Symbol(description)

+ + + + diff --git a/test/parallel/test-whatwg-console-tests-historical.js b/test/fixtures/wpt/console/console-tests-historical.any.js similarity index 59% rename from test/parallel/test-whatwg-console-tests-historical.js rename to test/fixtures/wpt/console/console-tests-historical.any.js index d4a998b07061b9..4c4d4c276d0cd4 100644 --- a/test/parallel/test-whatwg-console-tests-historical.js +++ b/test/fixtures/wpt/console/console-tests-historical.any.js @@ -1,18 +1,3 @@ -'use strict'; - -require('../common'); - -const { test, assert_equals } = - require('../common/wpt'); - -/* eslint-disable max-len, quotes */ - -/* The following tests should not be modified as they are copied */ -/* WPT Refs: - https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/console/console-tests-historical.any.js - License: https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/LICENSE.md -*/ - /** * These tests assert the non-existence of certain * legacy Console methods that are not included in @@ -32,5 +17,3 @@ test(() => { test(() => { assert_equals(console.markTimeline, undefined, "console.markTimeline should be undefined"); }, "'markTimeline' function should not exist on the console object"); - -/* eslint-enable */ diff --git a/test/fixtures/wpt/console/console-timing-logging-manual.html b/test/fixtures/wpt/console/console-timing-logging-manual.html new file mode 100644 index 00000000000000..3b9e5cea21da8e --- /dev/null +++ b/test/fixtures/wpt/console/console-timing-logging-manual.html @@ -0,0 +1,70 @@ + + + +Console Timing Methods - Logging Manual Test + + + + + +

Open the console inside the developer tools. It should contain entries whose contents are:

+

default: <some time>

+

default: <some time>

+ +

default: <some time>

+

default: <some time> extra data

+

default: <some time>

+ +

default: <some time>

+

default: <some time> extra data

+

default: <some time>

+ +

default: <some time>

+

default: <some time> extra data

+

default: <some time>

+ +

custom toString(): <some time>

+

custom toString(): <some time> extra data

+

custom toString(): <some time>

+ +

a label: <some time>

+

a label: <some time> extra data

+

a label: <some time>

+ +

[some warning message indicating that a timer for label "b" does not exist]

+ + + + diff --git a/test/fixtures/wpt/console/idlharness.any.js b/test/fixtures/wpt/console/idlharness.any.js new file mode 100644 index 00000000000000..1e7ba76ecddca2 --- /dev/null +++ b/test/fixtures/wpt/console/idlharness.any.js @@ -0,0 +1,9 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://console.spec.whatwg.org/ + +idl_test( + ['console'], + [] // no deps +); diff --git a/test/fixtures/wpt/interfaces/console.idl b/test/fixtures/wpt/interfaces/console.idl new file mode 100644 index 00000000000000..53130711a1173f --- /dev/null +++ b/test/fixtures/wpt/interfaces/console.idl @@ -0,0 +1,34 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into reffy-reports +// (https://github.com/tidoust/reffy-reports) +// Source: Console Standard (https://console.spec.whatwg.org/) + +[Exposed=(Window,Worker,Worklet)] +namespace console { // but see namespace object requirements below + // Logging + void assert(optional boolean condition = false, any... data); + void clear(); + void debug(any... data); + void error(any... data); + void info(any... data); + void log(any... data); + void table(any tabularData, optional sequence properties); + void trace(any... data); + void warn(any... data); + void dir(any item, optional object? options); + void dirxml(any... data); + + // Counting + void count(optional DOMString label = "default"); + void countReset(optional DOMString label = "default"); + + // Grouping + void group(any... data); + void groupCollapsed(any... data); + void groupEnd(); + + // Timing + void time(optional DOMString label = "default"); + void timeLog(optional DOMString label = "default", any... data); + void timeEnd(optional DOMString label = "default"); +}; diff --git a/test/fixtures/wpt/interfaces/url.idl b/test/fixtures/wpt/interfaces/url.idl new file mode 100644 index 00000000000000..998052da6ef1b3 --- /dev/null +++ b/test/fixtures/wpt/interfaces/url.idl @@ -0,0 +1,40 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into reffy-reports +// (https://github.com/tidoust/reffy-reports) +// Source: URL Standard (https://url.spec.whatwg.org/) + +[Constructor(USVString url, optional USVString base), + Exposed=(Window,Worker), + LegacyWindowAlias=webkitURL] +interface URL { + stringifier attribute USVString href; + readonly attribute USVString origin; + attribute USVString protocol; + attribute USVString username; + attribute USVString password; + attribute USVString host; + attribute USVString hostname; + attribute USVString port; + attribute USVString pathname; + attribute USVString search; + [SameObject] readonly attribute URLSearchParams searchParams; + attribute USVString hash; + + USVString toJSON(); +}; + +[Constructor(optional (sequence> or record or USVString) init = ""), + Exposed=(Window,Worker)] +interface URLSearchParams { + void append(USVString name, USVString value); + void delete(USVString name); + USVString? get(USVString name); + sequence getAll(USVString name); + boolean has(USVString name); + void set(USVString name, USVString value); + + void sort(); + + iterable; + stringifier; +}; diff --git a/test/fixtures/wpt/resources/.gitignore b/test/fixtures/wpt/resources/.gitignore new file mode 100644 index 00000000000000..04fdeda1cc4ea1 --- /dev/null +++ b/test/fixtures/wpt/resources/.gitignore @@ -0,0 +1,3 @@ +ROBIN-TODO.txt +scratch +node_modules diff --git a/test/fixtures/wpt/resources/.htaccess b/test/fixtures/wpt/resources/.htaccess new file mode 100644 index 00000000000000..fd46101ca0099e --- /dev/null +++ b/test/fixtures/wpt/resources/.htaccess @@ -0,0 +1,2 @@ +# make tests that use utf-16 not inherit the encoding for testharness.js et. al. +AddCharset utf-8 .css .js diff --git a/test/fixtures/wpt/resources/LICENSE b/test/fixtures/wpt/resources/LICENSE new file mode 100644 index 00000000000000..45896e6be2bd51 --- /dev/null +++ b/test/fixtures/wpt/resources/LICENSE @@ -0,0 +1,30 @@ +W3C 3-clause BSD License + +http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of works must retain the original copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the original copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of the W3C nor the names of its contributors may be + used to endorse or promote products derived from this work without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/test/fixtures/wpt/resources/META.yml b/test/fixtures/wpt/resources/META.yml new file mode 100644 index 00000000000000..8f988f99a82e09 --- /dev/null +++ b/test/fixtures/wpt/resources/META.yml @@ -0,0 +1,3 @@ +suggested_reviewers: + - jgraham + - gsnedders diff --git a/test/fixtures/wpt/resources/check-layout-th.js b/test/fixtures/wpt/resources/check-layout-th.js new file mode 100644 index 00000000000000..928b0cf2a1041e --- /dev/null +++ b/test/fixtures/wpt/resources/check-layout-th.js @@ -0,0 +1,196 @@ +(function() { +// Test is initiated from body.onload, so explicit done() call is required. +setup({ explicit_done: true }); + +function checkSubtreeExpectedValues(t, parent, prefix) +{ + var checkedLayout = checkExpectedValues(t, parent, prefix); + Array.prototype.forEach.call(parent.childNodes, function(node) { + checkedLayout |= checkSubtreeExpectedValues(t, node, prefix); + }); + return checkedLayout; +} + +function checkAttribute(output, node, attribute) +{ + var result = node.getAttribute && node.getAttribute(attribute); + output.checked |= !!result; + return result; +} + +function assert_tolerance(actual, expected, message) +{ + if (isNaN(expected) || Math.abs(actual - expected) >= 1) { + assert_equals(actual, Number(expected), message); + } +} + +function checkExpectedValues(t, node, prefix) +{ + var output = { checked: false }; + + var expectedWidth = checkAttribute(output, node, "data-expected-width"); + if (expectedWidth) { + assert_tolerance(node.offsetWidth, expectedWidth, prefix + "width"); + } + + var expectedHeight = checkAttribute(output, node, "data-expected-height"); + if (expectedHeight) { + assert_tolerance(node.offsetHeight, expectedHeight, prefix + "height"); + } + + var expectedOffset = checkAttribute(output, node, "data-offset-x"); + if (expectedOffset) { + assert_tolerance(node.offsetLeft, expectedOffset, prefix + "offsetLeft"); + } + + var expectedOffset = checkAttribute(output, node, "data-offset-y"); + if (expectedOffset) { + assert_tolerance(node.offsetTop, expectedOffset, prefix + "offsetTop"); + } + + var expectedWidth = checkAttribute(output, node, "data-expected-client-width"); + if (expectedWidth) { + assert_tolerance(node.clientWidth, expectedWidth, prefix + "clientWidth"); + } + + var expectedHeight = checkAttribute(output, node, "data-expected-client-height"); + if (expectedHeight) { + assert_tolerance(node.clientHeight, expectedHeight, prefix + "clientHeight"); + } + + var expectedWidth = checkAttribute(output, node, "data-expected-scroll-width"); + if (expectedWidth) { + assert_tolerance(node.scrollWidth, expectedWidth, prefix + "scrollWidth"); + } + + var expectedHeight = checkAttribute(output, node, "data-expected-scroll-height"); + if (expectedHeight) { + assert_tolerance(node.scrollHeight, expectedHeight, prefix + "scrollHeight"); + } + + var expectedWidth = checkAttribute(output, node, "data-expected-bounding-client-rect-width"); + if (expectedWidth) { + assert_tolerance(node.getBoundingClientRect().width, expectedWidth, prefix + "getBoundingClientRect().width"); + } + + var expectedOffset = checkAttribute(output, node, "data-total-x"); + if (expectedOffset) { + var totalLeft = node.clientLeft + node.offsetLeft; + assert_tolerance(totalLeft, expectedOffset, prefix + + "clientLeft+offsetLeft (" + node.clientLeft + " + " + node.offsetLeft + ")"); + } + + var expectedOffset = checkAttribute(output, node, "data-total-y"); + if (expectedOffset) { + var totalTop = node.clientTop + node.offsetTop; + assert_tolerance(totalTop, expectedOffset, prefix + + "clientTop+offsetTop (" + node.clientTop + " + " + node.offsetTop + ")"); + } + + var expectedDisplay = checkAttribute(output, node, "data-expected-display"); + if (expectedDisplay) { + var actualDisplay = getComputedStyle(node).display; + assert_equals(actualDisplay, expectedDisplay, prefix + "display"); + } + + var expectedPaddingTop = checkAttribute(output, node, "data-expected-padding-top"); + if (expectedPaddingTop) { + var actualPaddingTop = getComputedStyle(node).paddingTop; + // Trim the unit "px" from the output. + actualPaddingTop = actualPaddingTop.slice(0, -2); + assert_equals(actualPaddingTop, expectedPaddingTop, prefix + "padding-top"); + } + + var expectedPaddingBottom = checkAttribute(output, node, "data-expected-padding-bottom"); + if (expectedPaddingBottom) { + var actualPaddingBottom = getComputedStyle(node).paddingBottom; + // Trim the unit "px" from the output. + actualPaddingBottom = actualPaddingBottom.slice(0, -2); + assert_equals(actualPaddingBottom, expectedPaddingBottom, prefix + "padding-bottom"); + } + + var expectedPaddingLeft = checkAttribute(output, node, "data-expected-padding-left"); + if (expectedPaddingLeft) { + var actualPaddingLeft = getComputedStyle(node).paddingLeft; + // Trim the unit "px" from the output. + actualPaddingLeft = actualPaddingLeft.slice(0, -2); + assert_equals(actualPaddingLeft, expectedPaddingLeft, prefix + "padding-left"); + } + + var expectedPaddingRight = checkAttribute(output, node, "data-expected-padding-right"); + if (expectedPaddingRight) { + var actualPaddingRight = getComputedStyle(node).paddingRight; + // Trim the unit "px" from the output. + actualPaddingRight = actualPaddingRight.slice(0, -2); + assert_equals(actualPaddingRight, expectedPaddingRight, prefix + "padding-right"); + } + + var expectedMarginTop = checkAttribute(output, node, "data-expected-margin-top"); + if (expectedMarginTop) { + var actualMarginTop = getComputedStyle(node).marginTop; + // Trim the unit "px" from the output. + actualMarginTop = actualMarginTop.slice(0, -2); + assert_equals(actualMarginTop, expectedMarginTop, prefix + "margin-top"); + } + + var expectedMarginBottom = checkAttribute(output, node, "data-expected-margin-bottom"); + if (expectedMarginBottom) { + var actualMarginBottom = getComputedStyle(node).marginBottom; + // Trim the unit "px" from the output. + actualMarginBottom = actualMarginBottom.slice(0, -2); + assert_equals(actualMarginBottom, expectedMarginBottom, prefix + "margin-bottom"); + } + + var expectedMarginLeft = checkAttribute(output, node, "data-expected-margin-left"); + if (expectedMarginLeft) { + var actualMarginLeft = getComputedStyle(node).marginLeft; + // Trim the unit "px" from the output. + actualMarginLeft = actualMarginLeft.slice(0, -2); + assert_equals(actualMarginLeft, expectedMarginLeft, prefix + "margin-left"); + } + + var expectedMarginRight = checkAttribute(output, node, "data-expected-margin-right"); + if (expectedMarginRight) { + var actualMarginRight = getComputedStyle(node).marginRight; + // Trim the unit "px" from the output. + actualMarginRight = actualMarginRight.slice(0, -2); + assert_equals(actualMarginRight, expectedMarginRight, prefix + "margin-right"); + } + + return output.checked; +} + +var testNumber = 0; + +window.checkLayout = function(selectorList, callDone = true) +{ + if (!selectorList) { + console.error("You must provide a CSS selector of nodes to check."); + return; + } + var nodes = document.querySelectorAll(selectorList); + nodes = Array.prototype.slice.call(nodes); + var checkedLayout = false; + Array.prototype.forEach.call(nodes, function(node) { + test(function(t) { + var container = node.parentNode.className == 'container' ? node.parentNode : node; + var prefix = "\n" + container.outerHTML + "\n"; + var passed = false; + try { + checkedLayout |= checkExpectedValues(t, node.parentNode, prefix); + checkedLayout |= checkSubtreeExpectedValues(t, node, prefix); + passed = true; + } finally { + checkedLayout |= !passed; + } + }, selectorList + ' ' + String(++testNumber)); + }); + if (!checkedLayout) { + console.error("No valid data-* attributes found in selector list : " + selectorList); + } + if (callDone) + done(); +}; + +})(); diff --git a/test/fixtures/wpt/resources/idlharness.js b/test/fixtures/wpt/resources/idlharness.js new file mode 100644 index 00000000000000..40a5fa59cd209d --- /dev/null +++ b/test/fixtures/wpt/resources/idlharness.js @@ -0,0 +1,3180 @@ +/* +Distributed under both the W3C Test Suite License [1] and the W3C +3-clause BSD License [2]. To contribute to a W3C Test Suite, see the +policies and contribution forms [3]. + +[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license +[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license +[3] http://www.w3.org/2004/10/27-testcases +*/ + +/* For user documentation see docs/_writing-tests/idlharness.md */ + +/** + * Notes for people who want to edit this file (not just use it as a library): + * + * Most of the interesting stuff happens in the derived classes of IdlObject, + * especially IdlInterface. The entry point for all IdlObjects is .test(), + * which is called by IdlArray.test(). An IdlObject is conceptually just + * "thing we want to run tests on", and an IdlArray is an array of IdlObjects + * with some additional data thrown in. + * + * The object model is based on what WebIDLParser.js produces, which is in turn + * based on its pegjs grammar. If you want to figure out what properties an + * object will have from WebIDLParser.js, the best way is to look at the + * grammar: + * + * https://github.com/darobin/webidl.js/blob/master/lib/grammar.peg + * + * So for instance: + * + * // interface definition + * interface + * = extAttrs:extendedAttributeList? S? "interface" S name:identifier w herit:ifInheritance? w "{" w mem:ifMember* w "}" w ";" w + * { return { type: "interface", name: name, inheritance: herit, members: mem, extAttrs: extAttrs }; } + * + * This means that an "interface" object will have a .type property equal to + * the string "interface", a .name property equal to the identifier that the + * parser found, an .inheritance property equal to either null or the result of + * the "ifInheritance" production found elsewhere in the grammar, and so on. + * After each grammatical production is a JavaScript function in curly braces + * that gets called with suitable arguments and returns some JavaScript value. + * + * (Note that the version of WebIDLParser.js we use might sometimes be + * out-of-date or forked.) + * + * The members and methods of the classes defined by this file are all at least + * briefly documented, hopefully. + */ +(function(){ +"use strict"; +// Support subsetTestByKey from /common/subset-tests-by-key.js, but make it optional +if (!('subsetTestByKey' in self)) { + self.subsetTestByKey = function(key, callback, ...args) { + return callback(...args); + } + self.shouldRunSubTest = () => true; +} +/// Helpers /// +function constValue (cnt) +{ + if (cnt.type === "null") return null; + if (cnt.type === "NaN") return NaN; + if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity; + if (cnt.type === "number") return +cnt.value; + return cnt.value; +} + +function minOverloadLength(overloads) +{ + // "The value of the Function object’s “length” property is + // a Number determined as follows: + // ". . . + // "Return the length of the shortest argument list of the + // entries in S." + if (!overloads.length) { + return 0; + } + + return overloads.map(function(attr) { + return attr.arguments ? attr.arguments.filter(function(arg) { + return !arg.optional && !arg.variadic; + }).length : 0; + }) + .reduce(function(m, n) { return Math.min(m, n); }); +} + +function throwOrReject(a_test, operation, fn, obj, args, message, cb) +{ + if (operation.idlType.generic !== "Promise") { + assert_throws(new TypeError(), function() { + fn.apply(obj, args); + }, message); + cb(); + } else { + try { + promise_rejects(a_test, new TypeError(), fn.apply(obj, args), message).then(cb, cb); + } catch (e){ + a_test.step(function() { + assert_unreached("Throws \"" + e + "\" instead of rejecting promise"); + cb(); + }); + } + } +} + +function awaitNCallbacks(n, cb, ctx) +{ + var counter = 0; + return function() { + counter++; + if (counter >= n) { + cb(); + } + }; +} + +var fround = +(function(){ + if (Math.fround) return Math.fround; + + var arr = new Float32Array(1); + return function fround(n) { + arr[0] = n; + return arr[0]; + }; +})(); + +/// IdlHarnessError /// +// Entry point +self.IdlHarnessError = function(message) +{ + /** + * Message to be printed as the error's toString invocation. + */ + this.message = message; +}; + +IdlHarnessError.prototype = Object.create(Error.prototype); + +IdlHarnessError.prototype.toString = function() +{ + return this.message; +}; + + +/// IdlArray /// +// Entry point +self.IdlArray = function() +{ + /** + * A map from strings to the corresponding named IdlObject, such as + * IdlInterface or IdlException. These are the things that test() will run + * tests on. + */ + this.members = {}; + + /** + * A map from strings to arrays of strings. The keys are interface or + * exception names, and are expected to also exist as keys in this.members + * (otherwise they'll be ignored). This is populated by add_objects() -- + * see documentation at the start of the file. The actual tests will be + * run by calling this.members[name].test_object(obj) for each obj in + * this.objects[name]. obj is a string that will be eval'd to produce a + * JavaScript value, which is supposed to be an object implementing the + * given IdlObject (interface, exception, etc.). + */ + this.objects = {}; + + /** + * When adding multiple collections of IDLs one at a time, an earlier one + * might contain a partial interface or implements statement that depends + * on a later one. Save these up and handle them right before we run + * tests. + * + * .partials is simply an array of objects from WebIDLParser.js' + * "partialinterface" production. .implements maps strings to arrays of + * strings, such that + * + * A implements B; + * A implements C; + * D implements E; + * + * results in this["implements"] = { A: ["B", "C"], D: ["E"] }. + * + * Similarly, + * + * interface A : B {}; + * interface B : C {}; + * + * results in this["inheritance"] = { A: "B", B: "C" } + */ + this.partials = []; + this["implements"] = {}; + this["includes"] = {}; + this["inheritance"] = {}; +}; + +IdlArray.prototype.add_idls = function(raw_idls, options) +{ + /** Entry point. See documentation at beginning of file. */ + this.internal_add_idls(WebIDL2.parse(raw_idls), options); +}; + +IdlArray.prototype.add_untested_idls = function(raw_idls, options) +{ + /** Entry point. See documentation at beginning of file. */ + var parsed_idls = WebIDL2.parse(raw_idls); + this.mark_as_untested(parsed_idls); + this.internal_add_idls(parsed_idls, options); +}; + +IdlArray.prototype.mark_as_untested = function (parsed_idls) +{ + for (var i = 0; i < parsed_idls.length; i++) { + parsed_idls[i].untested = true; + if ("members" in parsed_idls[i]) { + for (var j = 0; j < parsed_idls[i].members.length; j++) { + parsed_idls[i].members[j].untested = true; + } + } + } +}; + +IdlArray.prototype.is_excluded_by_options = function (name, options) +{ + return options && + (options.except && options.except.includes(name) + || options.only && !options.only.includes(name)); +}; + +IdlArray.prototype.add_dependency_idls = function(raw_idls, options) +{ + const parsed_idls = WebIDL2.parse(raw_idls); + const new_options = { only: [] } + + const all_deps = new Set(); + Object.values(this.inheritance).forEach(v => all_deps.add(v)); + Object.entries(this.implements).forEach(([k, v]) => { + all_deps.add(k); + all_deps.add(v); + }); + // NOTE: If 'A includes B' for B that we care about, then A is also a dep. + Object.keys(this.includes).forEach(k => { + all_deps.add(k); + this.includes[k].forEach(v => all_deps.add(v)); + }); + this.partials.map(p => p.name).forEach(v => all_deps.add(v)); + // Add the attribute idlTypes of all the nested members of all tested idls. + for (const obj of [this.members, this.partials]) { + const tested = Object.values(obj).filter(m => !m.untested && m.members); + for (const parsed of tested) { + for (const attr of Object.values(parsed.members).filter(m => !m.untested && m.type === 'attribute')) { + all_deps.add(attr.idlType.idlType); + } + } + } + + if (options && options.except && options.only) { + throw new IdlHarnessError("The only and except options can't be used together."); + } + + const should_skip = name => { + // NOTE: Deps are untested, so we're lenient, and skip re-encountered definitions. + // e.g. for 'idl' containing A:B, B:C, C:D + // array.add_idls(idl, {only: ['A','B']}). + // array.add_dependency_idls(idl); + // B would be encountered as tested, and encountered as a dep, so we ignore. + return name in this.members + || this.is_excluded_by_options(name, options); + } + // Record of skipped items, in case we later determine they are a dependency. + // Maps name -> [parsed_idl, ...] + const skipped = new Map(); + const process = function(parsed) { + var deps = []; + if (parsed.name) { + deps.push(parsed.name); + } else if (parsed.type === "implements") { + deps.push(parsed.target); + deps.push(parsed.implements); + } else if (parsed.type === "includes") { + deps.push(parsed.target); + deps.push(parsed.includes); + } + + deps = deps.filter(function(name) { + if (!name || should_skip(name) || !all_deps.has(name)) { + // Flag as skipped, if it's not already processed, so we can + // come back to it later if we retrospectively call it a dep. + if (name && !(name in this.members)) { + skipped.has(name) + ? skipped.get(name).push(parsed) + : skipped.set(name, [parsed]); + } + return false; + } + return true; + }.bind(this)); + + deps.forEach(function(name) { + new_options.only.push(name); + + const follow_up = new Set(); + for (const dep_type of ["inheritance", "implements", "includes"]) { + if (parsed[dep_type]) { + const inheriting = parsed[dep_type]; + const inheritor = parsed.name || parsed.target; + const deps = [inheriting]; + // For A includes B, we can ignore A unless B is being tested. + if (dep_type !== "includes" + || (inheriting in this.members && !this.members[inheriting].untested)) { + deps.push(inheritor); + } + for (const dep of deps) { + new_options.only.push(dep); + all_deps.add(dep); + follow_up.add(dep); + } + } + } + + for (const deferred of follow_up) { + if (skipped.has(deferred)) { + const next = skipped.get(deferred); + skipped.delete(deferred); + next.forEach(process); + } + } + }.bind(this)); + }.bind(this); + + for (let parsed of parsed_idls) { + process(parsed); + } + + this.mark_as_untested(parsed_idls); + + if (new_options.only.length) { + this.internal_add_idls(parsed_idls, new_options); + } +} + +IdlArray.prototype.internal_add_idls = function(parsed_idls, options) +{ + /** + * Internal helper called by add_idls() and add_untested_idls(). + * + * parsed_idls is an array of objects that come from WebIDLParser.js's + * "definitions" production. The add_untested_idls() entry point + * additionally sets an .untested property on each object (and its + * .members) so that they'll be skipped by test() -- they'll only be + * used for base interfaces of tested interfaces, return types, etc. + * + * options is a dictionary that can have an only or except member which are + * arrays. If only is given then only members, partials and interface + * targets listed will be added, and if except is given only those that + * aren't listed will be added. Only one of only and except can be used. + */ + + if (options && options.only && options.except) + { + throw new IdlHarnessError("The only and except options can't be used together."); + } + + var should_skip = name => { + return this.is_excluded_by_options(name, options); + } + + parsed_idls.forEach(function(parsed_idl) + { + var partial_types = [ + "interface", + "interface mixin", + "dictionary", + "namespace", + ]; + if (parsed_idl.partial && partial_types.includes(parsed_idl.type)) + { + if (should_skip(parsed_idl.name)) + { + return; + } + this.partials.push(parsed_idl); + return; + } + + if (parsed_idl.type == "implements") + { + if (should_skip(parsed_idl.target)) + { + return; + } + if (!(parsed_idl.target in this["implements"])) + { + this["implements"][parsed_idl.target] = []; + } + this["implements"][parsed_idl.target].push(parsed_idl["implements"]); + return; + } + + if (parsed_idl.type == "includes") + { + if (should_skip(parsed_idl.target)) + { + return; + } + if (!(parsed_idl.target in this["includes"])) + { + this["includes"][parsed_idl.target] = []; + } + this["includes"][parsed_idl.target].push(parsed_idl["includes"]); + return; + } + + parsed_idl.array = this; + if (should_skip(parsed_idl.name)) + { + return; + } + if (parsed_idl.name in this.members) + { + throw new IdlHarnessError("Duplicate identifier " + parsed_idl.name); + } + + if (parsed_idl["inheritance"]) { + // NOTE: Clash should be impossible (would require redefinition of parsed_idl.name). + if (parsed_idl.name in this["inheritance"] + && parsed_idl["inheritance"] != this["inheritance"][parsed_idl.name]) { + throw new IdlHarnessError( + `Inheritance for ${parsed_idl.name} was already defined`); + } + this["inheritance"][parsed_idl.name] = parsed_idl["inheritance"]; + } + + switch(parsed_idl.type) + { + case "interface": + this.members[parsed_idl.name] = + new IdlInterface(parsed_idl, /* is_callback = */ false, /* is_mixin = */ false); + break; + + case "interface mixin": + this.members[parsed_idl.name] = + new IdlInterface(parsed_idl, /* is_callback = */ false, /* is_mixin = */ true); + break; + + case "dictionary": + // Nothing to test, but we need the dictionary info around for type + // checks + this.members[parsed_idl.name] = new IdlDictionary(parsed_idl); + break; + + case "typedef": + this.members[parsed_idl.name] = new IdlTypedef(parsed_idl); + break; + + case "callback": + // TODO + console.log("callback not yet supported"); + break; + + case "enum": + this.members[parsed_idl.name] = new IdlEnum(parsed_idl); + break; + + case "callback interface": + this.members[parsed_idl.name] = + new IdlInterface(parsed_idl, /* is_callback = */ true, /* is_mixin = */ false); + break; + + case "namespace": + this.members[parsed_idl.name] = new IdlNamespace(parsed_idl); + break; + + default: + throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported"; + } + }.bind(this)); +}; + +IdlArray.prototype.add_objects = function(dict) +{ + /** Entry point. See documentation at beginning of file. */ + for (var k in dict) + { + if (k in this.objects) + { + this.objects[k] = this.objects[k].concat(dict[k]); + } + else + { + this.objects[k] = dict[k]; + } + } +}; + +IdlArray.prototype.prevent_multiple_testing = function(name) +{ + /** Entry point. See documentation at beginning of file. */ + this.members[name].prevent_multiple_testing = true; +}; + +IdlArray.prototype.recursively_get_implements = function(interface_name) +{ + /** + * Helper function for test(). Returns an array of things that implement + * interface_name, so if the IDL contains + * + * A implements B; + * B implements C; + * B implements D; + * + * then recursively_get_implements("A") should return ["B", "C", "D"]. + */ + var ret = this["implements"][interface_name]; + if (ret === undefined) + { + return []; + } + for (var i = 0; i < this["implements"][interface_name].length; i++) + { + ret = ret.concat(this.recursively_get_implements(ret[i])); + if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i])) + { + throw new IdlHarnessError("Circular implements statements involving " + ret[i]); + } + } + return ret; +}; + +IdlArray.prototype.recursively_get_includes = function(interface_name) +{ + /** + * Helper function for test(). Returns an array of things that implement + * interface_name, so if the IDL contains + * + * A includes B; + * B includes C; + * B includes D; + * + * then recursively_get_includes("A") should return ["B", "C", "D"]. + */ + var ret = this["includes"][interface_name]; + if (ret === undefined) + { + return []; + } + for (var i = 0; i < this["includes"][interface_name].length; i++) + { + ret = ret.concat(this.recursively_get_includes(ret[i])); + if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i])) + { + throw new IdlHarnessError("Circular includes statements involving " + ret[i]); + } + } + return ret; +}; + +IdlArray.prototype.is_json_type = function(type) +{ + /** + * Checks whether type is a JSON type as per + * https://heycam.github.io/webidl/#dfn-json-types + */ + + var idlType = type.idlType; + + if (type.generic == "Promise") { return false; } + + // nullable and annotated types don't need to be handled separately, + // as webidl2 doesn't represent them wrapped-up (as they're described + // in WebIDL). + + // union and record types + if (type.union || type.generic == "record") { + return idlType.every(this.is_json_type, this); + } + + // sequence types + if (type.generic == "sequence" || type.generic == "FrozenArray") { + return this.is_json_type(idlType); + } + + if (typeof idlType != "string") { throw new Error("Unexpected type " + JSON.stringify(idlType)); } + + switch (idlType) + { + // Numeric types + case "byte": + case "octet": + case "short": + case "unsigned short": + case "long": + case "unsigned long": + case "long long": + case "unsigned long long": + case "float": + case "double": + case "unrestricted float": + case "unrestricted double": + // boolean + case "boolean": + // string types + case "DOMString": + case "ByteString": + case "USVString": + // object type + case "object": + return true; + case "Error": + case "DOMException": + case "Int8Array": + case "Int16Array": + case "Int32Array": + case "Uint8Array": + case "Uint16Array": + case "Uint32Array": + case "Uint8ClampedArray": + case "Float32Array": + case "ArrayBuffer": + case "DataView": + case "any": + return false; + default: + var thing = this.members[idlType]; + if (!thing) { throw new Error("Type " + idlType + " not found"); } + if (thing instanceof IdlEnum) { return true; } + + if (thing instanceof IdlTypedef) { + return this.is_json_type(thing.idlType); + } + + // dictionaries where all of their members are JSON types + if (thing instanceof IdlDictionary) { + var stack = thing.get_inheritance_stack(); + var map = new Map(); + while (stack.length) + { + stack.pop().members.forEach(function(m) { + map.set(m.name, m.idlType) + }); + } + return Array.from(map.values()).every(this.is_json_type, this); + } + + // interface types that have a toJSON operation declared on themselves or + // one of their inherited or consequential interfaces. + if (thing instanceof IdlInterface) { + var base; + while (thing) + { + if (thing.has_to_json_regular_operation()) { return true; } + var mixins = this.implements[thing.name] || this.includes[thing.name]; + if (mixins) { + mixins = mixins.map(function(id) { + var mixin = this.members[id]; + if (!mixin) { + throw new Error("Interface " + id + " not found (implemented by " + thing.name + ")"); + } + return mixin; + }, this); + if (mixins.some(function(m) { return m.has_to_json_regular_operation() } )) { return true; } + } + if (!thing.base) { return false; } + base = this.members[thing.base]; + if (!base) { + throw new Error("Interface " + thing.base + " not found (inherited by " + thing.name + ")"); + } + thing = base; + } + return false; + } + return false; + } +}; + +function exposure_set(object, default_set) { + var exposed = object.extAttrs && object.extAttrs.filter(a => a.name === "Exposed"); + if (exposed && exposed.length > 1) { + throw new IdlHarnessError( + `Multiple 'Exposed' extended attributes on ${object.name}`); + } + + let result = default_set || ["Window"]; + if (result && !(result instanceof Set)) { + result = new Set(result); + } + if (exposed && exposed.length) { + var set = exposed[0].rhs.value; + // Could be a list or a string. + if (typeof set == "string") { + set = [ set ]; + } + result = new Set(set); + } + if (result && result.has("Worker")) { + result.delete("Worker"); + result.add("DedicatedWorker"); + result.add("ServiceWorker"); + result.add("SharedWorker"); + } + return result; +} + +function exposed_in(globals) { + if ('document' in self) { + return globals.has("Window"); + } + if ('DedicatedWorkerGlobalScope' in self && + self instanceof DedicatedWorkerGlobalScope) { + return globals.has("DedicatedWorker"); + } + if ('SharedWorkerGlobalScope' in self && + self instanceof SharedWorkerGlobalScope) { + return globals.has("SharedWorker"); + } + if ('ServiceWorkerGlobalScope' in self && + self instanceof ServiceWorkerGlobalScope) { + return globals.has("ServiceWorker"); + } + throw new IdlHarnessError("Unexpected global object"); +} + +/** + * Asserts that the given error message is thrown for the given function. + * @param {string|IdlHarnessError} error Expected Error message. + * @param {Function} idlArrayFunc Function operating on an IdlArray that should throw. + */ +IdlArray.prototype.assert_throws = function(error, idlArrayFunc) +{ + try { + idlArrayFunc.call(this, this); + } catch (e) { + if (e instanceof AssertionError) { + throw e; + } + // Assertions for behaviour of the idlharness.js engine. + if (error instanceof IdlHarnessError) { + error = error.message; + } + if (e.message !== error) { + throw new IdlHarnessError(`${idlArrayFunc} threw "${e}", not the expected IdlHarnessError "${error}"`); + } + return; + } + throw new IdlHarnessError(`${idlArrayFunc} did not throw the expected IdlHarnessError`); +} + +IdlArray.prototype.test = function() +{ + /** Entry point. See documentation at beginning of file. */ + + // First merge in all the partial interfaces and implements statements we + // encountered. + this.collapse_partials(); + + for (var lhs in this["implements"]) + { + this.recursively_get_implements(lhs).forEach(function(rhs) + { + var errStr = lhs + " implements " + rhs + ", but "; + if (!(lhs in this.members)) throw errStr + lhs + " is undefined."; + if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface."; + if (!(rhs in this.members)) throw errStr + rhs + " is undefined."; + if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface."; + this.members[rhs].members.forEach(function(member) + { + this.members[lhs].members.push(new IdlInterfaceMember(member)); + }.bind(this)); + }.bind(this)); + } + this["implements"] = {}; + + for (var lhs in this["includes"]) + { + this.recursively_get_includes(lhs).forEach(function(rhs) + { + var errStr = lhs + " includes " + rhs + ", but "; + if (!(lhs in this.members)) throw errStr + lhs + " is undefined."; + if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface."; + if (!(rhs in this.members)) throw errStr + rhs + " is undefined."; + if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface."; + this.members[rhs].members.forEach(function(member) + { + this.members[lhs].members.push(new IdlInterfaceMember(member)); + }.bind(this)); + }.bind(this)); + } + this["includes"] = {}; + + // Assert B defined for A : B + for (const member of Object.values(this.members).filter(m => m.base)) { + const lhs = member.name; + const rhs = member.base; + if (!(rhs in this.members)) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is undefined.`); + const lhs_is_interface = this.members[lhs] instanceof IdlInterface; + const rhs_is_interface = this.members[rhs] instanceof IdlInterface; + if (rhs_is_interface != lhs_is_interface) { + if (!lhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${lhs} is not an interface.`); + if (!rhs_is_interface) throw new IdlHarnessError(`${lhs} inherits ${rhs}, but ${rhs} is not an interface.`); + } + // Check for circular dependencies. + member.get_inheritance_stack(); + } + + Object.getOwnPropertyNames(this.members).forEach(function(memberName) { + var member = this.members[memberName]; + if (!(member instanceof IdlInterface)) { + return; + } + + var globals = exposure_set(member); + member.exposed = exposed_in(globals); + member.exposureSet = globals; + }.bind(this)); + + // Now run test() on every member, and test_object() for every object. + for (var name in this.members) + { + this.members[name].test(); + if (name in this.objects) + { + const objects = this.objects[name]; + if (!objects || !Array.isArray(objects)) { + throw new IdlHarnessError(`Invalid or empty objects for member ${name}`); + } + objects.forEach(function(str) + { + if (!this.members[name] || !(this.members[name] instanceof IdlInterface)) { + throw new IdlHarnessError(`Invalid object member name ${name}`); + } + this.members[name].test_object(str); + }.bind(this)); + } + } +}; + +IdlArray.prototype.collapse_partials = function() +{ + const testedPartials = new Map(); + this.partials.forEach(function(parsed_idl) + { + const originalExists = parsed_idl.name in this.members + && (this.members[parsed_idl.name] instanceof IdlInterface + || this.members[parsed_idl.name] instanceof IdlDictionary + || this.members[parsed_idl.name] instanceof IdlNamespace); + + let partialTestName = parsed_idl.name; + if (!parsed_idl.untested) { + // Ensure unique test name in case of multiple partials. + let partialTestCount = 1; + if (testedPartials.has(parsed_idl.name)) { + partialTestCount += testedPartials.get(parsed_idl.name); + partialTestName = `${partialTestName}[${partialTestCount}]`; + } + testedPartials.set(parsed_idl.name, partialTestCount); + + test(function () { + assert_true(originalExists, `Original ${parsed_idl.type} should be defined`); + + var expected = IdlInterface; + switch (parsed_idl.type) { + case 'interface': expected = IdlInterface; break; + case 'dictionary': expected = IdlDictionary; break; + case 'namespace': expected = IdlNamespace; break; + } + assert_true( + expected.prototype.isPrototypeOf(this.members[parsed_idl.name]), + `Original ${parsed_idl.name} definition should have type ${parsed_idl.type}`); + }.bind(this), `Partial ${parsed_idl.type} ${partialTestName}: original ${parsed_idl.type} defined`); + } + if (!originalExists) { + // Not good.. but keep calm and carry on. + return; + } + + if (parsed_idl.extAttrs) + { + // Special-case "Exposed". Must be a subset of original interface's exposure. + // Exposed on a partial is the equivalent of having the same Exposed on all nested members. + // See https://github.com/heycam/webidl/issues/154 for discrepency between Exposed and + // other extended attributes on partial interfaces. + const exposureAttr = parsed_idl.extAttrs.find(a => a.name === "Exposed"); + if (exposureAttr) { + if (!parsed_idl.untested) { + test(function () { + const partialExposure = exposure_set(parsed_idl); + const memberExposure = exposure_set(this.members[parsed_idl.name]); + partialExposure.forEach(name => { + if (!memberExposure || !memberExposure.has(name)) { + throw new IdlHarnessError( + `Partial ${parsed_idl.name} ${parsed_idl.type} is exposed to '${name}', the original ${parsed_idl.type} is not.`); + } + }); + }.bind(this), `Partial ${parsed_idl.type} ${partialTestName}: valid exposure set`); + } + parsed_idl.members.forEach(function (member) { + member.extAttrs.push(exposureAttr); + }.bind(this)); + } + + parsed_idl.extAttrs.forEach(function(extAttr) + { + // "Exposed" already handled above. + if (extAttr.name === "Exposed") { + return; + } + this.members[parsed_idl.name].extAttrs.push(extAttr); + }.bind(this)); + } + parsed_idl.members.forEach(function(member) + { + this.members[parsed_idl.name].members.push(new IdlInterfaceMember(member)); + }.bind(this)); + }.bind(this)); + this.partials = []; +} + +IdlArray.prototype.assert_type_is = function(value, type) +{ + if (type.idlType in this.members + && this.members[type.idlType] instanceof IdlTypedef) { + this.assert_type_is(value, this.members[type.idlType].idlType); + return; + } + if (type.union) { + for (var i = 0; i < type.idlType.length; i++) { + try { + this.assert_type_is(value, type.idlType[i]); + // No AssertionError, so we match one type in the union + return; + } catch(e) { + if (e instanceof AssertionError) { + // We didn't match this type, let's try some others + continue; + } + throw e; + } + } + // TODO: Is there a nice way to list the union's types in the message? + assert_true(false, "Attribute has value " + format_value(value) + + " which doesn't match any of the types in the union"); + + } + + /** + * Helper function that tests that value is an instance of type according + * to the rules of WebIDL. value is any JavaScript value, and type is an + * object produced by WebIDLParser.js' "type" production. That production + * is fairly elaborate due to the complexity of WebIDL's types, so it's + * best to look at the grammar to figure out what properties it might have. + */ + if (type.idlType == "any") + { + // No assertions to make + return; + } + + if (type.nullable && value === null) + { + // This is fine + return; + } + + if (type.array) + { + // TODO: not supported yet + return; + } + + if (type.generic === "sequence") + { + assert_true(Array.isArray(value), "should be an Array"); + if (!value.length) + { + // Nothing we can do. + return; + } + this.assert_type_is(value[0], type.idlType); + return; + } + + if (type.generic === "Promise") { + assert_true("then" in value, "Attribute with a Promise type should have a then property"); + // TODO: Ideally, we would check on project fulfillment + // that we get the right type + // but that would require making the type check async + return; + } + + if (type.generic === "FrozenArray") { + assert_true(Array.isArray(value), "Value should be array"); + assert_true(Object.isFrozen(value), "Value should be frozen"); + if (!value.length) + { + // Nothing we can do. + return; + } + this.assert_type_is(value[0], type.idlType); + return; + } + + type = type.idlType; + + switch(type) + { + case "void": + assert_equals(value, undefined); + return; + + case "boolean": + assert_equals(typeof value, "boolean"); + return; + + case "byte": + assert_equals(typeof value, "number"); + assert_equals(value, Math.floor(value), "should be an integer"); + assert_true(-128 <= value && value <= 127, "byte " + value + " should be in range [-128, 127]"); + return; + + case "octet": + assert_equals(typeof value, "number"); + assert_equals(value, Math.floor(value), "should be an integer"); + assert_true(0 <= value && value <= 255, "octet " + value + " should be in range [0, 255]"); + return; + + case "short": + assert_equals(typeof value, "number"); + assert_equals(value, Math.floor(value), "should be an integer"); + assert_true(-32768 <= value && value <= 32767, "short " + value + " should be in range [-32768, 32767]"); + return; + + case "unsigned short": + assert_equals(typeof value, "number"); + assert_equals(value, Math.floor(value), "should be an integer"); + assert_true(0 <= value && value <= 65535, "unsigned short " + value + " should be in range [0, 65535]"); + return; + + case "long": + assert_equals(typeof value, "number"); + assert_equals(value, Math.floor(value), "should be an integer"); + assert_true(-2147483648 <= value && value <= 2147483647, "long " + value + " should be in range [-2147483648, 2147483647]"); + return; + + case "unsigned long": + assert_equals(typeof value, "number"); + assert_equals(value, Math.floor(value), "should be an integer"); + assert_true(0 <= value && value <= 4294967295, "unsigned long " + value + " should be in range [0, 4294967295]"); + return; + + case "long long": + assert_equals(typeof value, "number"); + return; + + case "unsigned long long": + case "DOMTimeStamp": + assert_equals(typeof value, "number"); + assert_true(0 <= value, "unsigned long long should be positive"); + return; + + case "float": + assert_equals(typeof value, "number"); + assert_equals(value, fround(value), "float rounded to 32-bit float should be itself"); + assert_not_equals(value, Infinity); + assert_not_equals(value, -Infinity); + assert_not_equals(value, NaN); + return; + + case "DOMHighResTimeStamp": + case "double": + assert_equals(typeof value, "number"); + assert_not_equals(value, Infinity); + assert_not_equals(value, -Infinity); + assert_not_equals(value, NaN); + return; + + case "unrestricted float": + assert_equals(typeof value, "number"); + assert_equals(value, fround(value), "unrestricted float rounded to 32-bit float should be itself"); + return; + + case "unrestricted double": + assert_equals(typeof value, "number"); + return; + + case "DOMString": + assert_equals(typeof value, "string"); + return; + + case "ByteString": + assert_equals(typeof value, "string"); + assert_regexp_match(value, /^[\x00-\x7F]*$/); + return; + + case "USVString": + assert_equals(typeof value, "string"); + assert_regexp_match(value, /^([\x00-\ud7ff\ue000-\uffff]|[\ud800-\udbff][\udc00-\udfff])*$/); + return; + + case "object": + assert_in_array(typeof value, ["object", "function"], "wrong type: not object or function"); + return; + } + + if (!(type in this.members)) + { + throw new IdlHarnessError("Unrecognized type " + type); + } + + if (this.members[type] instanceof IdlInterface) + { + // We don't want to run the full + // IdlInterface.prototype.test_instance_of, because that could result + // in an infinite loop. TODO: This means we don't have tests for + // NoInterfaceObject interfaces, and we also can't test objects that + // come from another self. + assert_in_array(typeof value, ["object", "function"], "wrong type: not object or function"); + if (value instanceof Object + && !this.members[type].has_extended_attribute("NoInterfaceObject") + && type in self) + { + assert_true(value instanceof self[type], "instanceof " + type); + } + } + else if (this.members[type] instanceof IdlEnum) + { + assert_equals(typeof value, "string"); + } + else if (this.members[type] instanceof IdlDictionary) + { + // TODO: Test when we actually have something to test this on + } + else + { + throw new IdlHarnessError("Type " + type + " isn't an interface or dictionary"); + } +}; + +/// IdlObject /// +function IdlObject() {} +IdlObject.prototype.test = function() +{ + /** + * By default, this does nothing, so no actual tests are run for IdlObjects + * that don't define any (e.g., IdlDictionary at the time of this writing). + */ +}; + +IdlObject.prototype.has_extended_attribute = function(name) +{ + /** + * This is only meaningful for things that support extended attributes, + * such as interfaces, exceptions, and members. + */ + return this.extAttrs.some(function(o) + { + return o.name == name; + }); +}; + + +/// IdlDictionary /// +// Used for IdlArray.prototype.assert_type_is +function IdlDictionary(obj) +{ + /** + * obj is an object produced by the WebIDLParser.js "dictionary" + * production. + */ + + /** Self-explanatory. */ + this.name = obj.name; + + /** A back-reference to our IdlArray. */ + this.array = obj.array; + + /** An array of objects produced by the "dictionaryMember" production. */ + this.members = obj.members; + + /** + * The name (as a string) of the dictionary type we inherit from, or null + * if there is none. + */ + this.base = obj.inheritance; +} + +IdlDictionary.prototype = Object.create(IdlObject.prototype); + +IdlDictionary.prototype.get_inheritance_stack = function() { + return IdlInterface.prototype.get_inheritance_stack.call(this); +}; + +/// IdlInterface /// +function IdlInterface(obj, is_callback, is_mixin) +{ + /** + * obj is an object produced by the WebIDLParser.js "interface" production. + */ + + /** Self-explanatory. */ + this.name = obj.name; + + /** A back-reference to our IdlArray. */ + this.array = obj.array; + + /** + * An indicator of whether we should run tests on the interface object and + * interface prototype object. Tests on members are controlled by .untested + * on each member, not this. + */ + this.untested = obj.untested; + + /** An array of objects produced by the "ExtAttr" production. */ + this.extAttrs = obj.extAttrs; + + /** An array of IdlInterfaceMembers. */ + this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); }); + if (this.has_extended_attribute("Unforgeable")) { + this.members + .filter(function(m) { return !m["static"] && (m.type == "attribute" || m.type == "operation"); }) + .forEach(function(m) { return m.isUnforgeable = true; }); + } + + /** + * The name (as a string) of the type we inherit from, or null if there is + * none. + */ + this.base = obj.inheritance; + + this._is_callback = is_callback; + this._is_mixin = is_mixin; +} +IdlInterface.prototype = Object.create(IdlObject.prototype); +IdlInterface.prototype.is_callback = function() +{ + return this._is_callback; +}; + +IdlInterface.prototype.is_mixin = function() +{ + return this._is_mixin; +}; + +IdlInterface.prototype.has_constants = function() +{ + return this.members.some(function(member) { + return member.type === "const"; + }); +}; + +IdlInterface.prototype.get_unscopables = function() +{ + return this.members.filter(function(member) { + return member.isUnscopable; + }); +}; + +IdlInterface.prototype.is_global = function() +{ + return this.extAttrs.some(function(attribute) { + return attribute.name === "Global"; + }); +}; + +/** + * Value of the LegacyNamespace extended attribute, if any. + * + * https://heycam.github.io/webidl/#LegacyNamespace + */ +IdlInterface.prototype.get_legacy_namespace = function() +{ + var legacyNamespace = this.extAttrs.find(function(attribute) { + return attribute.name === "LegacyNamespace"; + }); + return legacyNamespace ? legacyNamespace.rhs.value : undefined; +}; + +IdlInterface.prototype.get_interface_object_owner = function() +{ + var legacyNamespace = this.get_legacy_namespace(); + return legacyNamespace ? self[legacyNamespace] : self; +}; + +IdlInterface.prototype.assert_interface_object_exists = function() +{ + var owner = this.get_legacy_namespace() || "self"; + assert_own_property(self[owner], this.name, owner + " does not have own property " + format_value(this.name)); +}; + +IdlInterface.prototype.get_interface_object = function() { + if (this.has_extended_attribute("NoInterfaceObject")) { + throw new IdlHarnessError(this.name + " has no interface object due to NoInterfaceObject"); + } + + return this.get_interface_object_owner()[this.name]; +}; + +IdlInterface.prototype.get_qualified_name = function() { + // https://heycam.github.io/webidl/#qualified-name + var legacyNamespace = this.get_legacy_namespace(); + if (legacyNamespace) { + return legacyNamespace + "." + this.name; + } + return this.name; +}; + +IdlInterface.prototype.has_to_json_regular_operation = function() { + return this.members.some(function(m) { + return m.is_to_json_regular_operation(); + }); +}; + +IdlInterface.prototype.has_default_to_json_regular_operation = function() { + return this.members.some(function(m) { + return m.is_to_json_regular_operation() && m.has_extended_attribute("Default"); + }); +}; + +IdlInterface.prototype.get_inheritance_stack = function() { + /** + * See https://heycam.github.io/webidl/#create-an-inheritance-stack + * + * Returns an array of IdlInterface objects which contains itself + * and all of its inherited interfaces. + * + * So given: + * + * A : B {}; + * B : C {}; + * C {}; + * + * then A.get_inheritance_stack() should return [A, B, C], + * and B.get_inheritance_stack() should return [B, C]. + * + * Note: as dictionary inheritance is expressed identically by the AST, + * this works just as well for getting a stack of inherited dictionaries. + */ + + var stack = [this]; + var idl_interface = this; + while (idl_interface.base) { + var base = this.array.members[idl_interface.base]; + if (!base) { + throw new Error(idl_interface.type + " " + idl_interface.base + " not found (inherited by " + idl_interface.name + ")"); + } else if (stack.indexOf(base) > -1) { + stack.push(base); + let dep_chain = stack.map(i => i.name).join(','); + throw new IdlHarnessError(`${this.name} has a circular dependency: ${dep_chain}`); + } + idl_interface = base; + stack.push(idl_interface); + } + return stack; +}; + +/** + * Implementation of + * https://heycam.github.io/webidl/#default-tojson-operation + * for testing purposes. + * + * Collects the IDL types of the attributes that meet the criteria + * for inclusion in the default toJSON operation for easy + * comparison with actual value + */ +IdlInterface.prototype.default_to_json_operation = function(callback) { + var map = new Map(), isDefault = false; + this.traverse_inherited_and_consequential_interfaces(function(I) { + if (I.has_default_to_json_regular_operation()) { + isDefault = true; + I.members.forEach(function(m) { + if (!m.static && m.type == "attribute" && I.array.is_json_type(m.idlType)) { + map.set(m.name, m.idlType); + } + }); + } else if (I.has_to_json_regular_operation()) { + isDefault = false; + } + }); + return isDefault ? map : null; +}; + +/** + * Traverses inherited interfaces from the top down + * and imeplemented interfaces inside out. + * Invokes |callback| on each interface. + * + * This is an abstract implementation of the traversal + * algorithm specified in: + * https://heycam.github.io/webidl/#collect-attribute-values + * Given the following inheritance tree: + * + * F + * | + * C E - I + * | | + * B - D + * | + * G - A - H - J + * + * Invoking traverse_inherited_and_consequential_interfaces() on A + * would traverse the tree in the following order: + * C -> B -> F -> E -> I -> D -> A -> G -> H -> J + */ + +IdlInterface.prototype.traverse_inherited_and_consequential_interfaces = function(callback) { + if (typeof callback != "function") { + throw new TypeError(); + } + var stack = this.get_inheritance_stack(); + _traverse_inherited_and_consequential_interfaces(stack, callback); +}; + +function _traverse_inherited_and_consequential_interfaces(stack, callback) { + var I = stack.pop(); + callback(I); + var mixins = I.array["implements"][I.name] || I.array["includes"][I.name]; + if (mixins) { + mixins.forEach(function(id) { + var mixin = I.array.members[id]; + if (!mixin) { + throw new Error("Interface " + id + " not found (implemented by " + I.name + ")"); + } + var interfaces = mixin.get_inheritance_stack(); + _traverse_inherited_and_consequential_interfaces(interfaces, callback); + }); + } + if (stack.length > 0) { + _traverse_inherited_and_consequential_interfaces(stack, callback); + } +} + +IdlInterface.prototype.test = function() +{ + if (this.has_extended_attribute("NoInterfaceObject") || this.is_mixin()) + { + // No tests to do without an instance. TODO: We should still be able + // to run tests on the prototype object, if we obtain one through some + // other means. + return; + } + + if (!this.exposed) { + subsetTestByKey(this.name, test, function() { + assert_false(this.name in self); + }.bind(this), this.name + " interface: existence and properties of interface object"); + return; + } + + if (!this.untested) + { + // First test things to do with the exception/interface object and + // exception/interface prototype object. + this.test_self(); + } + // Then test things to do with its members (constants, fields, attributes, + // operations, . . .). These are run even if .untested is true, because + // members might themselves be marked as .untested. This might happen to + // interfaces if the interface itself is untested but a partial interface + // that extends it is tested -- then the interface itself and its initial + // members will be marked as untested, but the members added by the partial + // interface are still tested. + this.test_members(); +}; + +IdlInterface.prototype.test_self = function() +{ + subsetTestByKey(this.name, test, function() + { + // This function tests WebIDL as of 2015-01-13. + + // "For every interface that is exposed in a given ECMAScript global + // environment and: + // * is a callback interface that has constants declared on it, or + // * is a non-callback interface that is not declared with the + // [NoInterfaceObject] extended attribute, + // a corresponding property MUST exist on the ECMAScript global object. + // The name of the property is the identifier of the interface, and its + // value is an object called the interface object. + // The property has the attributes { [[Writable]]: true, + // [[Enumerable]]: false, [[Configurable]]: true }." + if (this.is_callback() && !this.has_constants()) { + return; + } + + // TODO: Should we test here that the property is actually writable + // etc., or trust getOwnPropertyDescriptor? + this.assert_interface_object_exists(); + var desc = Object.getOwnPropertyDescriptor(this.get_interface_object_owner(), this.name); + assert_false("get" in desc, "self's property " + format_value(this.name) + " should not have a getter"); + assert_false("set" in desc, "self's property " + format_value(this.name) + " should not have a setter"); + assert_true(desc.writable, "self's property " + format_value(this.name) + " should be writable"); + assert_false(desc.enumerable, "self's property " + format_value(this.name) + " should not be enumerable"); + assert_true(desc.configurable, "self's property " + format_value(this.name) + " should be configurable"); + + if (this.is_callback()) { + // "The internal [[Prototype]] property of an interface object for + // a callback interface must be the Function.prototype object." + assert_equals(Object.getPrototypeOf(this.get_interface_object()), Function.prototype, + "prototype of self's property " + format_value(this.name) + " is not Object.prototype"); + + return; + } + + // "The interface object for a given non-callback interface is a + // function object." + // "If an object is defined to be a function object, then it has + // characteristics as follows:" + + // Its [[Prototype]] internal property is otherwise specified (see + // below). + + // "* Its [[Get]] internal property is set as described in ECMA-262 + // section 9.1.8." + // Not much to test for this. + + // "* Its [[Construct]] internal property is set as described in + // ECMA-262 section 19.2.2.3." + // Tested below if no constructor is defined. TODO: test constructors + // if defined. + + // "* Its @@hasInstance property is set as described in ECMA-262 + // section 19.2.3.8, unless otherwise specified." + // TODO + + // ES6 (rev 30) 19.1.3.6: + // "Else, if O has a [[Call]] internal method, then let builtinTag be + // "Function"." + assert_class_string(this.get_interface_object(), "Function", "class string of " + this.name); + + // "The [[Prototype]] internal property of an interface object for a + // non-callback interface is determined as follows:" + var prototype = Object.getPrototypeOf(this.get_interface_object()); + if (this.base) { + // "* If the interface inherits from some other interface, the + // value of [[Prototype]] is the interface object for that other + // interface." + var inherited_interface = this.array.members[this.base]; + if (!inherited_interface.has_extended_attribute("NoInterfaceObject")) { + inherited_interface.assert_interface_object_exists(); + assert_equals(prototype, inherited_interface.get_interface_object(), + 'prototype of ' + this.name + ' is not ' + + this.base); + } + } else { + // "If the interface doesn't inherit from any other interface, the + // value of [[Prototype]] is %FunctionPrototype% ([ECMA-262], + // section 6.1.7.4)." + assert_equals(prototype, Function.prototype, + "prototype of self's property " + format_value(this.name) + " is not Function.prototype"); + } + + if (!this.has_extended_attribute("Constructor")) { + // "The internal [[Call]] method of the interface object behaves as + // follows . . . + // + // "If I was not declared with a [Constructor] extended attribute, + // then throw a TypeError." + var interface_object = this.get_interface_object(); + assert_throws(new TypeError(), function() { + interface_object(); + }, "interface object didn't throw TypeError when called as a function"); + assert_throws(new TypeError(), function() { + new interface_object(); + }, "interface object didn't throw TypeError when called as a constructor"); + } + }.bind(this), this.name + " interface: existence and properties of interface object"); + + if (!this.is_callback()) { + subsetTestByKey(this.name, test, function() { + // This function tests WebIDL as of 2014-10-25. + // https://heycam.github.io/webidl/#es-interface-call + + this.assert_interface_object_exists(); + + // "Interface objects for non-callback interfaces MUST have a + // property named “length” with attributes { [[Writable]]: false, + // [[Enumerable]]: false, [[Configurable]]: true } whose value is + // a Number." + assert_own_property(this.get_interface_object(), "length"); + var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "length"); + assert_false("get" in desc, this.name + ".length should not have a getter"); + assert_false("set" in desc, this.name + ".length should not have a setter"); + assert_false(desc.writable, this.name + ".length should not be writable"); + assert_false(desc.enumerable, this.name + ".length should not be enumerable"); + assert_true(desc.configurable, this.name + ".length should be configurable"); + + var constructors = this.extAttrs + .filter(function(attr) { return attr.name == "Constructor"; }); + var expected_length = minOverloadLength(constructors); + assert_equals(this.get_interface_object().length, expected_length, "wrong value for " + this.name + ".length"); + }.bind(this), this.name + " interface object length"); + } + + if (!this.is_callback() || this.has_constants()) { + subsetTestByKey(this.name, test, function() { + // This function tests WebIDL as of 2015-11-17. + // https://heycam.github.io/webidl/#interface-object + + this.assert_interface_object_exists(); + + // "All interface objects must have a property named “name” with + // attributes { [[Writable]]: false, [[Enumerable]]: false, + // [[Configurable]]: true } whose value is the identifier of the + // corresponding interface." + + assert_own_property(this.get_interface_object(), "name"); + var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "name"); + assert_false("get" in desc, this.name + ".name should not have a getter"); + assert_false("set" in desc, this.name + ".name should not have a setter"); + assert_false(desc.writable, this.name + ".name should not be writable"); + assert_false(desc.enumerable, this.name + ".name should not be enumerable"); + assert_true(desc.configurable, this.name + ".name should be configurable"); + assert_equals(this.get_interface_object().name, this.name, "wrong value for " + this.name + ".name"); + }.bind(this), this.name + " interface object name"); + } + + + if (this.has_extended_attribute("LegacyWindowAlias")) { + subsetTestByKey(this.name, test, function() + { + var aliasAttrs = this.extAttrs.filter(function(o) { return o.name === "LegacyWindowAlias"; }); + if (aliasAttrs.length > 1) { + throw new IdlHarnessError("Invalid IDL: multiple LegacyWindowAlias extended attributes on " + this.name); + } + if (this.is_callback()) { + throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on non-interface " + this.name); + } + if (!this.exposureSet.has("Window")) { + throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on " + this.name + " which is not exposed in Window"); + } + // TODO: when testing of [NoInterfaceObject] interfaces is supported, + // check that it's not specified together with LegacyWindowAlias. + + // TODO: maybe check that [LegacyWindowAlias] is not specified on a partial interface. + + var rhs = aliasAttrs[0].rhs; + if (!rhs) { + throw new IdlHarnessError("Invalid IDL: LegacyWindowAlias extended attribute on " + this.name + " without identifier"); + } + var aliases; + if (rhs.type === "identifier-list") { + aliases = rhs.value; + } else { // rhs.type === identifier + aliases = [ rhs.value ]; + } + + // OK now actually check the aliases... + var alias; + if (exposed_in(exposure_set(this, this.exposureSet)) && 'document' in self) { + for (alias of aliases) { + assert_true(alias in self, alias + " should exist"); + assert_equals(self[alias], this.get_interface_object(), "self." + alias + " should be the same value as self." + this.get_qualified_name()); + var desc = Object.getOwnPropertyDescriptor(self, alias); + assert_equals(desc.value, this.get_interface_object(), "wrong value in " + alias + " property descriptor"); + assert_true(desc.writable, alias + " should be writable"); + assert_false(desc.enumerable, alias + " should not be enumerable"); + assert_true(desc.configurable, alias + " should be configurable"); + assert_false('get' in desc, alias + " should not have a getter"); + assert_false('set' in desc, alias + " should not have a setter"); + } + } else { + for (alias of aliases) { + assert_false(alias in self, alias + " should not exist"); + } + } + + }.bind(this), this.name + " interface: legacy window alias"); + } + // TODO: Test named constructors if I find any interfaces that have them. + + subsetTestByKey(this.name, test, function() + { + // This function tests WebIDL as of 2015-01-21. + // https://heycam.github.io/webidl/#interface-object + + if (this.is_callback() && !this.has_constants()) { + return; + } + + this.assert_interface_object_exists(); + + if (this.is_callback()) { + assert_false("prototype" in this.get_interface_object(), + this.name + ' should not have a "prototype" property'); + return; + } + + // "An interface object for a non-callback interface must have a + // property named “prototype” with attributes { [[Writable]]: false, + // [[Enumerable]]: false, [[Configurable]]: false } whose value is an + // object called the interface prototype object. This object has + // properties that correspond to the regular attributes and regular + // operations defined on the interface, and is described in more detail + // in section 4.5.4 below." + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "prototype"); + assert_false("get" in desc, this.name + ".prototype should not have a getter"); + assert_false("set" in desc, this.name + ".prototype should not have a setter"); + assert_false(desc.writable, this.name + ".prototype should not be writable"); + assert_false(desc.enumerable, this.name + ".prototype should not be enumerable"); + assert_false(desc.configurable, this.name + ".prototype should not be configurable"); + + // Next, test that the [[Prototype]] of the interface prototype object + // is correct. (This is made somewhat difficult by the existence of + // [NoInterfaceObject].) + // TODO: Aryeh thinks there's at least other place in this file where + // we try to figure out if an interface prototype object is + // correct. Consolidate that code. + + // "The interface prototype object for a given interface A must have an + // internal [[Prototype]] property whose value is returned from the + // following steps: + // "If A is declared with the [Global] extended + // attribute, and A supports named properties, then return the named + // properties object for A, as defined in §3.6.4 Named properties + // object. + // "Otherwise, if A is declared to inherit from another interface, then + // return the interface prototype object for the inherited interface. + // "Otherwise, return %ObjectPrototype%. + // + // "In the ECMAScript binding, the DOMException type has some additional + // requirements: + // + // "Unlike normal interface types, the interface prototype object + // for DOMException must have as its [[Prototype]] the intrinsic + // object %ErrorPrototype%." + // + if (this.name === "Window") { + assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype), + 'WindowProperties', + 'Class name for prototype of Window' + + '.prototype is not "WindowProperties"'); + } else { + var inherit_interface, inherit_interface_interface_object; + if (this.base) { + inherit_interface = this.base; + var parent = this.array.members[inherit_interface]; + if (!parent.has_extended_attribute("NoInterfaceObject")) { + parent.assert_interface_object_exists(); + inherit_interface_interface_object = parent.get_interface_object(); + } + } else if (this.name === "DOMException") { + inherit_interface = 'Error'; + inherit_interface_interface_object = self.Error; + } else { + inherit_interface = 'Object'; + inherit_interface_interface_object = self.Object; + } + if (inherit_interface_interface_object) { + assert_not_equals(inherit_interface_interface_object, undefined, + 'should inherit from ' + inherit_interface + ', but there is no such property'); + assert_own_property(inherit_interface_interface_object, 'prototype', + 'should inherit from ' + inherit_interface + ', but that object has no "prototype" property'); + assert_equals(Object.getPrototypeOf(this.get_interface_object().prototype), + inherit_interface_interface_object.prototype, + 'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype'); + } else { + // We can't test that we get the correct object, because this is the + // only way to get our hands on it. We only test that its class + // string, at least, is correct. + assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype), + inherit_interface + 'Prototype', + 'Class name for prototype of ' + this.name + + '.prototype is not "' + inherit_interface + 'Prototype"'); + } + } + + // "The class string of an interface prototype object is the + // concatenation of the interface’s qualified identifier and the string + // “Prototype”." + + // Skip these tests for now due to a specification issue about + // prototype name. + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244 + + // assert_class_string(this.get_interface_object().prototype, this.get_qualified_name() + "Prototype", + // "class string of " + this.name + ".prototype"); + + // String() should end up calling {}.toString if nothing defines a + // stringifier. + if (!this.has_stringifier()) { + // assert_equals(String(this.get_interface_object().prototype), "[object " + this.get_qualified_name() + "Prototype]", + // "String(" + this.name + ".prototype)"); + } + }.bind(this), this.name + " interface: existence and properties of interface prototype object"); + + // "If the interface is declared with the [Global] + // extended attribute, or the interface is in the set of inherited + // interfaces for any other interface that is declared with one of these + // attributes, then the interface prototype object must be an immutable + // prototype exotic object." + // https://heycam.github.io/webidl/#interface-prototype-object + if (this.is_global()) { + this.test_immutable_prototype("interface prototype object", this.get_interface_object().prototype); + } + + subsetTestByKey(this.name, test, function() + { + if (this.is_callback() && !this.has_constants()) { + return; + } + + this.assert_interface_object_exists(); + + if (this.is_callback()) { + assert_false("prototype" in this.get_interface_object(), + this.name + ' should not have a "prototype" property'); + return; + } + + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + + // "If the [NoInterfaceObject] extended attribute was not specified on + // the interface, then the interface prototype object must also have a + // property named “constructor” with attributes { [[Writable]]: true, + // [[Enumerable]]: false, [[Configurable]]: true } whose value is a + // reference to the interface object for the interface." + assert_own_property(this.get_interface_object().prototype, "constructor", + this.name + '.prototype does not have own property "constructor"'); + var desc = Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, "constructor"); + assert_false("get" in desc, this.name + ".prototype.constructor should not have a getter"); + assert_false("set" in desc, this.name + ".prototype.constructor should not have a setter"); + assert_true(desc.writable, this.name + ".prototype.constructor should be writable"); + assert_false(desc.enumerable, this.name + ".prototype.constructor should not be enumerable"); + assert_true(desc.configurable, this.name + ".prototype.constructor should be configurable"); + assert_equals(this.get_interface_object().prototype.constructor, this.get_interface_object(), + this.name + '.prototype.constructor is not the same object as ' + this.name); + }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property'); + + + subsetTestByKey(this.name, test, function() + { + if (this.is_callback() && !this.has_constants()) { + return; + } + + this.assert_interface_object_exists(); + + if (this.is_callback()) { + assert_false("prototype" in this.get_interface_object(), + this.name + ' should not have a "prototype" property'); + return; + } + + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + + // If the interface has any member declared with the [Unscopable] extended + // attribute, then there must be a property on the interface prototype object + // whose name is the @@unscopables symbol, which has the attributes + // { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }, + // and whose value is an object created as follows... + var unscopables = this.get_unscopables().map(m => m.name); + var proto = this.get_interface_object().prototype; + if (unscopables.length != 0) { + assert_own_property( + proto, Symbol.unscopables, + this.name + '.prototype should have an @@unscopables property'); + var desc = Object.getOwnPropertyDescriptor(proto, Symbol.unscopables); + assert_false("get" in desc, + this.name + ".prototype[Symbol.unscopables] should not have a getter"); + assert_false("set" in desc, this.name + ".prototype[Symbol.unscopables] should not have a setter"); + assert_false(desc.writable, this.name + ".prototype[Symbol.unscopables] should not be writable"); + assert_false(desc.enumerable, this.name + ".prototype[Symbol.unscopables] should not be enumerable"); + assert_true(desc.configurable, this.name + ".prototype[Symbol.unscopables] should be configurable"); + assert_equals(desc.value, proto[Symbol.unscopables], + this.name + '.prototype[Symbol.unscopables] should be in the descriptor'); + assert_equals(typeof desc.value, "object", + this.name + '.prototype[Symbol.unscopables] should be an object'); + assert_equals(Object.getPrototypeOf(desc.value), null, + this.name + '.prototype[Symbol.unscopables] should have a null prototype'); + assert_equals(Object.getOwnPropertySymbols(desc.value).length, + 0, + this.name + '.prototype[Symbol.unscopables] should have the right number of symbol-named properties'); + + // Check that we do not have _extra_ unscopables. Checking that we + // have all the ones we should will happen in the per-member tests. + var observed = Object.getOwnPropertyNames(desc.value); + for (var prop of observed) { + assert_not_equals(unscopables.indexOf(prop), + -1, + this.name + '.prototype[Symbol.unscopables] has unexpected property "' + prop + '"'); + } + } else { + assert_equals(Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, Symbol.unscopables), + undefined, + this.name + '.prototype should not have @@unscopables'); + } + }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s @@unscopables property'); +}; + +IdlInterface.prototype.test_immutable_prototype = function(type, obj) +{ + if (typeof Object.setPrototypeOf !== "function") { + return; + } + + subsetTestByKey(this.name, test, function(t) { + var originalValue = Object.getPrototypeOf(obj); + var newValue = Object.create(null); + + t.add_cleanup(function() { + try { + Object.setPrototypeOf(obj, originalValue); + } catch (err) {} + }); + + assert_throws(new TypeError(), function() { + Object.setPrototypeOf(obj, newValue); + }); + + assert_equals( + Object.getPrototypeOf(obj), + originalValue, + "original value not modified" + ); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to a new value via Object.setPrototypeOf " + + "should throw a TypeError"); + + subsetTestByKey(this.name, test, function(t) { + var originalValue = Object.getPrototypeOf(obj); + var newValue = Object.create(null); + + t.add_cleanup(function() { + var setter = Object.getOwnPropertyDescriptor( + Object.prototype, '__proto__' + ).set; + + try { + setter.call(obj, originalValue); + } catch (err) {} + }); + + assert_throws(new TypeError(), function() { + obj.__proto__ = newValue; + }); + + assert_equals( + Object.getPrototypeOf(obj), + originalValue, + "original value not modified" + ); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to a new value via __proto__ " + + "should throw a TypeError"); + + subsetTestByKey(this.name, test, function(t) { + var originalValue = Object.getPrototypeOf(obj); + var newValue = Object.create(null); + + t.add_cleanup(function() { + try { + Reflect.setPrototypeOf(obj, originalValue); + } catch (err) {} + }); + + assert_false(Reflect.setPrototypeOf(obj, newValue)); + + assert_equals( + Object.getPrototypeOf(obj), + originalValue, + "original value not modified" + ); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to a new value via Reflect.setPrototypeOf " + + "should return false"); + + subsetTestByKey(this.name, test, function() { + var originalValue = Object.getPrototypeOf(obj); + + Object.setPrototypeOf(obj, originalValue); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to its original value via Object.setPrototypeOf " + + "should not throw"); + + subsetTestByKey(this.name, test, function() { + var originalValue = Object.getPrototypeOf(obj); + + obj.__proto__ = originalValue; + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to its original value via __proto__ " + + "should not throw"); + + subsetTestByKey(this.name, test, function() { + var originalValue = Object.getPrototypeOf(obj); + + assert_true(Reflect.setPrototypeOf(obj, originalValue)); + }.bind(this), this.name + " interface: internal [[SetPrototypeOf]] method " + + "of " + type + " - setting to its original value via Reflect.setPrototypeOf " + + "should return true"); +}; + +IdlInterface.prototype.test_member_const = function(member) +{ + if (!this.has_constants()) { + throw new IdlHarnessError("Internal error: test_member_const called without any constants"); + } + + subsetTestByKey(this.name, test, function() + { + this.assert_interface_object_exists(); + + // "For each constant defined on an interface A, there must be + // a corresponding property on the interface object, if it + // exists." + assert_own_property(this.get_interface_object(), member.name); + // "The value of the property is that which is obtained by + // converting the constant’s IDL value to an ECMAScript + // value." + assert_equals(this.get_interface_object()[member.name], constValue(member.value), + "property has wrong value"); + // "The property has attributes { [[Writable]]: false, + // [[Enumerable]]: true, [[Configurable]]: false }." + var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name); + assert_false("get" in desc, "property should not have a getter"); + assert_false("set" in desc, "property should not have a setter"); + assert_false(desc.writable, "property should not be writable"); + assert_true(desc.enumerable, "property should be enumerable"); + assert_false(desc.configurable, "property should not be configurable"); + }.bind(this), this.name + " interface: constant " + member.name + " on interface object"); + + // "In addition, a property with the same characteristics must + // exist on the interface prototype object." + subsetTestByKey(this.name, test, function() + { + this.assert_interface_object_exists(); + + if (this.is_callback()) { + assert_false("prototype" in this.get_interface_object(), + this.name + ' should not have a "prototype" property'); + return; + } + + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + + assert_own_property(this.get_interface_object().prototype, member.name); + assert_equals(this.get_interface_object().prototype[member.name], constValue(member.value), + "property has wrong value"); + var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name); + assert_false("get" in desc, "property should not have a getter"); + assert_false("set" in desc, "property should not have a setter"); + assert_false(desc.writable, "property should not be writable"); + assert_true(desc.enumerable, "property should be enumerable"); + assert_false(desc.configurable, "property should not be configurable"); + }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object"); +}; + + +IdlInterface.prototype.test_member_attribute = function(member) + { + if (!shouldRunSubTest(this.name)) { + return; + } + var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: attribute " + member.name); + a_test.step(function() + { + if (this.is_callback() && !this.has_constants()) { + a_test.done() + return; + } + + this.assert_interface_object_exists(); + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + + if (member["static"]) { + assert_own_property(this.get_interface_object(), member.name, + "The interface object must have a property " + + format_value(member.name)); + a_test.done(); + return; + } + + this.do_member_unscopable_asserts(member); + + if (this.is_global()) { + assert_own_property(self, member.name, + "The global object must have a property " + + format_value(member.name)); + assert_false(member.name in this.get_interface_object().prototype, + "The prototype object should not have a property " + + format_value(member.name)); + + var getter = Object.getOwnPropertyDescriptor(self, member.name).get; + assert_equals(typeof(getter), "function", + format_value(member.name) + " must have a getter"); + + // Try/catch around the get here, since it can legitimately throw. + // If it does, we obviously can't check for equality with direct + // invocation of the getter. + var gotValue; + var propVal; + try { + propVal = self[member.name]; + gotValue = true; + } catch (e) { + gotValue = false; + } + if (gotValue) { + assert_equals(propVal, getter.call(undefined), + "Gets on a global should not require an explicit this"); + } + + // do_interface_attribute_asserts must be the last thing we do, + // since it will call done() on a_test. + this.do_interface_attribute_asserts(self, member, a_test); + } else { + assert_true(member.name in this.get_interface_object().prototype, + "The prototype object must have a property " + + format_value(member.name)); + + if (!member.has_extended_attribute("LenientThis")) { + if (member.idlType.generic !== "Promise") { + assert_throws(new TypeError(), function() { + this.get_interface_object().prototype[member.name]; + }.bind(this), "getting property on prototype object must throw TypeError"); + // do_interface_attribute_asserts must be the last thing we + // do, since it will call done() on a_test. + this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test); + } else { + promise_rejects(a_test, new TypeError(), + this.get_interface_object().prototype[member.name]) + .then(function() { + // do_interface_attribute_asserts must be the last + // thing we do, since it will call done() on a_test. + this.do_interface_attribute_asserts(this.get_interface_object().prototype, + member, a_test); + }.bind(this)); + } + } else { + assert_equals(this.get_interface_object().prototype[member.name], undefined, + "getting property on prototype object must return undefined"); + // do_interface_attribute_asserts must be the last thing we do, + // since it will call done() on a_test. + this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test); + } + } + }.bind(this)); +}; + +IdlInterface.prototype.test_member_operation = function(member) +{ + if (!shouldRunSubTest(this.name)) { + return; + } + var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: operation " + member.name + + "(" + member.arguments.map( + function(m) {return m.idlType.idlType; } ).join(", ") + +")"); + a_test.step(function() + { + // This function tests WebIDL as of 2015-12-29. + // https://heycam.github.io/webidl/#es-operations + + if (this.is_callback() && !this.has_constants()) { + a_test.done(); + return; + } + + this.assert_interface_object_exists(); + + if (this.is_callback()) { + assert_false("prototype" in this.get_interface_object(), + this.name + ' should not have a "prototype" property'); + a_test.done(); + return; + } + + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + + // "For each unique identifier of an exposed operation defined on the + // interface, there must exist a corresponding property, unless the + // effective overload set for that identifier and operation and with an + // argument count of 0 has no entries." + + // TODO: Consider [Exposed]. + + // "The location of the property is determined as follows:" + var memberHolderObject; + // "* If the operation is static, then the property exists on the + // interface object." + if (member["static"]) { + assert_own_property(this.get_interface_object(), member.name, + "interface object missing static operation"); + memberHolderObject = this.get_interface_object(); + // "* Otherwise, [...] if the interface was declared with the [Global] + // extended attribute, then the property exists + // on every object that implements the interface." + } else if (this.is_global()) { + assert_own_property(self, member.name, + "global object missing non-static operation"); + memberHolderObject = self; + // "* Otherwise, the property exists solely on the interface’s + // interface prototype object." + } else { + assert_own_property(this.get_interface_object().prototype, member.name, + "interface prototype object missing non-static operation"); + memberHolderObject = this.get_interface_object().prototype; + } + this.do_member_unscopable_asserts(member); + this.do_member_operation_asserts(memberHolderObject, member, a_test); + }.bind(this)); +}; + +IdlInterface.prototype.do_member_unscopable_asserts = function(member) +{ + // Check that if the member is unscopable then it's in the + // @@unscopables object properly. + if (!member.isUnscopable) { + return; + } + + var unscopables = this.get_interface_object().prototype[Symbol.unscopables]; + var prop = member.name; + var propDesc = Object.getOwnPropertyDescriptor(unscopables, prop); + assert_equals(typeof propDesc, "object", + this.name + '.prototype[Symbol.unscopables].' + prop + ' must exist') + assert_false("get" in propDesc, + this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no getter'); + assert_false("set" in propDesc, + this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no setter'); + assert_true(propDesc.writable, + this.name + '.prototype[Symbol.unscopables].' + prop + ' must be writable'); + assert_true(propDesc.enumerable, + this.name + '.prototype[Symbol.unscopables].' + prop + ' must be enumerable'); + assert_true(propDesc.configurable, + this.name + '.prototype[Symbol.unscopables].' + prop + ' must be configurable'); + assert_equals(propDesc.value, true, + this.name + '.prototype[Symbol.unscopables].' + prop + ' must have the value `true`'); +}; + +IdlInterface.prototype.do_member_operation_asserts = function(memberHolderObject, member, a_test) +{ + var done = a_test.done.bind(a_test); + var operationUnforgeable = member.isUnforgeable; + var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name); + // "The property has attributes { [[Writable]]: B, + // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the + // operation is unforgeable on the interface, and true otherwise". + assert_false("get" in desc, "property should not have a getter"); + assert_false("set" in desc, "property should not have a setter"); + assert_equals(desc.writable, !operationUnforgeable, + "property should be writable if and only if not unforgeable"); + assert_true(desc.enumerable, "property should be enumerable"); + assert_equals(desc.configurable, !operationUnforgeable, + "property should be configurable if and only if not unforgeable"); + // "The value of the property is a Function object whose + // behavior is as follows . . ." + assert_equals(typeof memberHolderObject[member.name], "function", + "property must be a function"); + + const ctors = this.members.filter(function(m) { + return m.type == "operation" && m.name == member.name; + }); + assert_equals( + memberHolderObject[member.name].length, + minOverloadLength(ctors), + "property has wrong .length"); + + // Make some suitable arguments + var args = member.arguments.map(function(arg) { + return create_suitable_object(arg.idlType); + }); + + // "Let O be a value determined as follows: + // ". . . + // "Otherwise, throw a TypeError." + // This should be hit if the operation is not static, there is + // no [ImplicitThis] attribute, and the this value is null. + // + // TODO: We currently ignore the [ImplicitThis] case. Except we manually + // check for globals, since otherwise we'll invoke window.close(). And we + // have to skip this test for anything that on the proto chain of "self", + // since that does in fact have implicit-this behavior. + if (!member["static"]) { + var cb; + if (!this.is_global() && + memberHolderObject[member.name] != self[member.name]) + { + cb = awaitNCallbacks(2, done); + throwOrReject(a_test, member, memberHolderObject[member.name], null, args, + "calling operation with this = null didn't throw TypeError", cb); + } else { + cb = awaitNCallbacks(1, done); + } + + // ". . . If O is not null and is also not a platform object + // that implements interface I, throw a TypeError." + // + // TODO: Test a platform object that implements some other + // interface. (Have to be sure to get inheritance right.) + throwOrReject(a_test, member, memberHolderObject[member.name], {}, args, + "calling operation with this = {} didn't throw TypeError", cb); + } else { + done(); + } +} + +IdlInterface.prototype.add_iterable_members = function(member) +{ + this.members.push(new IdlInterfaceMember( + { type: "operation", name: "entries", idlType: "iterator", arguments: []})); + this.members.push(new IdlInterfaceMember( + { type: "operation", name: "keys", idlType: "iterator", arguments: []})); + this.members.push(new IdlInterfaceMember( + { type: "operation", name: "values", idlType: "iterator", arguments: []})); + this.members.push(new IdlInterfaceMember( + { type: "operation", name: "forEach", idlType: "void", + arguments: + [{ name: "callback", idlType: {idlType: "function"}}, + { name: "thisValue", idlType: {idlType: "any"}, optional: true}]})); +}; + +IdlInterface.prototype.test_to_json_operation = function(memberHolderObject, member) { + var instanceName = memberHolderObject && memberHolderObject.constructor.name + || member.name + " object"; + if (member.has_extended_attribute("Default")) { + subsetTestByKey(this.name, test, function() { + var map = this.default_to_json_operation(); + var json = memberHolderObject.toJSON(); + map.forEach(function(type, k) { + assert_true(k in json, "property " + JSON.stringify(k) + " should be present in the output of " + this.name + ".prototype.toJSON()"); + var descriptor = Object.getOwnPropertyDescriptor(json, k); + assert_true(descriptor.writable, "property " + k + " should be writable"); + assert_true(descriptor.configurable, "property " + k + " should be configurable"); + assert_true(descriptor.enumerable, "property " + k + " should be enumerable"); + this.array.assert_type_is(json[k], type); + delete json[k]; + }, this); + }.bind(this), "Test default toJSON operation of " + instanceName); + } else { + subsetTestByKey(this.name, test, function() { + assert_true(this.array.is_json_type(member.idlType), JSON.stringify(member.idlType) + " is not an appropriate return value for the toJSON operation of " + instanceName); + this.array.assert_type_is(memberHolderObject.toJSON(), member.idlType); + }.bind(this), "Test toJSON operation of " + instanceName); + } +}; + +IdlInterface.prototype.test_member_iterable = function(member) +{ + var isPairIterator = member.idlType.length === 2; + subsetTestByKey(this.name, test, function() + { + var descriptor = Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, Symbol.iterator); + assert_true(descriptor.writable, "property should be writable"); + assert_true(descriptor.configurable, "property should be configurable"); + assert_false(descriptor.enumerable, "property should not be enumerable"); + assert_equals(this.get_interface_object().prototype[Symbol.iterator].name, isPairIterator ? "entries" : "values", "@@iterator function does not have the right name"); + }.bind(this), "Testing Symbol.iterator property of iterable interface " + this.name); + + if (isPairIterator) { + subsetTestByKey(this.name, test, function() { + assert_equals(this.get_interface_object().prototype[Symbol.iterator], this.get_interface_object().prototype["entries"], "entries method is not the same as @@iterator"); + }.bind(this), "Testing pair iterable interface " + this.name); + } else { + subsetTestByKey(this.name, test, function() { + ["entries", "keys", "values", "forEach", Symbol.Iterator].forEach(function(property) { + assert_equals(this.get_interface_object().prototype[property], Array.prototype[property], property + " function is not the same as Array one"); + }.bind(this)); + }.bind(this), "Testing value iterable interface " + this.name); + } +}; + +IdlInterface.prototype.test_member_stringifier = function(member) +{ + subsetTestByKey(this.name, test, function() + { + if (this.is_callback() && !this.has_constants()) { + return; + } + + this.assert_interface_object_exists(); + + if (this.is_callback()) { + assert_false("prototype" in this.get_interface_object(), + this.name + ' should not have a "prototype" property'); + return; + } + + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + + // ". . . the property exists on the interface prototype object." + var interfacePrototypeObject = this.get_interface_object().prototype; + assert_own_property(interfacePrototypeObject, "toString", + "interface prototype object missing non-static operation"); + + var stringifierUnforgeable = member.isUnforgeable; + var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, "toString"); + // "The property has attributes { [[Writable]]: B, + // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the + // stringifier is unforgeable on the interface, and true otherwise." + assert_false("get" in desc, "property should not have a getter"); + assert_false("set" in desc, "property should not have a setter"); + assert_equals(desc.writable, !stringifierUnforgeable, + "property should be writable if and only if not unforgeable"); + assert_true(desc.enumerable, "property should be enumerable"); + assert_equals(desc.configurable, !stringifierUnforgeable, + "property should be configurable if and only if not unforgeable"); + // "The value of the property is a Function object, which behaves as + // follows . . ." + assert_equals(typeof interfacePrototypeObject.toString, "function", + "property must be a function"); + // "The value of the Function object’s “length” property is the Number + // value 0." + assert_equals(interfacePrototypeObject.toString.length, 0, + "property has wrong .length"); + + // "Let O be the result of calling ToObject on the this value." + assert_throws(new TypeError(), function() { + interfacePrototypeObject.toString.apply(null, []); + }, "calling stringifier with this = null didn't throw TypeError"); + + // "If O is not an object that implements the interface on which the + // stringifier was declared, then throw a TypeError." + // + // TODO: Test a platform object that implements some other + // interface. (Have to be sure to get inheritance right.) + assert_throws(new TypeError(), function() { + interfacePrototypeObject.toString.apply({}, []); + }, "calling stringifier with this = {} didn't throw TypeError"); + }.bind(this), this.name + " interface: stringifier"); +}; + +IdlInterface.prototype.test_members = function() +{ + for (var i = 0; i < this.members.length; i++) + { + var member = this.members[i]; + switch (member.type) { + case "iterable": + this.add_iterable_members(member); + break; + // TODO: add setlike and maplike handling. + default: + break; + } + } + + for (var i = 0; i < this.members.length; i++) + { + var member = this.members[i]; + if (member.untested) { + continue; + } + + if (!exposed_in(exposure_set(member, this.exposureSet))) { + subsetTestByKey(this.name, test, function() { + // It's not exposed, so we shouldn't find it anywhere. + assert_false(member.name in this.get_interface_object(), + "The interface object must not have a property " + + format_value(member.name)); + assert_false(member.name in this.get_interface_object().prototype, + "The prototype object must not have a property " + + format_value(member.name)); + }.bind(this), this.name + " interface: member " + member.name); + continue; + } + + switch (member.type) { + case "const": + this.test_member_const(member); + break; + + case "attribute": + // For unforgeable attributes, we do the checks in + // test_interface_of instead. + if (!member.isUnforgeable) + { + this.test_member_attribute(member); + } + if (member.stringifier) { + this.test_member_stringifier(member); + } + break; + + case "operation": + // TODO: Need to correctly handle multiple operations with the same + // identifier. + // For unforgeable operations, we do the checks in + // test_interface_of instead. + if (member.name) { + if (!member.isUnforgeable) + { + this.test_member_operation(member); + } + } else if (member.stringifier) { + this.test_member_stringifier(member); + } + break; + + case "iterable": + this.test_member_iterable(member); + break; + default: + // TODO: check more member types. + break; + } + } +}; + +IdlInterface.prototype.test_object = function(desc) +{ + var obj, exception = null; + try + { + obj = eval(desc); + } + catch(e) + { + exception = e; + } + + var expected_typeof = + this.members.some(function(member) { return member.legacycaller; }) + ? "function" + : "object"; + + this.test_primary_interface_of(desc, obj, exception, expected_typeof); + + var current_interface = this; + while (current_interface) + { + if (!(current_interface.name in this.array.members)) + { + throw new IdlHarnessError("Interface " + current_interface.name + " not found (inherited by " + this.name + ")"); + } + if (current_interface.prevent_multiple_testing && current_interface.already_tested) + { + return; + } + current_interface.test_interface_of(desc, obj, exception, expected_typeof); + current_interface = this.array.members[current_interface.base]; + } +}; + +IdlInterface.prototype.test_primary_interface_of = function(desc, obj, exception, expected_typeof) +{ + // Only the object itself, not its members, are tested here, so if the + // interface is untested, there is nothing to do. + if (this.untested) + { + return; + } + + // "The internal [[SetPrototypeOf]] method of every platform object that + // implements an interface with the [Global] extended + // attribute must execute the same algorithm as is defined for the + // [[SetPrototypeOf]] internal method of an immutable prototype exotic + // object." + // https://heycam.github.io/webidl/#platform-object-setprototypeof + if (this.is_global()) + { + this.test_immutable_prototype("global platform object", obj); + } + + + // We can't easily test that its prototype is correct if there's no + // interface object, or the object is from a different global environment + // (not instanceof Object). TODO: test in this case that its prototype at + // least looks correct, even if we can't test that it's actually correct. + if (!this.has_extended_attribute("NoInterfaceObject") + && (typeof obj != expected_typeof || obj instanceof Object)) + { + subsetTestByKey(this.name, test, function() + { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_equals(typeof obj, expected_typeof, "wrong typeof object"); + this.assert_interface_object_exists(); + assert_own_property(this.get_interface_object(), "prototype", + 'interface "' + this.name + '" does not have own property "prototype"'); + + // "The value of the internal [[Prototype]] property of the + // platform object is the interface prototype object of the primary + // interface from the platform object’s associated global + // environment." + assert_equals(Object.getPrototypeOf(obj), + this.get_interface_object().prototype, + desc + "'s prototype is not " + this.name + ".prototype"); + }.bind(this), this.name + " must be primary interface of " + desc); + } + + // "The class string of a platform object that implements one or more + // interfaces must be the qualified name of the primary interface of the + // platform object." + subsetTestByKey(this.name, test, function() + { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_equals(typeof obj, expected_typeof, "wrong typeof object"); + assert_class_string(obj, this.get_qualified_name(), "class string of " + desc); + if (!this.has_stringifier()) + { + assert_equals(String(obj), "[object " + this.get_qualified_name() + "]", "String(" + desc + ")"); + } + }.bind(this), "Stringification of " + desc); +}; + +IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expected_typeof) +{ + // TODO: Indexed and named properties, more checks on interface members + this.already_tested = true; + if (!shouldRunSubTest(this.name)) { + return; + } + + for (var i = 0; i < this.members.length; i++) + { + var member = this.members[i]; + if (member.untested) { + continue; + } + if (!exposed_in(exposure_set(member, this.exposureSet))) { + subsetTestByKey(this.name, test, function() { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_false(member.name in obj); + }.bind(this), this.name + " interface: " + desc + ' must not have property "' + member.name + '"'); + continue; + } + if (member.type == "attribute" && member.isUnforgeable) + { + var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: " + desc + ' must have own property "' + member.name + '"'); + a_test.step(function() { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_equals(typeof obj, expected_typeof, "wrong typeof object"); + // Call do_interface_attribute_asserts last, since it will call a_test.done() + this.do_interface_attribute_asserts(obj, member, a_test); + }.bind(this)); + } + else if (member.type == "operation" && + member.name && + member.isUnforgeable) + { + var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: " + desc + ' must have own property "' + member.name + '"'); + a_test.step(function() + { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_equals(typeof obj, expected_typeof, "wrong typeof object"); + assert_own_property(obj, member.name, + "Doesn't have the unforgeable operation property"); + this.do_member_operation_asserts(obj, member, a_test); + }.bind(this)); + } + else if ((member.type == "const" + || member.type == "attribute" + || member.type == "operation") + && member.name) + { + var described_name = member.name; + if (member.type == "operation") + { + described_name += "(" + member.arguments.map(arg => arg.idlType.idlType).join(", ") + ")"; + } + subsetTestByKey(this.name, test, function() + { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_equals(typeof obj, expected_typeof, "wrong typeof object"); + if (!member["static"]) { + if (!this.is_global()) { + assert_inherits(obj, member.name); + } else { + assert_own_property(obj, member.name); + } + + if (member.type == "const") + { + assert_equals(obj[member.name], constValue(member.value)); + } + if (member.type == "attribute") + { + // Attributes are accessor properties, so they might + // legitimately throw an exception rather than returning + // anything. + var property, thrown = false; + try + { + property = obj[member.name]; + } + catch (e) + { + thrown = true; + } + if (!thrown) + { + this.array.assert_type_is(property, member.idlType); + } + } + if (member.type == "operation") + { + assert_equals(typeof obj[member.name], "function"); + } + } + }.bind(this), this.name + " interface: " + desc + ' must inherit property "' + described_name + '" with the proper type'); + } + // TODO: This is wrong if there are multiple operations with the same + // identifier. + // TODO: Test passing arguments of the wrong type. + if (member.type == "operation" && member.name && member.arguments.length) + { + var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: calling " + member.name + + "(" + member.arguments.map(function(m) { return m.idlType.idlType; }).join(", ") + + ") on " + desc + " with too few arguments must throw TypeError"); + a_test.step(function() + { + assert_equals(exception, null, "Unexpected exception when evaluating object"); + assert_equals(typeof obj, expected_typeof, "wrong typeof object"); + var fn; + if (!member["static"]) { + if (!this.is_global() && !member.isUnforgeable) { + assert_inherits(obj, member.name); + } else { + assert_own_property(obj, member.name); + } + fn = obj[member.name]; + } + else + { + assert_own_property(obj.constructor, member.name, "interface object must have static operation as own property"); + fn = obj.constructor[member.name]; + } + + var minLength = minOverloadLength(this.members.filter(function(m) { + return m.type == "operation" && m.name == member.name; + })); + var args = []; + var cb = awaitNCallbacks(minLength, a_test.done.bind(a_test)); + for (var i = 0; i < minLength; i++) { + throwOrReject(a_test, member, fn, obj, args, "Called with " + i + " arguments", cb); + + args.push(create_suitable_object(member.arguments[i].idlType)); + } + if (minLength === 0) { + cb(); + } + }.bind(this)); + } + + if (member.is_to_json_regular_operation()) { + this.test_to_json_operation(obj, member); + } + } +}; + +IdlInterface.prototype.has_stringifier = function() +{ + if (this.name === "DOMException") { + // toString is inherited from Error, so don't assume we have the + // default stringifer + return true; + } + if (this.members.some(function(member) { return member.stringifier; })) { + return true; + } + if (this.base && + this.array.members[this.base].has_stringifier()) { + return true; + } + return false; +}; + +IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member, a_test) +{ + // This function tests WebIDL as of 2015-01-27. + // TODO: Consider [Exposed]. + + // This is called by test_member_attribute() with the prototype as obj if + // it is not a global, and the global otherwise, and by test_interface_of() + // with the object as obj. + + var pendingPromises = []; + + // "For each exposed attribute of the interface, whether it was declared on + // the interface itself or one of its consequential interfaces, there MUST + // exist a corresponding property. The characteristics of this property are + // as follows:" + + // "The name of the property is the identifier of the attribute." + assert_own_property(obj, member.name); + + // "The property has attributes { [[Get]]: G, [[Set]]: S, [[Enumerable]]: + // true, [[Configurable]]: configurable }, where: + // "configurable is false if the attribute was declared with the + // [Unforgeable] extended attribute and true otherwise; + // "G is the attribute getter, defined below; and + // "S is the attribute setter, also defined below." + var desc = Object.getOwnPropertyDescriptor(obj, member.name); + assert_false("value" in desc, 'property descriptor should not have a "value" field'); + assert_false("writable" in desc, 'property descriptor should not have a "writable" field'); + assert_true(desc.enumerable, "property should be enumerable"); + if (member.isUnforgeable) + { + assert_false(desc.configurable, "[Unforgeable] property must not be configurable"); + } + else + { + assert_true(desc.configurable, "property must be configurable"); + } + + + // "The attribute getter is a Function object whose behavior when invoked + // is as follows:" + assert_equals(typeof desc.get, "function", "getter must be Function"); + + // "If the attribute is a regular attribute, then:" + if (!member["static"]) { + // "If O is not a platform object that implements I, then: + // "If the attribute was specified with the [LenientThis] extended + // attribute, then return undefined. + // "Otherwise, throw a TypeError." + if (!member.has_extended_attribute("LenientThis")) { + if (member.idlType.generic !== "Promise") { + assert_throws(new TypeError(), function() { + desc.get.call({}); + }.bind(this), "calling getter on wrong object type must throw TypeError"); + } else { + pendingPromises.push( + promise_rejects(a_test, new TypeError(), desc.get.call({}), + "calling getter on wrong object type must reject the return promise with TypeError")); + } + } else { + assert_equals(desc.get.call({}), undefined, + "calling getter on wrong object type must return undefined"); + } + } + + // "The value of the Function object’s “length” property is the Number + // value 0." + assert_equals(desc.get.length, 0, "getter length must be 0"); + + // "Let name be the string "get " prepended to attribute’s identifier." + // "Perform ! SetFunctionName(F, name)." + assert_equals(desc.get.name, "get " + member.name, + "getter must have the name 'get " + member.name + "'"); + + + // TODO: Test calling setter on the interface prototype (should throw + // TypeError in most cases). + if (member.readonly + && !member.has_extended_attribute("LenientSetter") + && !member.has_extended_attribute("PutForwards") + && !member.has_extended_attribute("Replaceable")) + { + // "The attribute setter is undefined if the attribute is declared + // readonly and has neither a [PutForwards] nor a [Replaceable] + // extended attribute declared on it." + assert_equals(desc.set, undefined, "setter must be undefined for readonly attributes"); + } + else + { + // "Otherwise, it is a Function object whose behavior when + // invoked is as follows:" + assert_equals(typeof desc.set, "function", "setter must be function for PutForwards, Replaceable, or non-readonly attributes"); + + // "If the attribute is a regular attribute, then:" + if (!member["static"]) { + // "If /validThis/ is false and the attribute was not specified + // with the [LenientThis] extended attribute, then throw a + // TypeError." + // "If the attribute is declared with a [Replaceable] extended + // attribute, then: ..." + // "If validThis is false, then return." + if (!member.has_extended_attribute("LenientThis")) { + assert_throws(new TypeError(), function() { + desc.set.call({}); + }.bind(this), "calling setter on wrong object type must throw TypeError"); + } else { + assert_equals(desc.set.call({}), undefined, + "calling setter on wrong object type must return undefined"); + } + } + + // "The value of the Function object’s “length” property is the Number + // value 1." + assert_equals(desc.set.length, 1, "setter length must be 1"); + + // "Let name be the string "set " prepended to id." + // "Perform ! SetFunctionName(F, name)." + assert_equals(desc.set.name, "set " + member.name, + "The attribute setter must have the name 'set " + member.name + "'"); + } + + Promise.all(pendingPromises).then(a_test.done.bind(a_test)); +} + +/// IdlInterfaceMember /// +function IdlInterfaceMember(obj) +{ + /** + * obj is an object produced by the WebIDLParser.js "ifMember" production. + * We just forward all properties to this object without modification, + * except for special extAttrs handling. + */ + for (var k in obj) + { + this[k] = obj[k]; + } + if (!("extAttrs" in this)) + { + this.extAttrs = []; + } + + this.isUnforgeable = this.has_extended_attribute("Unforgeable"); + this.isUnscopable = this.has_extended_attribute("Unscopable"); +} + +IdlInterfaceMember.prototype = Object.create(IdlObject.prototype); + +IdlInterfaceMember.prototype.is_to_json_regular_operation = function() { + return this.type == "operation" && !this.static && this.name == "toJSON"; +}; + +/// Internal helper functions /// +function create_suitable_object(type) +{ + /** + * type is an object produced by the WebIDLParser.js "type" production. We + * return a JavaScript value that matches the type, if we can figure out + * how. + */ + if (type.nullable) + { + return null; + } + switch (type.idlType) + { + case "any": + case "boolean": + return true; + + case "byte": case "octet": case "short": case "unsigned short": + case "long": case "unsigned long": case "long long": + case "unsigned long long": case "float": case "double": + case "unrestricted float": case "unrestricted double": + return 7; + + case "DOMString": + case "ByteString": + case "USVString": + return "foo"; + + case "object": + return {a: "b"}; + + case "Node": + return document.createTextNode("abc"); + } + return null; +} + +/// IdlEnum /// +// Used for IdlArray.prototype.assert_type_is +function IdlEnum(obj) +{ + /** + * obj is an object produced by the WebIDLParser.js "dictionary" + * production. + */ + + /** Self-explanatory. */ + this.name = obj.name; + + /** An array of values produced by the "enum" production. */ + this.values = obj.values; + +} + +IdlEnum.prototype = Object.create(IdlObject.prototype); + +/// IdlTypedef /// +// Used for IdlArray.prototype.assert_type_is +function IdlTypedef(obj) +{ + /** + * obj is an object produced by the WebIDLParser.js "typedef" + * production. + */ + + /** Self-explanatory. */ + this.name = obj.name; + + /** The idlType that we are supposed to be typedeffing to. */ + this.idlType = obj.idlType; + +} + +IdlTypedef.prototype = Object.create(IdlObject.prototype); + +/// IdlNamespace /// +function IdlNamespace(obj) +{ + this.name = obj.name; + this.extAttrs = obj.extAttrs; + this.untested = obj.untested; + /** A back-reference to our IdlArray. */ + this.array = obj.array; + + /** An array of IdlInterfaceMembers. */ + this.members = obj.members.map(m => new IdlInterfaceMember(m)); +} + +IdlNamespace.prototype = Object.create(IdlObject.prototype); + +IdlNamespace.prototype.do_member_operation_asserts = function (memberHolderObject, member, a_test) +{ + var desc = Object.getOwnPropertyDescriptor(memberHolderObject, member.name); + + assert_false("get" in desc, "property should not have a getter"); + assert_false("set" in desc, "property should not have a setter"); + assert_equals( + desc.writable, + !member.isUnforgeable, + "property should be writable if and only if not unforgeable"); + assert_true(desc.enumerable, "property should be enumerable"); + assert_equals( + desc.configurable, + !member.isUnforgeable, + "property should be configurable if and only if not unforgeable"); + + assert_equals( + typeof memberHolderObject[member.name], + "function", + "property must be a function"); + + assert_equals( + memberHolderObject[member.name].length, + minOverloadLength(this.members.filter(function(m) { + return m.type == "operation" && m.name == member.name; + })), + "operation has wrong .length"); + a_test.done(); +} + +IdlNamespace.prototype.test_member_operation = function(member) +{ + if (!shouldRunSubTest(this.name)) { + return; + } + var args = member.arguments.map(function(a) { + var s = a.idlType.idlType; + if (a.variadic) { + s += '...'; + } + return s; + }).join(", "); + var a_test = subsetTestByKey( + this.name, + async_test, + this.name + ' namespace: operation ' + member.name + '(' + args + ')'); + a_test.step(function() { + assert_own_property( + self[this.name], + member.name, + 'namespace object missing operation ' + format_value(member.name)); + + this.do_member_operation_asserts(self[this.name], member, a_test); + }.bind(this)); +}; + +IdlNamespace.prototype.test_member_attribute = function (member) +{ + if (!shouldRunSubTest(this.name)) { + return; + } + var a_test = subsetTestByKey( + this.name, + async_test, + this.name + ' namespace: attribute ' + member.name); + a_test.step(function() + { + assert_own_property( + self[this.name], + member.name, + this.name + ' does not have property ' + format_value(member.name)); + + var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name); + assert_equals(desc.set, undefined, "setter must be undefined for namespace members"); + a_test.done(); + }.bind(this)); +}; + +IdlNamespace.prototype.test = function () +{ + /** + * TODO(lukebjerring): Assert: + * - "Note that unlike interfaces or dictionaries, namespaces do not create types." + * - "Of the extended attributes defined in this specification, only the + * [Exposed] and [SecureContext] extended attributes are applicable to namespaces." + * - "Namespaces must be annotated with the [Exposed] extended attribute." + */ + + for (const v of Object.values(this.members)) { + switch (v.type) { + + case 'operation': + this.test_member_operation(v); + break; + + case 'attribute': + this.test_member_attribute(v); + break; + + default: + throw 'Invalid namespace member ' + v.name + ': ' + v.type + ' not supported'; + } + }; +}; + +}()); + +/** + * idl_test is a promise_test wrapper that handles the fetching of the IDL, + * avoiding repetitive boilerplate. + * + * @param {String|String[]} srcs Spec name(s) for source idl files (fetched from + * /interfaces/{name}.idl). + * @param {String|String[]} deps Spec name(s) for dependency idl files (fetched + * from /interfaces/{name}.idl). Order is important - dependencies from + * each source will only be included if they're already know to be a + * dependency (i.e. have already been seen). + * @param {Function} setup_func Function for extra setup of the idl_array, such + * as adding objects. Do not call idl_array.test() in the setup; it is + * called by this function (idl_test). + */ +function idl_test(srcs, deps, idl_setup_func) { + return promise_test(function (t) { + var idl_array = new IdlArray(); + srcs = (srcs instanceof Array) ? srcs : [srcs] || []; + deps = (deps instanceof Array) ? deps : [deps] || []; + var setup_error = null; + return Promise.all( + srcs.concat(deps).map(function(spec) { + return fetch_spec(spec); + })) + .then(function(idls) { + for (var i = 0; i < srcs.length; i++) { + idl_array.add_idls(idls[i]); + } + for (var i = srcs.length; i < srcs.length + deps.length; i++) { + idl_array.add_dependency_idls(idls[i]); + } + }) + .then(function() { + if (idl_setup_func) { + return idl_setup_func(idl_array, t); + } + }) + .catch(function(e) { setup_error = e || 'IDL setup failed.'; }) + .then(function () { + var error = setup_error; + try { + idl_array.test(); // Test what we can. + } catch (e) { + // If testing fails hard here, the original setup error + // is more likely to be the real cause. + error = error || e; + } + if (error) { + throw error; + } + }); + }, 'idl_test setup'); +} + +/** + * fetch_spec is a shorthand for a Promise that fetches the spec's content. + */ +function fetch_spec(spec) { + var url = '/interfaces/' + spec + '.idl'; + return fetch(url).then(function (r) { + if (!r.ok) { + throw new IdlHarnessError("Error fetching " + url + "."); + } + return r.text(); + }); +} +// vim: set expandtab shiftwidth=4 tabstop=4 foldmarker=@{,@} foldmethod=marker: diff --git a/test/fixtures/wpt/resources/idlharness.js.headers b/test/fixtures/wpt/resources/idlharness.js.headers new file mode 100644 index 00000000000000..5e8f640c6659d1 --- /dev/null +++ b/test/fixtures/wpt/resources/idlharness.js.headers @@ -0,0 +1,2 @@ +Content-Type: text/javascript; charset=utf-8 +Cache-Control: max-age=3600 diff --git a/test/fixtures/wpt/resources/readme.md b/test/fixtures/wpt/resources/readme.md new file mode 100644 index 00000000000000..97d2e6f92203d1 --- /dev/null +++ b/test/fixtures/wpt/resources/readme.md @@ -0,0 +1,26 @@ +# Resources + +## `testharness.js` + +`testharness.js` is a framework for writing low-level tests of +browser functionality in javascript. It provides a convenient API for +making assertions and is intended to work for both simple synchronous +tests, and tests of asynchronous behaviour. + +### Getting started + +To use `testharness.js` you must include two scripts, in the order given: + +``` html + + +``` + +### Full documentation + +For detailed API documentation please visit [https://web-platform-tests.org/writing-tests/testharness-api.html](https://web-platform-tests.org/writing-tests/testharness-api.html). + +### Tutorials + +You can also read a tutorial on +[Using testharness.js](http://darobin.github.com/test-harness-tutorial/docs/using-testharness.html). diff --git a/test/fixtures/wpt/resources/sriharness.js b/test/fixtures/wpt/resources/sriharness.js new file mode 100644 index 00000000000000..b36d29223585ec --- /dev/null +++ b/test/fixtures/wpt/resources/sriharness.js @@ -0,0 +1,99 @@ +var SRIScriptTest = function(pass, name, src, integrityValue, crossoriginValue, nonce) { + this.pass = pass; + this.name = "Script: " + name; + this.src = src; + this.integrityValue = integrityValue; + this.crossoriginValue = crossoriginValue; + this.nonce = nonce; +} + +SRIScriptTest.prototype.execute = function() { + var test = async_test(this.name); + var e = document.createElement("script"); + e.src = this.src; + e.setAttribute("integrity", this.integrityValue); + if(this.crossoriginValue) { + e.setAttribute("crossorigin", this.crossoriginValue); + } + if(this.nonce) { + e.setAttribute("nonce", this.nonce); + } + if(this.pass) { + e.addEventListener("load", function() {test.done()}); + e.addEventListener("error", function() { + test.step(function(){ assert_unreached("Good load fired error handler.") }) + }); + } else { + e.addEventListener("load", function() { + test.step(function() { assert_unreached("Bad load succeeded.") }) + }); + e.addEventListener("error", function() {test.done()}); + } + document.body.appendChild(e); +}; + +// tests +// Style tests must be done synchronously because they rely on the presence +// and absence of global style, which can affect later tests. Thus, instead +// of executing them one at a time, the style tests are implemented as a +// queue that builds up a list of tests, and then executes them one at a +// time. +var SRIStyleTest = function(queue, pass, name, attrs, customCallback, altPassValue) { + this.pass = pass; + this.name = "Style: " + name; + this.customCallback = customCallback || function () {}; + this.attrs = attrs || {}; + this.passValue = altPassValue || "rgb(255, 255, 0)"; + + this.test = async_test(this.name); + + this.queue = queue; + this.queue.push(this); +} + +SRIStyleTest.prototype.execute = function() { + var that = this; + var container = document.getElementById("container"); + while (container.hasChildNodes()) { + container.removeChild(container.firstChild); + } + + var test = this.test; + + var div = document.createElement("div"); + div.className = "testdiv"; + var e = document.createElement("link"); + this.attrs.rel = this.attrs.rel || "stylesheet"; + for (var key in this.attrs) { + if (this.attrs.hasOwnProperty(key)) { + e.setAttribute(key, this.attrs[key]); + } + } + + if(this.pass) { + e.addEventListener("load", function() { + test.step(function() { + var background = window.getComputedStyle(div, null).getPropertyValue("background-color"); + assert_equals(background, that.passValue); + test.done(); + }); + }); + e.addEventListener("error", function() { + test.step(function(){ assert_unreached("Good load fired error handler.") }) + }); + } else { + e.addEventListener("load", function() { + test.step(function() { assert_unreached("Bad load succeeded.") }) + }); + e.addEventListener("error", function() { + test.step(function() { + var background = window.getComputedStyle(div, null).getPropertyValue("background-color"); + assert_not_equals(background, that.passValue); + test.done(); + }); + }); + } + container.appendChild(div); + container.appendChild(e); + this.customCallback(e, container); +}; diff --git a/test/fixtures/wpt/resources/testdriver-actions.js b/test/fixtures/wpt/resources/testdriver-actions.js new file mode 100644 index 00000000000000..46c68858e45746 --- /dev/null +++ b/test/fixtures/wpt/resources/testdriver-actions.js @@ -0,0 +1,391 @@ +(function() { + let sourceNameIdx = 0; + + /** + * Builder for creating a sequence of actions + */ + function Actions() { + this.sourceTypes = new Map([["key", KeySource], + ["pointer", PointerSource], + ["general", GeneralSource]]); + this.sources = new Map(); + this.sourceOrder = []; + for (let sourceType of this.sourceTypes.keys()) { + this.sources.set(sourceType, new Map()); + } + this.currentSources = new Map(); + for (let sourceType of this.sourceTypes.keys()) { + this.currentSources.set(sourceType, null); + } + this.createSource("general"); + this.tickIdx = 0; + } + + Actions.prototype = { + /** + * Generate the action sequence suitable for passing to + * test_driver.action_sequence + * + * @returns {Array} Array of WebDriver-compatible actions sequences + */ + serialize: function() { + let actions = []; + for (let [sourceType, sourceName] of this.sourceOrder) { + let source = this.sources.get(sourceType).get(sourceName); + let serialized = source.serialize(this.tickIdx + 1); + if (serialized) { + serialized.id = sourceName; + actions.push(serialized); + } + } + return actions; + }, + + /** + * Generate and send the action sequence + * + * @returns {Promise} fulfilled after the sequence is executed, + * rejected if any actions fail. + */ + send: function() { + let actions; + try { + actions = this.serialize(); + } catch(e) { + return Promise.reject(e); + } + return test_driver.action_sequence(actions); + }, + + /** + * Get the action source with a particular source type and name. + * If no name is passed, a new source with the given type is + * created. + * + * @param {String} type - Source type ('general', 'key', or 'pointer') + * @param {String?} name - Name of the source + * @returns {Source} Source object for that source. + */ + getSource: function(type, name) { + if (!this.sources.has(type)) { + throw new Error(`${type} is not a valid action type`); + } + if (name === null || name === undefined) { + name = this.currentSources.get(type); + } + if (name === null || name === undefined) { + return this.createSource(type, null); + } + return this.sources.get(type).get(name); + }, + + setSource: function(type, name) { + if (!this.sources.has(type)) { + throw new Error(`${type} is not a valid action type`); + } + if (!this.sources.get(type).has(name)) { + throw new Error(`${name} is not a valid source for ${type}`); + } + this.currentSources.set(type, name); + return this; + }, + + /** + * Add a new key input source with the given name + * + * @param {String} name - Name of the key source + * @param {Bool} set - Set source as the default key source + * @returns {Actions} + */ + addKeyboard: function(name, set=true) { + this.createSource("key", name, true); + if (set) { + this.setKeyboard(name); + } + return this; + }, + + /** + * Set the current default key source + * + * @param {String} name - Name of the key source + * @returns {Actions} + */ + setKeyboard: function(name) { + this.setSource("key", name); + return this; + }, + + /** + * Add a new pointer input source with the given name + * + * @param {String} type - Name of the key source + * @param {String} pointerType - Type of pointing device + * @param {Bool} set - Set source as the default key source + * @returns {Actions} + */ + addPointer: function(name, pointerType="mouse", set=true) { + this.createSource("pointer", name, true, {pointerType: pointerType}); + if (set) { + this.setPointer(name); + } + return this; + }, + + /** + * Set the current default pointer source + * + * @param {String} name - Name of the pointer source + * @returns {Actions} + */ + setPointer: function(name) { + this.setSource("pointer", name); + return this; + }, + + createSource: function(type, name, parameters={}) { + if (!this.sources.has(type)) { + throw new Error(`${type} is not a valid action type`); + } + let sourceNames = new Set(); + for (let [_, name] of this.sourceOrder) { + sourceNames.add(name); + } + if (!name) { + do { + name = "" + sourceNameIdx++; + } while (sourceNames.has(name)) + } else { + if (sourceNames.has(name)) { + throw new Error(`Alreay have a source of type ${type} named ${name}.`); + } + } + this.sources.get(type).set(name, new (this.sourceTypes.get(type))(parameters)); + this.currentSources.set(type, name); + this.sourceOrder.push([type, name]); + return this.sources.get(type).get(name); + }, + + /** + * Insert a new actions tick + * + * @param {Number?} duration - Minimum length of the tick in ms. + * @returns {Actions} + */ + addTick: function(duration) { + this.tickIdx += 1; + if (duration) { + this.pause(duration); + } + return this; + }, + + /** + * Add a pause to the current tick + * + * @param {Number?} duration - Minimum length of the tick in ms. + * @returns {Actions} + */ + pause: function(duration) { + this.getSource("general").addPause(this, duration); + return this; + }, + + /** + * Create a keyDown event for the current default key source + * + * @param {String} key - Key to press + * @param {String?} sourceName - Named key source to use or null for the default key source + * @returns {Actions} + */ + keyDown: function(key, {sourceName=null}={}) { + let source = this.getSource("key", sourceName); + source.keyDown(this, key); + return this; + }, + + /** + * Create a keyDown event for the current default key source + * + * @param {String} key - Key to release + * @param {String?} sourceName - Named key source to use or null for the default key source + * @returns {Actions} + */ + keyUp: function(key, {sourceName=null}={}) { + let source = this.getSource("key", sourceName); + source.keyUp(this, key); + return this; + }, + + /** + * Create a pointerDown event for the current default pointer source + * + * @param {String} button - Button to press + * @param {String?} sourceName - Named pointer source to use or null for the default + * pointer source + * @returns {Actions} + */ + pointerDown: function({button=0, sourceName=null}={}) { + let source = this.getSource("pointer", sourceName); + source.pointerDown(this, button); + return this; + }, + + /** + * Create a pointerUp event for the current default pointer source + * + * @param {String} button - Button to release + * @param {String?} sourceName - Named pointer source to use or null for the default pointer + * source + * @returns {Actions} + */ + pointerUp: function({button=0, sourceName=null}={}) { + let source = this.getSource("pointer", sourceName); + source.pointerUp(this, button); + return this; + }, + + /** + * Create a move event for the current default pointer source + * + * @param {Number} x - Destination x coordinate + * @param {Number} y - Destination y coordinate + * @param {String|Element} origin - Origin of the coordinate system. + * Either "pointer", "viewport" or an Element + * @param {Number?} duration - Time in ms for the move + * @param {String?} sourceName - Named pointer source to use or null for the default pointer + * source + * @returns {Actions} + */ + pointerMove: function(x, y, + {origin="viewport", duration, sourceName=null}={}) { + let source = this.getSource("pointer", sourceName); + source.pointerMove(this, x, y, duration, origin); + return this; + }, + }; + + function GeneralSource() { + this.actions = new Map(); + } + + GeneralSource.prototype = { + serialize: function(tickCount) { + if (!this.actions.size) { + return undefined; + } + let actions = []; + let data = {"type": "none", "actions": actions}; + for (let i=0; i
" + + (assertions ? "" : "") + + "" + + ""; + for (var i = 0; i < tests.length; i++) { + html += '"; + } + html += "
11Current
-11.1.0
+11.2.0
+11.1.0
11.0.0
@@ -129,10 +125,9 @@ release. ### Notes -* Release streams marked with `LTS` are currently covered by the - [Node.js Long Term Support plan](https://github.com/nodejs/Release). -* Release versions displayed in **bold** text represent the most - recent actively supported release. +* The [Node.js Long Term Support plan](https://github.com/nodejs/Release) covers + LTS releases. +* Release versions in **bold** text are the most recent supported releases. ---- ---- diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5a935352a1f9f0..4c211405596cb4 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,8 +1,4 @@ # Code of Conduct -The Node.js Code of Conduct document has moved to -https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md. Please update -links to this document accordingly. - -The Node.js Moderation policy can be found at -https://github.com/nodejs/admin/blob/master/Moderation-Policy.md +* [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md) +* [Node.js Moderation Policy](https://github.com/nodejs/admin/blob/master/Moderation-Policy.md) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 7cfc6388c549b5..ec3b0a8bf503fb 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -3,7 +3,6 @@ ## Contents * [Issues and Pull Requests](#issues-and-pull-requests) - - [Managing Issues and Pull Requests](#managing-issues-and-pull-requests) - [Welcoming First-Time Contributors](#welcoming-first-time-contributors) - [Closing Issues and Pull Requests](#closing-issues-and-pull-requests) - [Author ready pull requests](#author-ready-pull-requests) @@ -28,7 +27,7 @@ - [Using `git-node`](#using-git-node) - [Technical HOWTO](#technical-howto) - [Troubleshooting](#troubleshooting) - - [I Just Made a Mistake](#i-just-made-a-mistake) + - [I Made a Mistake](#i-made-a-mistake) - [Long Term Support](#long-term-support) - [What is LTS?](#what-is-lts) - [How does LTS work?](#how-does-lts-work) @@ -38,24 +37,16 @@ - [How is an LTS release cut?](#how-is-an-lts-release-cut) * [Who to CC in the issue tracker](#who-to-cc-in-the-issue-tracker) -This document contains information for Collaborators of the Node.js -project regarding managing the project's code, documentation, and issue tracker. - -Collaborators should be familiar with the guidelines for new -contributors in [CONTRIBUTING.md](./CONTRIBUTING.md) and also -understand the project governance model as outlined in -[GOVERNANCE.md](./GOVERNANCE.md). +This document explains how Collaborators manage the Node.js project. +Collaborators should understand the +[guidelines for new contributors](CONTRIBUTING.md) and the +[project governance model](GOVERNANCE.md). ## Issues and Pull Requests -### Managing Issues and Pull Requests - -Collaborators should take full responsibility for managing issues and pull -requests they feel qualified to handle. Make sure this is done while being -mindful of these guidelines, the opinions of other Collaborators, and guidance -of the [TSC][]. They may also notify other qualified parties for more input on -an issue or a pull request. -See [Who to CC in the issue tracker](#who-to-cc-in-the-issue-tracker). +Mind these guidelines, the opinions of other Collaborators, and guidance of the +[TSC][]. Notify other qualified parties for more input on an issue or a pull +request. See [Who to CC in the issue tracker](#who-to-cc-in-the-issue-tracker). ### Welcoming First-Time Contributors @@ -497,7 +488,7 @@ This should be done where a pull request: Assign the `tsc-review` label or @-mention the `@nodejs/tsc` GitHub team if you want to elevate an issue to the [TSC][]. -Do not use the GitHub UI on the right hand side to assign to +Do not use the GitHub UI on the right-hand side to assign to `@nodejs/tsc` or request a review from `@nodejs/tsc`. The TSC should serve as the final arbiter where required. @@ -528,7 +519,7 @@ The TSC should serve as the final arbiter where required. you are unsure exactly how to format the commit messages, use the commit log as a reference. See [this commit][commit-example] as an example. -For PRs from first time contributors, be [welcoming](#welcoming-first-time-contributors). +For PRs from first-time contributors, be [welcoming](#welcoming-first-time-contributors). Also, verify that their git settings are to their liking. All commits should be self-contained, meaning every commit should pass all @@ -747,7 +738,7 @@ make -j4 test git push upstream master ``` -### I Just Made a Mistake +### I Made a Mistake * Ping a TSC member. * `#node-dev` on freenode diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 684277980a8ee6..1a3babf8405ea2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,18 +1,5 @@ # Contributing to Node.js -Contributions to Node.js include code, documentation, answering user questions, -running the project's infrastructure, and advocating for all types of Node.js -users. - -The Node.js project welcomes all contributions from anyone willing to work in -good faith with other contributors and the community. No contribution is too -small and all contributions are valued. - -This guide explains the process for contributing to the Node.js project's core -`nodejs/node` GitHub Repository and describes what to expect at each step. - -## Contents - * [Code of Conduct](#code-of-conduct) * [Issues](#issues) * [Pull Requests](#pull-requests) @@ -22,16 +9,12 @@ This guide explains the process for contributing to the Node.js project's core The Node.js project has a [Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md) -that *all* contributors are expected to follow. This code describes the -*minimum* behavior expectations for all contributors. +to which all contributors must adhere. See [details on our policy on Code of Conduct](./doc/guides/contributing/coc.md). ## [Issues](./doc/guides/contributing/issues.md) -Issues in `nodejs/node` are the primary means by which bug reports and -general discussions are made. - * [How to Contribute in Issues](./doc/guides/contributing/issues.md#how-to-contribute-in-issues) * [Asking for General Help](./doc/guides/contributing/issues.md#asking-for-general-help) * [Discussing non-technical topics](./doc/guides/contributing/issues.md#discussing-non-technical-topics) @@ -41,14 +24,11 @@ general discussions are made. ## [Pull Requests](./doc/guides/contributing/pull-requests.md) -Pull Requests are the way concrete changes are made to the code, documentation, -dependencies, and tools contained in the `nodejs/node` repository. - * [Dependencies](./doc/guides/contributing/pull-requests.md#dependencies) * [Setting up your local environment](./doc/guides/contributing/pull-requests.md#setting-up-your-local-environment) * [The Process of Making Changes](./doc/guides/contributing/pull-requests.md#the-process-of-making-changes) * [Reviewing Pull Requests](./doc/guides/contributing/pull-requests.md#reviewing-pull-requests) -* [Additional Notes](./doc/guides/contributing/pull-requests.md#additional-notes) +* [Notes](./doc/guides/contributing/pull-requests.md#notes) ## Developer's Certificate of Origin 1.1 diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 40ef6e7bbe5fcb..d92d3c821e85b3 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -45,7 +45,7 @@ be accepted unless: * Discussions and/or additional changes result in no Collaborators objecting to the change. Previously-objecting Collaborators do not necessarily have to - sign-off on the change, but they should not be opposed to it. + sign off on the change, but they should not be opposed to it. * The change is escalated to the TSC and the TSC votes to approve the change. This should only happen if disagreements between Collaborators cannot be resolved through discussion. @@ -123,8 +123,8 @@ The meeting chair is responsible for ensuring that minutes are taken and that a pull request with the minutes is submitted after the meeting. Due to the challenges of scheduling a global meeting with participants in -several timezones, the TSC will seek to resolve as many agenda items as possible -outside of meetings using +several time zones, the TSC will seek to resolve as many agenda items as +possible outside of meetings using [the TSC issue tracker](https://github.com/nodejs/TSC/issues). The process in the issue tracker is: @@ -196,7 +196,7 @@ completed within a month after the nomination is accepted. ## Consensus Seeking Process -The TSC follows a [Consensus Seeking][] decision making model as described by +The TSC follows a [Consensus Seeking][] decision-making model as described by the [TSC Charter][]. [collaborators-discussions]: https://github.com/orgs/nodejs/teams/collaborators/discussions diff --git a/LICENSE b/LICENSE index b19517094f64db..59958b20e24a06 100644 --- a/LICENSE +++ b/LICENSE @@ -606,6 +606,32 @@ The externally maintained libraries used by Node.js are: n° 289016). Three clause BSD license. """ +- llhttp, located at deps/llhttp, is licensed as follows: + """ + This software is licensed under the MIT License. + + Copyright Fedor Indutny, 2018. + + 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. + """ + - OpenSSL, located at deps/openssl, is licensed as follows: """ Copyright (c) 1998-2018 The OpenSSL Project. All rights reserved. diff --git a/Makefile b/Makefile index 88be22fcace3ec..7c2afde30a3d28 100644 --- a/Makefile +++ b/Makefile @@ -205,7 +205,7 @@ coverage-build: all if [ ! -d node_modules/nyc ]; then \ $(NODE) ./deps/npm install nyc@13 --no-save --no-package-lock; fi if [ ! -d gcovr ]; then git clone -b 3.4 --depth=1 \ - --single-branch git://github.com/gcovr/gcovr.git; fi + --single-branch https://github.com/gcovr/gcovr.git; fi if [ ! -d build ]; then git clone --depth=1 \ --single-branch https://github.com/nodejs/build.git; fi if [ ! -f gcovr/scripts/gcovr.orig ]; then \ @@ -270,7 +270,7 @@ v8: tools/make-v8.sh $(V8_ARCH).$(BUILDTYPE_LOWER) $(V8_BUILD_OPTIONS) .PHONY: jstest -jstest: build-addons build-addons-napi bench-addons-build ## Runs addon tests and JS tests +jstest: build-addons build-addons-napi ## Runs addon tests and JS tests $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) \ --skip-tests=$(CI_SKIP_TESTS) \ $(CI_JS_SUITES) \ @@ -308,19 +308,19 @@ test-valgrind: all test-check-deopts: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) --check-deopts parallel sequential -benchmark/napi/function_call/build/Release/binding.node: all \ +benchmark/napi/function_call/build/$(BUILDTYPE)/binding.node: \ benchmark/napi/function_call/napi_binding.c \ benchmark/napi/function_call/binding.cc \ - benchmark/napi/function_call/binding.gyp + benchmark/napi/function_call/binding.gyp | all $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ --python="$(PYTHON)" \ --directory="$(shell pwd)/benchmark/napi/function_call" \ --nodedir="$(shell pwd)" -benchmark/napi/function_args/build/Release/binding.node: all \ +benchmark/napi/function_args/build/$(BUILDTYPE)/binding.node: \ benchmark/napi/function_args/napi_binding.c \ benchmark/napi/function_args/binding.cc \ - benchmark/napi/function_args/binding.gyp + benchmark/napi/function_args/binding.gyp | all $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ --python="$(PYTHON)" \ --directory="$(shell pwd)/benchmark/napi/function_args" \ @@ -332,16 +332,16 @@ ifeq ($(OSTYPE),aix) DOCBUILDSTAMP_PREREQS := $(DOCBUILDSTAMP_PREREQS) out/$(BUILDTYPE)/node.exp endif -node_use_openssl = $(shell $(call available-node,"-p" \ - "process.versions.openssl != undefined")) +node_use_openssl = $(call available-node,"-p" \ + "process.versions.openssl != undefined") test/addons/.docbuildstamp: $(DOCBUILDSTAMP_PREREQS) tools/doc/node_modules -ifeq ($(node_use_openssl),true) - $(RM) -r test/addons/??_*/ - [ -x $(NODE) ] && $(NODE) $< || node $< - touch $@ -else - @echo "Skipping .docbuildstamp (no crypto)" -endif + @if [ "$(shell $(node_use_openssl))" != "true" ]; then \ + echo "Skipping .docbuildstamp (no crypto)"; \ + else \ + $(RM) -r test/addons/??_*/; \ + [ -x $(NODE) ] && $(NODE) $< || node $< ; \ + touch $@; \ + fi ADDONS_BINDING_GYPS := \ $(filter-out test/addons/??_*/binding.gyp, \ @@ -414,7 +414,7 @@ clear-stalled: echo $${PS_OUT} | xargs kill -9; \ fi -test-build: | all build-addons build-addons-napi bench-addons-build +test-build: | all build-addons build-addons-napi test-build-addons-napi: all build-addons-napi @@ -496,7 +496,10 @@ test-debug: test-build test-message: test-build $(PYTHON) tools/test.py $(PARALLEL_ARGS) message -test-simple: | cctest bench-addons-build # Depends on 'all'. +test-wpt: all + $(PYTHON) tools/test.py $(PARALLEL_ARGS) wpt + +test-simple: | cctest # Depends on 'all'. $(PYTHON) tools/test.py $(PARALLEL_ARGS) parallel sequential test-pummel: all @@ -509,6 +512,9 @@ test-node-inspect: $(NODE_EXE) USE_EMBEDDED_NODE_INSPECT=1 $(NODE) tools/test-npm-package \ --install deps/node-inspect test +test-benchmark: | bench-addons-build + $(PYTHON) tools/test.py $(PARALLEL_ARGS) benchmark + test-tick-processor: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) tick-processor @@ -609,11 +615,11 @@ apidocs_json = $(addprefix out/,$(apidoc_sources:.md=.json)) apiassets = $(subst api_assets,api/assets,$(addprefix out/,$(wildcard doc/api_assets/*))) tools/doc/node_modules: tools/doc/package.json -ifeq ($(node_use_openssl),true) - cd tools/doc && $(call available-node,$(run-npm-ci)) -else - @echo "Skipping tools/doc/node_modules (no crypto)" -endif + @if [ "$(shell $(node_use_openssl))" != "true" ]; then \ + echo "Skipping tools/doc/node_modules (no crypto)"; \ + else \ + cd tools/doc && $(call available-node,$(run-npm-ci)) \ + fi .PHONY: doc-only doc-only: tools/doc/node_modules \ @@ -1044,8 +1050,8 @@ bench: bench-addons-build # Build required addons for benchmark before running it. .PHONY: bench-addons-build -bench-addons-build: benchmark/napi/function_call/build/Release/binding.node \ - benchmark/napi/function_args/build/Release/binding.node +bench-addons-build: benchmark/napi/function_call/build/$(BUILDTYPE)/binding.node \ + benchmark/napi/function_args/build/$(BUILDTYPE)/binding.node .PHONY: bench-addons-clean bench-addons-clean: diff --git a/README.md b/README.md index 671e5321450c7e..533b36bf8dbd58 100644 --- a/README.md +++ b/README.md @@ -159,43 +159,8 @@ source and a list of supported platforms. ## Security -If you find a security vulnerability in Node.js, please report it to -security@nodejs.org. Please withhold public disclosure until after the security -team has addressed the vulnerability. - -The security team will acknowledge your email within 24 hours. You will receive -a more detailed response within 48 hours. - -There are no hard and fast rules to determine if a bug is worth reporting as a -security issue. Here are some examples of past issues and what the Security -Response Team thinks of them. When in doubt, please do send us a report -nonetheless. - - -### Public disclosure preferred - -- [#14519](https://github.com/nodejs/node/issues/14519): _Internal domain - function can be used to cause segfaults_. Requires the ability to execute - arbitrary JavaScript code. That is already the highest level of privilege - possible. - -### Private disclosure preferred - -- [CVE-2016-7099](https://nodejs.org/en/blog/vulnerability/september-2016-security-releases/): - _Fix invalid wildcard certificate validation check_. This was a high-severity - defect. It caused Node.js TLS clients to accept invalid wildcard certificates. - -- [#5507](https://github.com/nodejs/node/pull/5507): _Fix a defect that makes - the CacheBleed Attack possible_. Many, though not all, OpenSSL vulnerabilities - in the TLS/SSL protocols also affect Node.js. - -- [CVE-2016-2216](https://nodejs.org/en/blog/vulnerability/february-2016-security-releases/): - _Fix defects in HTTP header parsing for requests and responses that can allow - response splitting_. This was a remotely-exploitable defect in the Node.js - HTTP implementation. - -When in doubt, please do send us a report. - +For information on reporting security vulnerabilities in Node.js, see +[SECURITY.md](./SECURITY.md). ## Current Project Team Members @@ -436,10 +401,14 @@ For information about the governance of the Node.js project, see **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) - **Minqi Pan** <pmq2001@gmail.com> * [princejwesley](https://github.com/princejwesley) - **Prince John Wesley** <princejohnwesley@gmail.com> +* [psmarshall](https://github.com/psmarshall) - +**Peter Marshall** <petermarshall@chromium.org> (he/him) * [Qard](https://github.com/Qard) - **Stephen Belanger** <admin@stephenbelanger.com> (he/him) * [refack](https://github.com/refack) - @@ -468,6 +437,8 @@ For information about the governance of the Node.js project, see **Nikolai Vavilov** <vvnicholas@gmail.com> * [shigeki](https://github.com/shigeki) - **Shigeki Ohtsu** <ohtsu@ohtsu.org> (he/him) +* [shisama](https://github.com/shisama) - +**Masashi Hirano** <shisama07@gmail.com> (he/him) * [silverwind](https://github.com/silverwind) - **Roman Reiss** <me@silverwind.io> * [srl295](https://github.com/srl295) - diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000000..5f1e3e2cc7d563 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,37 @@ +# Security + +If you find a security vulnerability in Node.js, please report it to +security@nodejs.org. Please withhold public disclosure until after the security +team has addressed the vulnerability. + +The security team will acknowledge your email within 24 hours. You will receive +a more detailed response within 48 hours. + +There are no hard and fast rules to determine if a bug is worth reporting as a +security issue. Here are some examples of past issues and what the Security +Response Team thinks of them. When in doubt, please do send us a report +nonetheless. + +## Public disclosure preferred + +- [#14519](https://github.com/nodejs/node/issues/14519): _Internal domain + function can be used to cause segfaults_. Requires the ability to execute + arbitrary JavaScript code. That is already the highest level of privilege + possible. + +## Private disclosure preferred + +- [CVE-2016-7099](https://nodejs.org/en/blog/vulnerability/september-2016-security-releases/): + _Fix invalid wildcard certificate validation check_. This was a high-severity + defect. It caused Node.js TLS clients to accept invalid wildcard certificates. + +- [#5507](https://github.com/nodejs/node/pull/5507): _Fix a defect that makes + the CacheBleed Attack possible_. Many, though not all, OpenSSL vulnerabilities + in the TLS/SSL protocols also affect Node.js. + +- [CVE-2016-2216](https://nodejs.org/en/blog/vulnerability/february-2016-security-releases/): + _Fix defects in HTTP header parsing for requests and responses that can allow + response splitting_. This was a remotely-exploitable defect in the Node.js + HTTP implementation. + +When in doubt, please do send us a report. diff --git a/benchmark/_http-benchmarkers.js b/benchmark/_http-benchmarkers.js index baa50f72cde906..f66c36ab1d3d19 100644 --- a/benchmark/_http-benchmarkers.js +++ b/benchmark/_http-benchmarkers.js @@ -35,7 +35,7 @@ class AutocannonBenchmarker { let result; try { result = JSON.parse(output); - } catch (err) { + } catch { return undefined; } if (!result || !result.requests || !result.requests.average) { @@ -106,7 +106,7 @@ class TestDoubleBenchmarker { let result; try { result = JSON.parse(output); - } catch (err) { + } catch { return undefined; } return result.throughput; diff --git a/benchmark/child_process/child-process-exec-stdout.js b/benchmark/child_process/child-process-exec-stdout.js index a891026b86971f..88c02533f605c2 100644 --- a/benchmark/child_process/child-process-exec-stdout.js +++ b/benchmark/child_process/child-process-exec-stdout.js @@ -30,7 +30,7 @@ function childProcessExecStdout({ dur, len }) { // Sometimes there's a yes.exe process left hanging around on Windows. try { execSync(`taskkill /f /t /pid ${child.pid}`); - } catch (_) { + } catch { // this is a best effort kill. stderr is piped to parent for tracing. } } else { diff --git a/benchmark/common.js b/benchmark/common.js index 79aef5a55f9bcd..c76831b573dde6 100644 --- a/benchmark/common.js +++ b/benchmark/common.js @@ -3,6 +3,8 @@ const child_process = require('child_process'); const http_benchmarkers = require('./_http-benchmarkers.js'); +exports.buildType = process.features.debug ? 'Debug' : 'Release'; + exports.createBenchmark = function(fn, configs, options) { return new Benchmark(fn, configs, options); }; diff --git a/benchmark/fixtures/require-cachable.js b/benchmark/fixtures/require-cachable.js new file mode 100644 index 00000000000000..f651728dc78f35 --- /dev/null +++ b/benchmark/fixtures/require-cachable.js @@ -0,0 +1,13 @@ +'use strict'; + +const list = require('internal/bootstrap/cache'); +const { + isMainThread +} = require('worker_threads'); + +for (const key of list.cachableBuiltins) { + if (!isMainThread && key === 'trace_events') { + continue; + } + require(key); +} diff --git a/benchmark/fs/bench-readdir.js b/benchmark/fs/bench-readdir.js index a3e19e242dadbe..0d8ed04856515f 100644 --- a/benchmark/fs/bench-readdir.js +++ b/benchmark/fs/bench-readdir.js @@ -5,16 +5,19 @@ const fs = require('fs'); const path = require('path'); const bench = common.createBenchmark(main, { - n: [1e4], + n: [10], + dir: [ 'lib', 'test/parallel'], + withFileTypes: ['true', 'false'] }); - -function main({ n }) { +function main({ n, dir, withFileTypes }) { + withFileTypes = withFileTypes === 'true'; + const fullPath = path.resolve(__dirname, '../../', dir); bench.start(); (function r(cntr) { if (cntr-- <= 0) return bench.end(n); - fs.readdir(path.resolve(__dirname, '../../lib/'), function() { + fs.readdir(fullPath, { withFileTypes }, function() { r(cntr); }); }(n)); diff --git a/benchmark/fs/bench-readdirSync.js b/benchmark/fs/bench-readdirSync.js index ef3327163e8c22..5d0e97399a33ff 100644 --- a/benchmark/fs/bench-readdirSync.js +++ b/benchmark/fs/bench-readdirSync.js @@ -5,14 +5,18 @@ const fs = require('fs'); const path = require('path'); const bench = common.createBenchmark(main, { - n: [1e4], + n: [10], + dir: [ 'lib', 'test/parallel'], + withFileTypes: ['true', 'false'] }); -function main({ n }) { +function main({ n, dir, withFileTypes }) { + withFileTypes = withFileTypes === 'true'; + const fullPath = path.resolve(__dirname, '../../', dir); bench.start(); for (var i = 0; i < n; i++) { - fs.readdirSync(path.resolve(__dirname, '../../lib/')); + fs.readdirSync(fullPath, { withFileTypes }); } bench.end(n); } diff --git a/benchmark/fs/read-stream-throughput.js b/benchmark/fs/read-stream-throughput.js index 3af80132725ec0..7f290a310b592c 100644 --- a/benchmark/fs/read-stream-throughput.js +++ b/benchmark/fs/read-stream-throughput.js @@ -55,7 +55,7 @@ function runTest() { }); rs.on('end', function() { - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} // MB/sec bench.end(bytes / (1024 * 1024)); }); @@ -74,7 +74,7 @@ function makeFile() { buf.fill('x'); } - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} var w = 1024; const ws = fs.createWriteStream(filename); ws.on('close', runTest); diff --git a/benchmark/fs/readfile-partitioned.js b/benchmark/fs/readfile-partitioned.js index be3b7fd057bbe0..6e355c158da850 100644 --- a/benchmark/fs/readfile-partitioned.js +++ b/benchmark/fs/readfile-partitioned.js @@ -24,7 +24,7 @@ const bench = common.createBenchmark(main, { function main(conf) { const len = +conf.len; - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} var data = Buffer.alloc(len, 'x'); fs.writeFileSync(filename, data); data = null; @@ -39,7 +39,7 @@ function main(conf) { const totalOps = reads + zips; benchEnded = true; bench.end(totalOps); - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} }, +conf.dur * 1000); function read() { diff --git a/benchmark/fs/readfile.js b/benchmark/fs/readfile.js index 282b4ac7621340..36439bdf909f1d 100644 --- a/benchmark/fs/readfile.js +++ b/benchmark/fs/readfile.js @@ -17,7 +17,7 @@ const bench = common.createBenchmark(main, { }); function main({ len, dur, concurrent }) { - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} var data = Buffer.alloc(len, 'x'); fs.writeFileSync(filename, data); data = null; @@ -28,7 +28,7 @@ function main({ len, dur, concurrent }) { setTimeout(function() { benchEnded = true; bench.end(reads); - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} process.exit(0); }, dur * 1000); diff --git a/benchmark/fs/write-stream-throughput.js b/benchmark/fs/write-stream-throughput.js index 60ad47bc4eabe1..baf98f849fed07 100644 --- a/benchmark/fs/write-stream-throughput.js +++ b/benchmark/fs/write-stream-throughput.js @@ -33,7 +33,7 @@ function main({ dur, encodingType, size }) { throw new Error(`invalid encodingType: ${encodingType}`); } - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} var started = false; var ended = false; @@ -45,7 +45,7 @@ function main({ dur, encodingType, size }) { f.on('finish', function() { ended = true; const written = fs.statSync(filename).size / 1024; - try { fs.unlinkSync(filename); } catch (e) {} + try { fs.unlinkSync(filename); } catch {} bench.end(written / 1024); }); diff --git a/benchmark/http2/headers.js b/benchmark/http2/headers.js index e2fad2ea02a0ee..f18a73b95e2421 100644 --- a/benchmark/http2/headers.js +++ b/benchmark/http2/headers.js @@ -39,8 +39,7 @@ function main({ n, nheaders }) { function doRequest(remaining) { const req = client.request(headersObject); - req.end(); - req.on('data', () => {}); + req.resume(); req.on('end', () => { if (remaining > 0) { doRequest(remaining - 1); diff --git a/benchmark/http2/respond-with-fd.js b/benchmark/http2/respond-with-fd.js index 3415a9c69f13ec..35856490f7e4a2 100644 --- a/benchmark/http2/respond-with-fd.js +++ b/benchmark/http2/respond-with-fd.js @@ -7,9 +7,9 @@ const fs = require('fs'); const file = path.join(path.resolve(__dirname, '../fixtures'), 'alice.html'); const bench = common.createBenchmark(main, { - requests: [100, 1000, 10000, 100000], - streams: [100, 200, 1000], - clients: [1, 2], + requests: [100, 1000, 5000], + streams: [1, 10, 20, 40, 100, 200], + clients: [2], benchmarker: ['h2load'] }, { flags: ['--no-warnings'] }); diff --git a/benchmark/http2/simple.js b/benchmark/http2/simple.js index f4598b81560230..aab7c6b609b715 100644 --- a/benchmark/http2/simple.js +++ b/benchmark/http2/simple.js @@ -6,9 +6,9 @@ const fs = require('fs'); const file = path.join(path.resolve(__dirname, '../fixtures'), 'alice.html'); const bench = common.createBenchmark(main, { - requests: [100, 1000, 10000, 100000], - streams: [100, 200, 1000], - clients: [1, 2], + requests: [100, 1000, 5000], + streams: [1, 10, 20, 40, 100, 200], + clients: [2], benchmarker: ['h2load'] }, { flags: ['--no-warnings'] }); diff --git a/benchmark/misc/punycode.js b/benchmark/misc/punycode.js index a55660fbc07247..c9eef1f7096fac 100644 --- a/benchmark/misc/punycode.js +++ b/benchmark/misc/punycode.js @@ -4,7 +4,7 @@ const common = require('../common.js'); let icu; try { icu = common.binding('icu'); -} catch (err) {} +} catch {} const punycode = require('punycode'); const bench = common.createBenchmark(main, { diff --git a/benchmark/misc/startup.js b/benchmark/misc/startup.js index 703146f081b3c6..1350cd291e2b18 100644 --- a/benchmark/misc/startup.js +++ b/benchmark/misc/startup.js @@ -1,36 +1,76 @@ 'use strict'; const common = require('../common.js'); -const spawn = require('child_process').spawn; +const { spawn } = require('child_process'); const path = require('path'); -const emptyJsFile = path.resolve(__dirname, '../../test/fixtures/semicolon.js'); -const bench = common.createBenchmark(startNode, { - dur: [1] +let Worker; // Lazy loaded in main + +const bench = common.createBenchmark(main, { + dur: [1], + script: ['benchmark/fixtures/require-cachable', 'test/fixtures/semicolon'], + mode: ['process', 'worker'] +}, { + flags: ['--expose-internals', '--experimental-worker'] // for workers }); -function startNode({ dur }) { - var go = true; - var starts = 0; +function spawnProcess(script) { + const cmd = process.execPath || process.argv[0]; + const argv = ['--expose-internals', script]; + return spawn(cmd, argv); +} + +function spawnWorker(script) { + return new Worker(script, { stderr: true, stdout: true }); +} + +function start(state, script, bench, getNode) { + const node = getNode(script); + 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, script, bench, getNode); + } else { + bench.end(state.throughput); + } + }); +} + +function main({ dur, script, mode }) { + const state = { + go: true, + throughput: 0 + }; setTimeout(function() { - go = false; + state.go = false; }, dur * 1000); - bench.start(); - start(); - - function start() { - const node = spawn(process.execPath || process.argv[0], [emptyJsFile]); - node.on('exit', function(exitCode) { - if (exitCode !== 0) { - throw new Error('Error during node startup'); - } - starts++; - - if (go) - start(); - else - bench.end(starts); - }); + script = path.resolve(__dirname, '../../', `${script}.js`); + if (mode === 'worker') { + Worker = require('worker_threads').Worker; + bench.start(); + start(state, script, bench, spawnWorker); + } else { + bench.start(); + start(state, script, bench, spawnProcess); } } diff --git a/benchmark/module/module-loader.js b/benchmark/module/module-loader.js index c79e1a73d4f21a..e780d6376b5e8d 100644 --- a/benchmark/module/module-loader.js +++ b/benchmark/module/module-loader.js @@ -14,7 +14,7 @@ const bench = common.createBenchmark(main, { function main({ n, fullPath, useCache }) { tmpdir.refresh(); - try { fs.mkdirSync(benchmarkDirectory); } catch (e) {} + try { fs.mkdirSync(benchmarkDirectory); } catch {} for (var i = 0; i <= n; i++) { fs.mkdirSync(`${benchmarkDirectory}${i}`); fs.writeFileSync( diff --git a/benchmark/napi/function_args/binding.cc b/benchmark/napi/function_args/binding.cc index d0c1a079210532..9f250aaa83db50 100644 --- a/benchmark/napi/function_args/binding.cc +++ b/benchmark/napi/function_args/binding.cc @@ -33,7 +33,8 @@ void CallWithArray(const FunctionCallbackInfo& args) { uint32_t length = array->Length(); for (uint32_t i = 0; i < length; ++ i) { Local v; - v = array->Get(i); + v = array->Get(args.GetIsolate()->GetCurrentContext(), + i).ToLocalChecked(); } } } diff --git a/benchmark/napi/function_args/index.js b/benchmark/napi/function_args/index.js index 4beab531c17301..df567dcfcc55bc 100644 --- a/benchmark/napi/function_args/index.js +++ b/benchmark/napi/function_args/index.js @@ -10,15 +10,15 @@ let v8; let napi; try { - v8 = require('./build/Release/binding'); -} catch (err) { + v8 = require(`./build/${common.buildType}/binding`); +} catch { console.error(`${__filename}: V8 Binding failed to load`); process.exit(0); } try { - napi = require('./build/Release/napi_binding'); -} catch (err) { + napi = require(`./build/${common.buildType}/napi_binding`); +} catch { console.error(`${__filename}: NAPI-Binding failed to load`); process.exit(0); } diff --git a/benchmark/napi/function_call/index.js b/benchmark/napi/function_call/index.js index cbc512c9729137..59063e500f7a84 100644 --- a/benchmark/napi/function_call/index.js +++ b/benchmark/napi/function_call/index.js @@ -12,8 +12,8 @@ const common = require('../../common.js'); // abort quietly. try { - var binding = require('./build/Release/binding'); -} catch (er) { + var binding = require(`./build/${common.buildType}/binding`); +} catch { console.error('misc/function_call.js Binding failed to load'); process.exit(0); } @@ -21,8 +21,8 @@ const cxx = binding.hello; let napi_binding; try { - napi_binding = require('./build/Release/napi_binding'); -} catch (er) { + napi_binding = require(`./build/${common.buildType}/napi_binding`); +} catch { console.error('misc/function_call/index.js NAPI-Binding failed to load'); process.exit(0); } diff --git a/common.gypi b/common.gypi index bacd496538a383..4b732704ba2618 100644 --- a/common.gypi +++ b/common.gypi @@ -28,12 +28,9 @@ 'openssl_fips%': '', - # Default to -O0 for debug builds. - 'v8_optimized_debug%': 0, - # 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.7', + 'v8_embedder_string': '-node.11', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, @@ -53,6 +50,12 @@ 'icu_use_data_file_flag%': 0, 'conditions': [ + ['target_arch=="arm64"', { + # Disabled pending https://github.com/nodejs/node/issues/23913. + 'openssl_no_asm%': 1, + }, { + 'openssl_no_asm%': 0, + }], ['GENERATOR=="ninja"', { 'obj_dir': '<(PRODUCT_DIR)/obj', 'conditions': [ diff --git a/configure.py b/configure.py index 5bc53630f3985b..065e31fd9cac51 100755 --- a/configure.py +++ b/configure.py @@ -182,6 +182,11 @@ help='Use the specified path to system CA (PEM format) in addition to ' 'the OpenSSL supplied CA store or compiled-in Mozilla CA copy.') +parser.add_option('--experimental-http-parser', + action='store_true', + dest='experimental_http_parser', + help='use llhttp instead of http_parser') + shared_optgroup.add_option('--shared-http-parser', action='store_true', dest='shared_http_parser', @@ -566,6 +571,12 @@ default=False, help='get more output from this script') +parser.add_option('--v8-non-optimized-debug', + action='store_true', + dest='v8_non_optimized_debug', + default=False, + help='compile V8 with minimal optimizations and with runtime checks') + # Create compile_commands.json in out/Debug and out/Release. parser.add_option('-C', action='store_true', @@ -1100,6 +1111,9 @@ def configure_node(o): else: o['variables']['node_target_type'] = 'executable' + o['variables']['node_experimental_http_parser'] = \ + b(options.experimental_http_parser) + def configure_library(lib, output): shared_lib = 'shared_' + lib output['variables']['node_' + shared_lib] = b(getattr(options, shared_lib)) @@ -1138,7 +1152,7 @@ def configure_library(lib, output): def configure_v8(o): o['variables']['v8_enable_gdbjit'] = 1 if options.gdb else 0 o['variables']['v8_no_strict_aliasing'] = 1 # Work around compiler bugs. - o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds. + o['variables']['v8_optimized_debug'] = 0 if options.v8_non_optimized_debug else 1 o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables. o['variables']['v8_promise_internal_field_count'] = 1 # Add internal field to promises for async hooks. o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true' @@ -1169,9 +1183,11 @@ def configure_openssl(o): variables = o['variables'] variables['node_use_openssl'] = b(not options.without_ssl) variables['node_shared_openssl'] = b(options.shared_openssl) - variables['openssl_no_asm'] = 1 if options.openssl_no_asm else 0 variables['openssl_fips'] = '' + if options.openssl_no_asm: + variables['openssl_no_asm'] = 1 + if options.without_ssl: def without_ssl_error(option): error('--without-ssl is incompatible with %s' % option) diff --git a/deps/cares/LICENSE.md b/deps/cares/LICENSE.md index 86b520b91d3705..ad6bb52b729ed4 100644 --- a/deps/cares/LICENSE.md +++ b/deps/cares/LICENSE.md @@ -1,6 +1,6 @@ # c-ares license -Copyright (c) 2007 - 2016, Daniel Stenberg with many contributors, see AUTHORS +Copyright (c) 2007 - 2018, Daniel Stenberg with many contributors, see AUTHORS file. Copyright 1998 by the Massachusetts Institute of Technology. diff --git a/deps/cares/Makefile b/deps/cares/Makefile deleted file mode 100644 index 069c67e542fa74..00000000000000 --- a/deps/cares/Makefile +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright Joyent, Inc. and other Node contributors. All rights reserved. -# -# 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. - -SRCDIR ?= $(CURDIR) - -ifeq (,$(builddir_name)) - -VPATH := $(SRCDIR) -include $(SRCDIR)/build.mk - -else # Out of tree build. - -# Drop all built-in rules. -.SUFFIXES: - -.PHONY: $(builddir_name) -$(builddir_name): $(builddir_name)/.buildstamp - $(MAKE) -C $@ -f $(CURDIR)/Makefile $(MAKECMDGOALS) \ - SRCDIR=$(CURDIR) builddir_name= - -$(builddir_name)/.buildstamp: - mkdir -p $(dir $@) - touch $@ - -# Add no-op rules for Makefiles to stop make from trying to rebuild them. -Makefile:: ; -%.mk:: ; - -# Turn everything else into a no-op rule that depends on the build directory. -%:: $(builddir_name) ; - -.PHONY: clean -clean: - $(RM) -fr $(builddir_name) - -endif diff --git a/deps/cares/android-configure b/deps/cares/android-configure deleted file mode 100755 index 5299e5c718a9bd..00000000000000 --- a/deps/cares/android-configure +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -export TOOLCHAIN=$PWD/android-toolchain -mkdir -p $TOOLCHAIN -$1/build/tools/make-standalone-toolchain.sh \ - --toolchain=arm-linux-androideabi-4.7 \ - --arch=arm \ - --install-dir=$TOOLCHAIN \ - --platform=android-9 -export PATH=$TOOLCHAIN/bin:$PATH -export AR=arm-linux-androideabi-ar -export CC=arm-linux-androideabi-gcc -export CXX=arm-linux-androideabi-g++ -export LINK=arm-linux-androideabi-g++ -export PLATFORM=android -export OS=android - -if [ $2 -a $2 == 'gyp' ] - then - ./gyp_cares -DOS=android -Dtarget_arch=arm -fi diff --git a/deps/cares/build.mk b/deps/cares/build.mk deleted file mode 100644 index 91af512721ce8d..00000000000000 --- a/deps/cares/build.mk +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright Joyent, Inc. and other Node contributors. All rights reserved. -# -# 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. - -OS ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') - -OBJS= \ - src/ares_cancel.o \ - src/ares__close_sockets.o \ - src/ares_create_query.o \ - src/ares_data.o \ - src/ares_destroy.o \ - src/ares_expand_name.o \ - src/ares_expand_string.o \ - src/ares_fds.o \ - src/ares_free_hostent.o \ - src/ares_free_string.o \ - src/ares_gethostbyaddr.o \ - src/ares_gethostbyname.o \ - src/ares__get_hostent.o \ - src/ares_getnameinfo.o \ - src/ares_getopt.o \ - src/ares_getsock.o \ - src/ares_init.o \ - src/ares_library_init.o \ - src/ares_llist.o \ - src/ares_mkquery.o \ - src/ares_nowarn.o \ - src/ares_options.o \ - src/ares_parse_aaaa_reply.o \ - src/ares_parse_a_reply.o \ - src/ares_parse_mx_reply.o \ - src/ares_parse_naptr_reply.o \ - src/ares_parse_ns_reply.o \ - src/ares_parse_ptr_reply.o \ - src/ares_parse_soa_reply.o \ - src/ares_parse_srv_reply.o \ - src/ares_parse_txt_reply.o \ - src/ares_process.o \ - src/ares_query.o \ - src/ares__read_line.o \ - src/ares_search.o \ - src/ares_send.o \ - src/ares_strcasecmp.o \ - src/ares_strdup.o \ - src/ares_strerror.o \ - src/ares_timeout.o \ - src/ares__timeval.o \ - src/ares_version.o \ - src/ares_writev.o \ - src/bitncmp.o \ - src/inet_net_pton.o \ - src/inet_ntop.o \ - -CFLAGS += -I. -I$(SRCDIR)/include -DHAVE_CONFIG_H - -ARES_CONFIG_OS = $(OS) -SOEXT = so - -# if on windows -ifneq (,$(findstring mingw,$(OS))) -ARES_CONFIG_OS = win32 -OBJS += src/windows_port.o -OBJS += src/ares_getenv.o -OBJS += src/ares_platform.o - -LDFLAGS += -lws2_32.lib -liphlpapi.lib -else # else a posix system -CFLAGS += -g --std=gnu89 -pedantic -CFLAGS += -Wall -Wextra -Wno-unused-parameter -CFLAGS += -D_LARGEFILE_SOURCE -CFLAGS += -D_FILE_OFFSET_BITS=64 -endif - -ifneq (,$(findstring cygwin,$(OS))) -ARES_CONFIG_OS = cygwin -CFLAGS += -D_GNU_SOURCE -endif - -ifeq (dragonflybsd,$(OS)) -ARES_CONFIG_OS = freebsd -endif - -ifeq (darwin,$(OS)) -CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 -LDFLAGS += -dynamiclib -install_name "@rpath/libcares.dylib" -SOEXT = dylib -endif - -ifeq (linux,$(OS)) -CFLAGS += -D_GNU_SOURCE -endif - -ifeq (android,$(OS)) -CFLAGS += -D_GNU_SOURCE -endif - -ifeq (sunos,$(OS)) -LDFLAGS += -lsocket -lnsl -CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 -endif - -CFLAGS += -I$(SRCDIR)/config/$(ARES_CONFIG_OS) - -ifneq (,$(findstring libcares.$(SOEXT),$(MAKECMDGOALS))) -CFLAGS += -DCARES_BUILDING_LIBRARY -else -CFLAGS += -DCARES_STATICLIB -endif - -all: libcares.a - -src/.buildstamp: - mkdir -p $(dir $@) - touch $@ - -libcares.a: $(OBJS) - $(AR) rcs $@ $^ - -libcares.$(SOEXT): override CFLAGS += -fPIC -libcares.$(SOEXT): $(OBJS:%.o=%.pic.o) - $(CC) -shared -o $@ $^ $(LDFLAGS) - -src/%.o src/%.pic.o: src/%.c include/ares.h include/ares_version.h \ - include/nameser.h src/.buildstamp \ - $(SRCDIR)/config/$(ARES_CONFIG_OS)/ares_config.h - $(CC) $(CFLAGS) -c $< -o $@ - -.PHONY: clean -clean: - $(RM) -f libcares.a libcares.$(SOEXT) src/*.o src/.buildstamp diff --git a/deps/cares/build/gcc_version.py b/deps/cares/build/gcc_version.py deleted file mode 100644 index da019e866114b0..00000000000000 --- a/deps/cares/build/gcc_version.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python - -import os -import re -import subprocess -import sys - - -def DoMain(*args): - cc = os.environ.get('CC', 'gcc') - stdin, stderr = os.pipe() - subprocess.call([cc, '-v'], stderr=stderr) - output = os.read(stdin, 4096) - match = re.search("\ngcc version (\d+\.\d+\.\d+)", output) - if match: - print(match.group(1)) - - -if __name__ == '__main__': - DoMain(*sys.argv) diff --git a/deps/cares/cares.gyp b/deps/cares/cares.gyp index fce52acb31f495..be7931f7743db1 100644 --- a/deps/cares/cares.gyp +++ b/deps/cares/cares.gyp @@ -35,7 +35,6 @@ 'include_dirs': [ 'include' ] }, 'sources': [ - 'common.gypi', 'include/ares.h', 'include/ares_rules.h', 'include/ares_version.h', @@ -93,6 +92,7 @@ 'src/ares_strdup.c', 'src/ares_strdup.h', 'src/ares_strerror.c', + 'src/ares_strsplit.c', 'src/ares_timeout.c', 'src/ares__timeval.c', 'src/ares_version.c', diff --git a/deps/cares/common.gypi b/deps/cares/common.gypi deleted file mode 100644 index 609ad62a3965d0..00000000000000 --- a/deps/cares/common.gypi +++ /dev/null @@ -1,172 +0,0 @@ -{ - 'variables': { - 'visibility%': 'hidden', - 'library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds - 'component%': 'static_library', - 'host_arch%': '', - 'target_arch%': '' - }, - - 'target_defaults': { - 'default_configuration': 'Debug', - 'configurations': { - - 'Debug': { - 'defines': [ 'DEBUG', '_DEBUG' ], - 'cflags': [ '-g', '-O0' ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'target_conditions': [ - ['library=="static_library"', { - 'RuntimeLibrary': 1 # static debug - }, { - 'RuntimeLibrary': 3 # DLL debug - }] - ], - 'Optimization': 0, # /Od, no optimization - 'MinimalRebuild': 'false', - 'OmitFramePointers': 'false', - 'BasicRuntimeChecks': 3 # /RTC1 - }, - 'VCLinkerTool': { - 'LinkIncremental': 2 # enable incremental linking - } - }, - 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '0' - } - }, - - 'Release': { - 'defines': [ 'NDEBUG' ], - 'cflags': [ - '-O3', - '-fomit-frame-pointer', - '-fdata-sections', - '-ffunction-sections' - ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'target_conditions': [ - ['library=="static_library"', { - 'RuntimeLibrary': 0, # static release - }, { - 'RuntimeLibrary': 2, # debug release - }], - ], - 'Optimization': 3, # /Ox, full optimization - 'FavorSizeOrSpeed': 1, # /Ot, favour speed over size - 'InlineFunctionExpansion': 2, # /Ob2, inline anything eligible - 'WholeProgramOptimization': 'true', # /GL, whole program optimization, needed for LTCG - 'OmitFramePointers': 'true', - 'EnableFunctionLevelLinking': 'true', - 'EnableIntrinsicFunctions': 'true' - }, - 'VCLibrarianTool': { - 'AdditionalOptions': [ - '/LTCG' # link time code generation - ] - }, - 'VCLinkerTool': { - 'LinkTimeCodeGeneration': 1, # link-time code generation - 'OptimizeReferences': 2, # /OPT:REF - 'EnableCOMDATFolding': 2, # /OPT:ICF - 'LinkIncremental': 1 # disable incremental linking - }, - }, - } - }, - - 'msvs_settings': { - 'VCCLCompilerTool': { - 'StringPooling': 'true', # pool string literals - 'DebugInformationFormat': 3, # Generate a PDB - 'WarningLevel': 3, - 'BufferSecurityCheck': 'true', - 'ExceptionHandling': 1, # /EHsc - 'SuppressStartupBanner': 'true', - 'WarnAsError': 'false', - 'AdditionalOptions': [ - '/MP', # compile across multiple CPUs - ], - }, - 'VCLinkerTool': { - 'GenerateDebugInformation': 'true', - 'RandomizedBaseAddress': 2, # enable ASLR - 'DataExecutionPrevention': 2, # enable DEP - 'AllowIsolation': 'true', - 'SuppressStartupBanner': 'true', - 'target_conditions': [ - ['_type=="executable"', { - 'SubSystem': 1, # console executable - }], - ], - }, - }, - - 'xcode_settings': { - 'ALWAYS_SEARCH_USER_PATHS': 'NO', - 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks - 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions - 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti - 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings - # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden - 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden - 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics - 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof - 'PREBINDING': 'NO', # No -Wl,-prebind - 'USE_HEADERMAP': 'NO', - 'WARNING_CFLAGS': [ - '-Wall', - '-Wendif-labels', - '-W', - '-Wno-unused-parameter' - ] - }, - - 'conditions': [ - ['OS == "win"', { - 'msvs_cygwin_shell': 0, # prevent actions from trying to use cygwin - 'defines': [ - 'WIN32', - # we don't want VC++ warning us about how dangerous C functions are. - '_CRT_SECURE_NO_DEPRECATE', - # ... or that C implementations shouldn't use POSIX names - '_CRT_NONSTDC_NO_DEPRECATE' - ], - }], - - [ 'OS in "linux freebsd openbsd solaris android aix"', { - 'variables': { - 'gcc_version%': ')' - }, - 'cflags': [ '-Wall' ], - 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ], - 'conditions': [ - [ 'host_arch != target_arch and target_arch=="ia32"', { - 'cflags': [ '-m32' ], - 'ldflags': [ '-m32' ] - }], - [ 'OS=="linux"', { - 'cflags': [ '-ansi' ] - }], - [ 'visibility=="hidden" and gcc_version >= "4.0.0"', { - 'cflags': [ '-fvisibility=hidden' ] - }], - ] - }] - ], - - 'target_conditions': [ - ['_type!="static_library"', { - 'cflags': [ '-fPIC' ], - 'xcode_settings': { - 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic - # (Equivalent to -fPIC) - 'OTHER_LDFLAGS': [ '-Wl,-search_paths_first' ] - } - }] - ] - } -} diff --git a/deps/cares/get_ver.awk b/deps/cares/get_ver.awk deleted file mode 100644 index f9929b73614ba3..00000000000000 --- a/deps/cares/get_ver.awk +++ /dev/null @@ -1,26 +0,0 @@ -# *************************************************************************** -# * Project: c-ares -# * -# *************************************************************************** -# awk script which fetches c-ares version number and string from input -# file and writes them to STDOUT. Here you can get an awk version for Win32: -# http://www.gknw.net/development/prgtools/awk-20100523.zip -# -BEGIN { - while ((getline < ARGV[1]) > 0) { - sub("\r", "") # make MSYS gawk work with CRLF header input. - if (match ($0, /^#define ARES_COPYRIGHT "[^"]+"$/)) - copyright_string = substr($0, 25, length($0)-25) - else if (match ($0, /^#define ARES_VERSION_STR "[^"]+"$/)) - version_string = substr($3, 2, length($3)-2) - else if (match ($0, /^#define ARES_VERSION_MAJOR [0-9]+$/)) - version_major = $3 - else if (match ($0, /^#define ARES_VERSION_MINOR [0-9]+$/)) - version_minor = $3 - else if (match ($0, /^#define ARES_VERSION_PATCH [0-9]+$/)) - version_patch = $3 - } - print "LIBCARES_VERSION = " version_major "," version_minor "," version_patch - print "LIBCARES_VERSION_STR = " version_string - print "LIBCARES_COPYRIGHT_STR = " copyright_string -} diff --git a/deps/cares/gyp_cares b/deps/cares/gyp_cares deleted file mode 100755 index d1f1640e015706..00000000000000 --- a/deps/cares/gyp_cares +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python - -import glob -import platform -import os -import subprocess -import sys - -CC = os.environ.get('CC', 'cc') -script_dir = os.path.dirname(__file__) -cares_root = os.path.normpath(script_dir) -output_dir = os.path.join(os.path.abspath(cares_root), 'out') - -sys.path.insert(0, os.path.join(cares_root, 'build', 'gyp', 'pylib')) -try: - import gyp -except ImportError: - print('You need to install gyp in build/gyp first. See the README.') - sys.exit(42) - - -def host_arch(): - machine = platform.machine() - if machine == 'i386': return 'ia32' - if machine == 'x86_64': return 'x64' - if machine.startswith('arm'): return 'arm' - return machine # Return as-is and hope for the best. - - -def compiler_version(): - proc = subprocess.Popen(CC.split() + ['--version'], stdout=subprocess.PIPE) - is_clang = 'clang' in proc.communicate()[0].split('\n')[0] - proc = subprocess.Popen(CC.split() + ['-dumpversion'], stdout=subprocess.PIPE) - version = proc.communicate()[0].split('.') - version = map(int, version[:2]) - version = tuple(version) - return (version, is_clang) - - -def run_gyp(args): - rc = gyp.main(args) - if rc != 0: - print 'Error running GYP' - sys.exit(rc) - - -if __name__ == '__main__': - args = sys.argv[1:] - - # GYP bug. - # On msvs it will crash if it gets an absolute path. - # On Mac/make it will crash if it doesn't get an absolute path. - if sys.platform == 'win32': - args.append(os.path.join(cares_root, 'cares.gyp')) - common_fn = os.path.join(cares_root, 'common.gypi') - options_fn = os.path.join(cares_root, 'options.gypi') - # we force vs 2010 over 2008 which would otherwise be the default for gyp - if not os.environ.get('GYP_MSVS_VERSION'): - os.environ['GYP_MSVS_VERSION'] = '2010' - else: - args.append(os.path.join(os.path.abspath(cares_root), 'cares.gyp')) - common_fn = os.path.join(os.path.abspath(cares_root), 'common.gypi') - options_fn = os.path.join(os.path.abspath(cares_root), 'options.gypi') - - if os.path.exists(common_fn): - args.extend(['-I', common_fn]) - - if os.path.exists(options_fn): - args.extend(['-I', options_fn]) - - args.append('--depth=' + cares_root) - - # There's a bug with windows which doesn't allow this feature. - if sys.platform != 'win32': - if '-f' not in args: - args.extend('-f make'.split()) - if 'ninja' not in args: - args.extend(['-Goutput_dir=' + output_dir]) - args.extend(['--generator-output', output_dir]) - (major, minor), is_clang = compiler_version() - args.append('-Dgcc_version=%d' % (10 * major + minor)) - args.append('-Dclang=%d' % int(is_clang)) - - if not any(a.startswith('-Dhost_arch=') for a in args): - args.append('-Dhost_arch=%s' % host_arch()) - - if not any(a.startswith('-Dtarget_arch=') for a in args): - args.append('-Dtarget_arch=%s' % host_arch()) - - if not any(a.startswith('-Dlibrary=') for a in args): - args.append('-Dlibrary=static_library') - - if not any(a.startswith('-Dcomponent=') for a in args): - args.append('-Dcomponent=static_library') - - gyp_args = list(args) - print gyp_args - run_gyp(gyp_args) diff --git a/deps/cares/include/ares.h b/deps/cares/include/ares.h index 65a82cb5b7eb47..06f60b33304b80 100644 --- a/deps/cares/include/ares.h +++ b/deps/cares/include/ares.h @@ -164,6 +164,7 @@ extern "C" { #define ARES_OPT_ROTATE (1 << 14) #define ARES_OPT_EDNSPSZ (1 << 15) #define ARES_OPT_NOROTATE (1 << 16) +#define ARES_OPT_RESOLVCONF (1 << 17) /* Nameinfo flag values */ #define ARES_NI_NOFQDN (1 << 0) @@ -270,6 +271,7 @@ struct ares_options { struct apattern *sortlist; int nsort; int ednspsz; + char *resolvconf_path; }; struct hostent; diff --git a/deps/cares/include/ares_build.h b/deps/cares/include/ares_build.h index f5535b38493fcb..5e3ba9f0d8cb0c 100644 --- a/deps/cares/include/ares_build.h +++ b/deps/cares/include/ares_build.h @@ -194,16 +194,14 @@ /* Data type definition of ares_ssize_t. */ #ifdef _WIN32 # ifdef _WIN64 - typedef __int64 ares_ssize_t; +# define CARES_TYPEOF_ARES_SSIZE_T __int64 # else - typedef long ares_ssize_t; +# define CARES_TYPEOF_ARES_SSIZE_T long # endif #else -# ifdef CARES_TYPEOF_ARES_SSIZE_T - typedef CARES_TYPEOF_ARES_SSIZE_T ares_ssize_t; -# else - typedef ssize_t ares_ssize_t; -# endif +# define CARES_TYPEOF_ARES_SSIZE_T ssize_t #endif +typedef CARES_TYPEOF_ARES_SSIZE_T ares_ssize_t; + #endif /* __CARES_BUILD_H */ diff --git a/deps/cares/include/ares_rules.h b/deps/cares/include/ares_rules.h index e617fdc6daaa49..cac23cf2e32db3 100644 --- a/deps/cares/include/ares_rules.h +++ b/deps/cares/include/ares_rules.h @@ -83,7 +83,7 @@ /* * Verify that the size previously defined and expected for - * ares_socklen_t is actually the the same as the one reported + * ares_socklen_t is actually the same as the one reported * by sizeof() at compile time. */ diff --git a/deps/cares/include/ares_version.h b/deps/cares/include/ares_version.h index 61b2b98a8d3683..3fe5b00a1171c2 100644 --- a/deps/cares/include/ares_version.h +++ b/deps/cares/include/ares_version.h @@ -3,15 +3,15 @@ #define ARES__VERSION_H /* This is the global package copyright */ -#define ARES_COPYRIGHT "2004 - 2017 Daniel Stenberg, ." +#define ARES_COPYRIGHT "2004 - 2018 Daniel Stenberg, ." #define ARES_VERSION_MAJOR 1 -#define ARES_VERSION_MINOR 14 +#define ARES_VERSION_MINOR 15 #define ARES_VERSION_PATCH 0 #define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\ (ARES_VERSION_MINOR<<8)|\ (ARES_VERSION_PATCH)) -#define ARES_VERSION_STR "1.14.0" +#define ARES_VERSION_STR "1.15.0" #if (ARES_VERSION >= 0x010700) # define CARES_HAVE_ARES_LIBRARY_INIT 1 diff --git a/deps/cares/src/RELEASE-NOTES b/deps/cares/src/RELEASE-NOTES index 91230a325b9a73..62276fdf4e38c6 100644 --- a/deps/cares/src/RELEASE-NOTES +++ b/deps/cares/src/RELEASE-NOTES @@ -1,47 +1,43 @@ -c-ares version 1.14.0 +c-ares version 1.15.0 Changes: - o android: Introduce new ares_library_init_android() call for Oreo support. [5] + o Add ares_init_options() configurability for path to resolv.conf file [1] + o Ability to exclude building of tools (adig, ahost, acountry) in CMake [3] + o Android: Support for domain search suffix [4] + o Report ARES_ENOTFOUND for .onion domain names as per RFC7686. [13] Bug fixes: - - o Fix patch for CVE-2017-1000381 to not be overly aggressive. [1] - o win32: Preserve DNS server order returned by Windows when sorting and exclude - DNS servers in legacy subnets. [2] [4] - o win32: Support most recent Visual Studio 2017 - o gethostbyaddr should fail with ECANCELLED not ENOTFOUND when ares_cancel - is called. [3] - o win32: Exclude legacy ipv6 subnets [4] - o android: Applications compiled for Oreo can no longer use - __system_property_get and must use Java calls to retrieve DNS servers. - [5] [7] - o win32: Force use of ANSI functions [6] - o CMake minimum version is now 3.1 - o ares_gethostbyname.3: fix callback status values [8] - o docs: Document WSAStartup requirement [9] - o Fix a typo in init_by_resolv_conf [10] - o Android JNI code leaks local references in some cases [11] - o Force using the ANSI versions of WinAPI functions [12] + o AIX build fix for trying to include both nameser_compat.h and + onameser_compat.h [2] + o Windows: Improve DNS suffixes extracting from WinNT registry [5] + o Fix modern GCC warnings [6] + o Apply the IPv6 server blacklist to all nameserver sources, not just Windows + [7] + o Fix warnings emitted by MSVC when using -W4 [8] + o Prevent changing name servers while queries are outstanding [9] + o Harden and rationalize c-ares timeout computation [10] + o Distribute ares_android.h [11] + o ares_set_servers_csv() on failure should not leave channel in a bad state + [12] + o Add missing docs to distribution Thanks go to these friendly people for their efforts and contributions: - - AC Thompson, Anna Henningsen, Antonio Tajuelo, Brad House, Brad Spencer, - Christian Ammer, Daniel Stenberg, David Drysdale, David Hotham, Felix Yan, - Gergely Nagy, Gregor Jasny, Jakub Hrozek, John Schember, - Konstantinos Sofokleous, Roman Teterin, Sergey Kolomenkin, Sheel Bedi, - (18 contributors) + @afalin, Andi Schnebinger, Ben Noordhuis, Brad House, Brad Spencer, + David Hotham, @flyingdutchman23, John Schember, Ruslan Baratov, + Sarat Addepalli, Tobias Nießen (11 contributors) References to bug reports and discussions on issues: + [1] = https://github.com/c-ares/c-ares/issues/220 + [2] = https://github.com/c-ares/c-ares/issues/224 + [3] = https://github.com/c-ares/c-ares/issues/200 + [4] = https://github.com/c-ares/c-ares/issues/207 + [5] = https://github.com/c-ares/c-ares/pull/202 + [6] = https://github.com/c-ares/c-ares/pull/201 + [7] = https://github.com/c-ares/c-ares/pull/193 + [8] = https://github.com/c-ares/c-ares/pull/192 + [9] = https://github.com/c-ares/c-ares/pull/191 + [10] = https://github.com/c-ares/c-ares/pull/187 + [11] = https://c-ares.haxx.se/mail/c-ares-archive-2018-04/0000.shtml + [12] = https://c-ares.haxx.se/mail/c-ares-archive-2018-03/0000.shtml + [13] = https://github.com/c-ares/c-ares/issues/196 - [1] = https://github.com/c-ares/c-ares/commit/18ea99 - [2] = https://github.com/c-ares/c-ares/issues/150 - [3] = https://github.com/c-ares/c-ares/pull/138 - [4] = https://github.com/c-ares/c-ares/pull/144 - [5] = https://github.com/c-ares/c-ares/pull/148 - [6] = https://github.com/c-ares/c-ares/pull/142 - [7] = https://github.com/c-ares/c-ares/pull/175 - [8] = https://c-ares.haxx.se/mail/c-ares-archive-2011-06/0012.shtml - [9] = https://github.com/c-ares/c-ares/pull/180 - [10] = https://github.com/c-ares/c-ares/pull/160 - [11] = https://github.com/c-ares/c-ares/pull/175 - [12] = https://github.com/c-ares/c-ares/pull/142 diff --git a/deps/cares/src/ares_android.c b/deps/cares/src/ares_android.c index ab388110bdeff9..bf77131b58cf84 100644 --- a/deps/cares/src/ares_android.c +++ b/deps/cares/src/ares_android.c @@ -30,6 +30,8 @@ static jmethodID android_cm_active_net_mid = NULL; static jmethodID android_cm_link_props_mid = NULL; /* LinkProperties.getDnsServers */ static jmethodID android_lp_dns_servers_mid = NULL; +/* LinkProperties.getDomains */ +static jmethodID android_lp_domains_mid = NULL; /* List.size */ static jmethodID android_list_size_mid = NULL; /* List.get */ @@ -139,6 +141,12 @@ int ares_library_init_android(jobject connectivity_manager) if (android_lp_dns_servers_mid == NULL) goto cleanup; + /* getDomains in API 21. */ + android_lp_domains_mid = jni_get_method_id(env, obj_cls, "getDomains", + "()Ljava/lang/String;"); + if (android_lp_domains_mid == NULL) + goto cleanup; + (*env)->DeleteLocalRef(env, obj_cls); obj_cls = jni_get_class(env, "java/util/List"); if (obj_cls == NULL) @@ -173,6 +181,7 @@ int ares_library_init_android(jobject connectivity_manager) android_cm_active_net_mid = NULL; android_cm_link_props_mid = NULL; android_lp_dns_servers_mid = NULL; + android_lp_domains_mid = NULL; android_list_size_mid = NULL; android_list_get_mid = NULL; android_ia_host_addr_mid = NULL; @@ -213,6 +222,7 @@ void ares_library_cleanup_android(void) android_cm_active_net_mid = NULL; android_cm_link_props_mid = NULL; android_lp_dns_servers_mid = NULL; + android_lp_domains_mid = NULL; android_list_size_mid = NULL; android_list_get_mid = NULL; android_ia_host_addr_mid = NULL; @@ -341,6 +351,95 @@ char **ares_get_android_server_list(size_t max_servers, (*android_jvm)->DetachCurrentThread(android_jvm); return dns_list; } + +char *ares_get_android_search_domains_list(void) +{ + JNIEnv *env = NULL; + jobject active_network = NULL; + jobject link_properties = NULL; + jstring domains = NULL; + const char *domain; + int res; + size_t i; + size_t cnt = 0; + char *domain_list = NULL; + int need_detatch = 0; + + if (android_jvm == NULL || android_connectivity_manager == NULL) + { + return NULL; + } + + if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL || + android_lp_domains_mid == NULL) + { + return NULL; + } + + res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6); + if (res == JNI_EDETACHED) + { + env = NULL; + res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL); + need_detatch = 1; + } + if (res != JNI_OK || env == NULL) + goto done; + + /* JNI below is equivalent to this Java code. + import android.content.Context; + import android.net.ConnectivityManager; + import android.net.LinkProperties; + + ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + Network an = cm.getActiveNetwork(); + LinkProperties lp = cm.getLinkProperties(an); + String domains = lp.getDomains(); + for (String domain: domains.split(",")) { + String d = domain; + } + + Note: The JNI ConnectivityManager object and all method IDs were previously + initialized in ares_library_init_android. + */ + + active_network = (*env)->CallObjectMethod(env, android_connectivity_manager, + android_cm_active_net_mid); + if (active_network == NULL) + goto done; + + link_properties = + (*env)->CallObjectMethod(env, android_connectivity_manager, + android_cm_link_props_mid, active_network); + if (link_properties == NULL) + goto done; + + /* Get the domains. It is a common separated list of domains to search. */ + domains = (*env)->CallObjectMethod(env, link_properties, + android_lp_domains_mid); + if (domains == NULL) + goto done; + + /* Split on , */ + domain = (*env)->GetStringUTFChars(env, domains, 0); + domain_list = ares_strdup(domain); + (*env)->ReleaseStringUTFChars(env, domains, domain); + (*env)->DeleteLocalRef(env, domains); + +done: + if ((*env)->ExceptionOccurred(env)) + (*env)->ExceptionClear(env); + + if (link_properties != NULL) + (*env)->DeleteLocalRef(env, link_properties); + if (active_network != NULL) + (*env)->DeleteLocalRef(env, active_network); + + if (need_detatch) + (*android_jvm)->DetachCurrentThread(android_jvm); + return domain_list; +} #else /* warning: ISO C forbids an empty translation unit */ typedef int dummy_make_iso_compilers_happy; diff --git a/deps/cares/src/ares_android.h b/deps/cares/src/ares_android.h index ff520f96e8eacc..93fb75f585057e 100644 --- a/deps/cares/src/ares_android.h +++ b/deps/cares/src/ares_android.h @@ -19,6 +19,7 @@ #if defined(ANDROID) || defined(__ANDROID__) char **ares_get_android_server_list(size_t max_servers, size_t *num_servers); +char *ares_get_android_search_domains_list(void); void ares_library_cleanup_android(void); #endif diff --git a/deps/cares/src/ares_create_query.c b/deps/cares/src/ares_create_query.c index 07d7570114403b..1606b1a1004706 100644 --- a/deps/cares/src/ares_create_query.c +++ b/deps/cares/src/ares_create_query.c @@ -94,6 +94,10 @@ int ares_create_query(const char *name, int dnsclass, int type, size_t buflen; unsigned char *buf; + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + return ARES_ENOTFOUND; + /* Set our results early, in case we bail out early with an error. */ *buflenp = 0; *bufp = NULL; @@ -188,7 +192,7 @@ int ares_create_query(const char *name, int dnsclass, int type, * specified in RFC 1035 ("To simplify implementations, the total length of * a domain name (i.e., label octets and label length octets) is restricted * to 255 octets or less."). */ - if (buflen > (MAXCDNAME + HFIXEDSZ + QFIXEDSZ + + if (buflen > (size_t)(MAXCDNAME + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0))) { ares_free (buf); return ARES_EBADNAME; diff --git a/deps/cares/src/ares_destroy.c b/deps/cares/src/ares_destroy.c index 8aa42236aecffe..fed2009ab324ff 100644 --- a/deps/cares/src/ares_destroy.c +++ b/deps/cares/src/ares_destroy.c @@ -36,6 +36,8 @@ void ares_destroy_options(struct ares_options *options) ares_free(options->sortlist); if(options->lookups) ares_free(options->lookups); + if(options->resolvconf_path) + ares_free(options->resolvconf_path); } void ares_destroy(ares_channel channel) @@ -44,7 +46,7 @@ void ares_destroy(ares_channel channel) struct query *query; struct list_node* list_head; struct list_node* list_node; - + if (!channel) return; @@ -85,6 +87,9 @@ void ares_destroy(ares_channel channel) if (channel->lookups) ares_free(channel->lookups); + if (channel->resolvconf_path) + ares_free(channel->resolvconf_path); + ares_free(channel); } diff --git a/deps/cares/src/ares_gethostbyname.c b/deps/cares/src/ares_gethostbyname.c index 7c46d96ceaf214..8187746bb14c7f 100644 --- a/deps/cares/src/ares_gethostbyname.c +++ b/deps/cares/src/ares_gethostbyname.c @@ -95,6 +95,13 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family, return; } + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + { + callback(arg, ARES_ENOTFOUND, 0, NULL); + return; + } + if (fake_hostent(name, family, callback, arg)) return; @@ -339,6 +346,10 @@ static int file_lookup(const char *name, int family, struct hostent **host) int status; int error; + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + return ARES_ENOTFOUND; + #ifdef WIN32 char PATH_HOSTS[MAX_PATH]; win_platform platform; diff --git a/deps/cares/src/ares_getnameinfo.c b/deps/cares/src/ares_getnameinfo.c index c77b1f81537834..aa089417060fec 100644 --- a/deps/cares/src/ares_getnameinfo.c +++ b/deps/cares/src/ares_getnameinfo.c @@ -440,3 +440,14 @@ STATIC_TESTABLE char *ares_striendstr(const char *s1, const char *s2) } return (char *)c1_begin; } + +int ares__is_onion_domain(const char *name) +{ + if (ares_striendstr(name, ".onion")) + return 1; + + if (ares_striendstr(name, ".onion.")) + return 1; + + return 0; +} diff --git a/deps/cares/src/ares_init.c b/deps/cares/src/ares_init.c index 90cfcabdd33a9e..c2c00d65237072 100644 --- a/deps/cares/src/ares_init.c +++ b/deps/cares/src/ares_init.c @@ -169,6 +169,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, channel->sock_config_cb_data = NULL; channel->sock_funcs = NULL; channel->sock_func_cb_data = NULL; + channel->resolvconf_path = NULL; channel->last_server = 0; channel->last_timeout_processed = (time_t)now.tv_sec; @@ -236,16 +237,14 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, /* Something failed; clean up memory we may have allocated. */ if (channel->servers) ares_free(channel->servers); - if (channel->domains) - { - for (i = 0; i < channel->ndomains; i++) - ares_free(channel->domains[i]); - ares_free(channel->domains); - } + if (channel->ndomains != -1) + ares_strsplit_free(channel->domains, channel->ndomains); if (channel->sortlist) ares_free(channel->sortlist); if(channel->lookups) ares_free(channel->lookups); + if(channel->resolvconf_path) + ares_free(channel->resolvconf_path); ares_free(channel); return status; } @@ -299,7 +298,7 @@ int ares_dup(ares_channel *dest, ares_channel src) (*dest)->sock_func_cb_data = src->sock_func_cb_data; strncpy((*dest)->local_dev_name, src->local_dev_name, - sizeof(src->local_dev_name)); + sizeof((*dest)->local_dev_name)); (*dest)->local_ip4 = src->local_ip4; memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6)); @@ -354,6 +353,9 @@ int ares_save_options(ares_channel channel, struct ares_options *options, ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS); (*optmask) |= (channel->rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE); + if (channel->resolvconf_path) + (*optmask) |= ARES_OPT_RESOLVCONF; + /* Copy easy stuff */ options->flags = channel->flags; @@ -426,6 +428,13 @@ int ares_save_options(ares_channel channel, struct ares_options *options, } options->nsort = channel->nsort; + /* copy path for resolv.conf file */ + if (channel->resolvconf_path) { + options->resolvconf_path = ares_strdup(channel->resolvconf_path); + if (!options->resolvconf_path) + return ARES_ENOMEM; + } + return ARES_SUCCESS; } @@ -534,6 +543,14 @@ static int init_by_options(ares_channel channel, channel->nsort = options->nsort; } + /* Set path for resolv.conf file, if given. */ + if ((optmask & ARES_OPT_RESOLVCONF) && !channel->resolvconf_path) + { + channel->resolvconf_path = ares_strdup(options->resolvconf_path); + if (!channel->resolvconf_path && options->resolvconf_path) + return ARES_ENOMEM; + } + channel->optmask = optmask; return ARES_SUCCESS; @@ -997,63 +1014,6 @@ static int compareAddresses(const void *arg1, return 0; } -/* Validate that the ip address matches the subnet (network base and network - * mask) specified. Addresses are specified in standard Network Byte Order as - * 16 bytes, and the netmask is 0 to 128 (bits). - */ -static int ares_ipv6_subnet_matches(const unsigned char netbase[16], - unsigned char netmask, - const unsigned char ipaddr[16]) -{ - unsigned char mask[16] = { 0 }; - unsigned char i; - - /* Misuse */ - if (netmask > 128) - return 0; - - /* Quickly set whole bytes */ - memset(mask, 0xFF, netmask / 8); - - /* Set remaining bits */ - if(netmask % 8) { - mask[netmask / 8] = (unsigned char)(0xff << (8 - (netmask % 8))); - } - - for (i=0; i<16; i++) { - if ((netbase[i] & mask[i]) != (ipaddr[i] & mask[i])) - return 0; - } - - return 1; -} - -static int ares_ipv6_server_blacklisted(const unsigned char ipaddr[16]) -{ - const struct { - const char *netbase; - unsigned char netmask; - } blacklist[] = { - /* Deprecated by [RFC3879] in September 2004. Formerly a Site-Local scoped - * address prefix. Causes known issues on Windows as these are not valid DNS - * servers. */ - { "fec0::", 10 }, - { NULL, 0 } - }; - size_t i; - - for (i=0; blacklist[i].netbase != NULL; i++) { - unsigned char netbase[16]; - - if (ares_inet_pton(AF_INET6, blacklist[i].netbase, netbase) != 1) - continue; - - if (ares_ipv6_subnet_matches(netbase, blacklist[i].netmask, ipaddr)) - return 1; - } - return 0; -} - /* There can be multiple routes to "the Internet". And there can be different * DNS servers associated with each of the interfaces that offer those routes. * We have to assume that any DNS server can serve any request. But, some DNS @@ -1257,7 +1217,7 @@ static int get_DNS_AdaptersAddresses(char **outptr) } else { - addresses[addressesIndex].metric = -1; + addresses[addressesIndex].metric = (ULONG)-1; } /* Record insertion index to make qsort stable */ @@ -1272,20 +1232,10 @@ static int get_DNS_AdaptersAddresses(char **outptr) } else if (namesrvr.sa->sa_family == AF_INET6) { - /* Windows apparently always reports some IPv6 DNS servers that - * prefixed with fec0:0:0:ffff. These ususally do not point to - * working DNS servers, so we ignore them. */ - if (strncmp(addresses[addressesIndex].text, "fec0:0:0:ffff:", 14) == 0) - continue; if (memcmp(&namesrvr.sa6->sin6_addr, &ares_in6addr_any, sizeof(namesrvr.sa6->sin6_addr)) == 0) continue; - if (ares_ipv6_server_blacklisted( - (const unsigned char *)&namesrvr.sa6->sin6_addr) - ) - continue; - /* Allocate room for another address, if necessary, else skip. */ if(addressesIndex == addressesSize) { const size_t newSize = addressesSize + 4; @@ -1309,7 +1259,7 @@ static int get_DNS_AdaptersAddresses(char **outptr) } else { - addresses[addressesIndex].metric = -1; + addresses[addressesIndex].metric = (ULONG)-1; } /* Record insertion index to make qsort stable */ @@ -1394,59 +1344,6 @@ static int get_DNS_Windows(char **outptr) return get_DNS_Registry(outptr); } -static void replace_comma_by_space(char* str) -{ - /* replace ',' by ' ' to coincide with resolv.conf search parameter */ - char *p; - for (p = str; *p != '\0'; p++) - { - if (*p == ',') - *p = ' '; - } -} - -/* Search if 'suffix' is containted in the 'searchlist'. Returns true if yes, - * otherwise false. 'searchlist' is a comma separated list of domain suffixes, - * 'suffix' is one domain suffix, 'len' is the length of 'suffix'. - * The search ignores case. E.g.: - * contains_suffix("abc.def,ghi.jkl", "ghi.JKL") returns true */ -static bool contains_suffix(const char* const searchlist, - const char* const suffix, const size_t len) -{ - const char* beg = searchlist; - const char* end; - if (!*suffix) - return true; - for (;;) - { - while (*beg && (ISSPACE(*beg) || (*beg == ','))) - ++beg; - if (!*beg) - return false; - end = beg; - while (*end && !ISSPACE(*end) && (*end != ',')) - ++end; - if (len == (end - beg) && !strnicmp(beg, suffix, len)) - return true; - beg = end; - } -} - -/* advances list to the next suffix within a comma separated search list. - * len is the length of the next suffix. */ -static size_t next_suffix(const char** list, const size_t advance) -{ - const char* beg = *list + advance; - const char* end; - while (*beg && (ISSPACE(*beg) || (*beg == ','))) - ++beg; - end = beg; - while (*end && !ISSPACE(*end) && (*end != ',')) - ++end; - *list = beg; - return end - beg; -} - /* * get_SuffixList_Windows() * @@ -1467,8 +1364,6 @@ static int get_SuffixList_Windows(char **outptr) DWORD keyNameBuffSize; DWORD keyIdx = 0; char *p = NULL; - const char *pp; - size_t len = 0; *outptr = NULL; @@ -1479,11 +1374,26 @@ static int get_SuffixList_Windows(char **outptr) if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - if (get_REG_SZ(hKey, SEARCHLIST_KEY, outptr)) - replace_comma_by_space(*outptr); + get_REG_SZ(hKey, SEARCHLIST_KEY, outptr); + if (get_REG_SZ(hKey, DOMAIN_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKey); + } + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NT_DNSCLIENT, 0, + KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (get_REG_SZ(hKey, SEARCHLIST_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } RegCloseKey(hKey); - if (*outptr) - return 1; } /* 2. Connection Specific Search List composed of: @@ -1491,45 +1401,53 @@ static int get_SuffixList_Windows(char **outptr) if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, outptr); + if (get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } RegCloseKey(hKey); } - if (!*outptr) - return 0; /* b. Interface SearchList, Domain, DhcpDomain */ - if (!RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0, + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - return 0; - for(;;) { - keyNameBuffSize = sizeof(keyName); - if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize, - 0, NULL, NULL, NULL) - != ERROR_SUCCESS) - break; - if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum) - != ERROR_SUCCESS) - continue; - if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p) || - get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p) || - get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p)) + for(;;) { + keyNameBuffSize = sizeof(keyName); + if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize, + 0, NULL, NULL, NULL) + != ERROR_SUCCESS) + break; + if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum) + != ERROR_SUCCESS) + continue; /* p can be comma separated (SearchList) */ - pp = p; - while ((len = next_suffix(&pp, len)) != 0) + if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p)) { - if (!contains_suffix(*outptr, pp, len)) - commanjoin(outptr, pp, len); + commajoin(outptr, p); + ares_free(p); + p = NULL; } - ares_free(p); - p = NULL; + if (get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + if (get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKeyEnum); } - RegCloseKey(hKeyEnum); + RegCloseKey(hKey); } - RegCloseKey(hKey); - if (*outptr) - replace_comma_by_space(*outptr); + return *outptr != NULL; } @@ -1628,6 +1546,7 @@ static int init_by_resolv_conf(ares_channel channel) char propname[PROP_NAME_MAX]; char propvalue[PROP_VALUE_MAX]=""; char **dns_servers; + char *domains; size_t num_servers; /* Use the Android connectivity manager to get a list @@ -1652,6 +1571,12 @@ static int init_by_resolv_conf(ares_channel channel) } ares_free(dns_servers); } + if (channel->ndomains == -1) + { + domains = ares_get_android_search_domains_list(); + set_search(channel, domains); + ares_free(domains); + } # ifdef HAVE___SYSTEM_PROPERTY_GET /* Old way using the system property still in place as @@ -1740,6 +1665,7 @@ static int init_by_resolv_conf(ares_channel channel) size_t linesize; int error; int update_domains; + const char *resolvconf_path; /* Don't read resolv.conf and friends if we don't have to */ if (ARES_CONFIG_CHECK(channel)) @@ -1748,7 +1674,14 @@ static int init_by_resolv_conf(ares_channel channel) /* Only update search domains if they're not already specified */ update_domains = (channel->ndomains == -1); - fp = fopen(PATH_RESOLV_CONF, "r"); + /* Support path for resolvconf filename set by ares_init_options */ + if(channel->resolvconf_path) { + resolvconf_path = channel->resolvconf_path; + } else { + resolvconf_path = PATH_RESOLV_CONF; + } + + fp = fopen(resolvconf_path, "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { @@ -1759,10 +1692,10 @@ static int init_by_resolv_conf(ares_channel channel) else if ((p = try_config(line, "search", ';')) && update_domains) status = set_search(channel, p); else if ((p = try_config(line, "nameserver", ';')) && - channel->nservers == -1) + channel->nservers == -1) status = config_nameserver(&servers, &nservers, p); else if ((p = try_config(line, "sortlist", ';')) && - channel->nsort == -1) + channel->nsort == -1) status = config_sortlist(&sortlist, &nsort, p); else if ((p = try_config(line, "options", ';'))) status = set_options(channel, p); @@ -1782,7 +1715,7 @@ static int init_by_resolv_conf(ares_channel channel) break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", - error, strerror(error))); + error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF)); status = ARES_EFILE; } @@ -2050,6 +1983,11 @@ static int init_by_defaults(ares_channel channel) ares_free(channel->lookups); channel->lookups = NULL; } + + if(channel->resolvconf_path) { + ares_free(channel->resolvconf_path); + channel->resolvconf_path = NULL; + } } if(hostname) @@ -2114,6 +2052,76 @@ static int config_lookup(ares_channel channel, const char *str, #endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ & !CARES_USE_LIBRESOLV */ #ifndef WATT32 +/* Validate that the ip address matches the subnet (network base and network + * mask) specified. Addresses are specified in standard Network Byte Order as + * 16 bytes, and the netmask is 0 to 128 (bits). + */ +static int ares_ipv6_subnet_matches(const unsigned char netbase[16], + unsigned char netmask, + const unsigned char ipaddr[16]) +{ + unsigned char mask[16] = { 0 }; + unsigned char i; + + /* Misuse */ + if (netmask > 128) + return 0; + + /* Quickly set whole bytes */ + memset(mask, 0xFF, netmask / 8); + + /* Set remaining bits */ + if(netmask % 8) { + mask[netmask / 8] = (unsigned char)(0xff << (8 - (netmask % 8))); + } + + for (i=0; i<16; i++) { + if ((netbase[i] & mask[i]) != (ipaddr[i] & mask[i])) + return 0; + } + + return 1; +} + +/* Return true iff the IPv6 ipaddr is blacklisted. */ +static int ares_ipv6_server_blacklisted(const unsigned char ipaddr[16]) +{ + /* A list of blacklisted IPv6 subnets. */ + const struct { + const unsigned char netbase[16]; + unsigned char netmask; + } blacklist[] = { + /* fec0::/10 was deprecated by [RFC3879] in September 2004. Formerly a + * Site-Local scoped address prefix. These are never valid DNS servers, + * but are known to be returned at least sometimes on Windows and Android. + */ + { + { + 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + 10 + } + }; + size_t i; + + /* See if ipaddr matches any of the entries in the blacklist. */ + for (i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); ++i) { + if (ares_ipv6_subnet_matches( + blacklist[i].netbase, blacklist[i].netmask, ipaddr)) + return 1; + } + return 0; +} + +/* Add the IPv4 or IPv6 nameservers in str (separated by commas) to the + * servers list, updating servers and nservers as required. + * + * This will silently ignore blacklisted IPv6 nameservers as detected by + * ares_ipv6_server_blacklisted(). + * + * Returns an error code on failure, else ARES_SUCCESS. + */ static int config_nameserver(struct server_state **servers, int *nservers, char *str) { @@ -2148,7 +2156,10 @@ static int config_nameserver(struct server_state **servers, int *nservers, /* Convert textual address to binary format. */ if (ares_inet_pton(AF_INET, txtaddr, &host.addrV4) == 1) host.family = AF_INET; - else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1) + else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1 + /* Silently skip blacklisted IPv6 servers. */ + && !ares_ipv6_server_blacklisted( + (const unsigned char *)&host.addrV6)) host.family = AF_INET6; else continue; @@ -2271,61 +2282,22 @@ static int config_sortlist(struct apattern **sortlist, int *nsort, static int set_search(ares_channel channel, const char *str) { - int n; - const char *p, *q; + size_t cnt; if(channel->ndomains != -1) { /* LCOV_EXCL_START: all callers check ndomains == -1 */ /* if we already have some domains present, free them first */ - for(n=0; n < channel->ndomains; n++) - ares_free(channel->domains[n]); - ares_free(channel->domains); + ares_strsplit_free(channel->domains, channel->ndomains); channel->domains = NULL; channel->ndomains = -1; } /* LCOV_EXCL_STOP */ - /* Count the domains given. */ - n = 0; - p = str; - while (*p) - { - while (*p && !ISSPACE(*p)) - p++; - while (ISSPACE(*p)) - p++; - n++; - } - - if (!n) - { - channel->ndomains = 0; - return ARES_SUCCESS; - } - - channel->domains = ares_malloc(n * sizeof(char *)); - if (!channel->domains) - return ARES_ENOMEM; - - /* Now copy the domains. */ - n = 0; - p = str; - while (*p) - { - channel->ndomains = n; - q = p; - while (*q && !ISSPACE(*q)) - q++; - channel->domains[n] = ares_malloc(q - p + 1); - if (!channel->domains[n]) - return ARES_ENOMEM; - memcpy(channel->domains[n], p, q - p); - channel->domains[n][q - p] = 0; - p = q; - while (ISSPACE(*p)) - p++; - n++; - } - channel->ndomains = n; + channel->domains = ares_strsplit(str, ", ", 1, &cnt); + channel->ndomains = (int)cnt; + if (channel->domains == NULL || channel->ndomains == 0) { + channel->domains = NULL; + channel->ndomains = -1; + } return ARES_SUCCESS; } diff --git a/deps/cares/src/ares_library_init.c b/deps/cares/src/ares_library_init.c index 88e7a537480813..67563499bec276 100644 --- a/deps/cares/src/ares_library_init.c +++ b/deps/cares/src/ares_library_init.c @@ -40,9 +40,19 @@ static unsigned int ares_initialized; static int ares_init_flags; /* library-private global vars with visibility across the whole library */ -void *(*ares_malloc)(size_t size) = malloc; -void *(*ares_realloc)(void *ptr, size_t size) = realloc; -void (*ares_free)(void *ptr) = free; +#if defined(WIN32) +/* We need indirections to handle Windows DLL rules. */ +static void *default_malloc(size_t size) { return malloc(size); } +static void *default_realloc(void *p, size_t size) { return realloc(p, size); } +static void default_free(void *p) { free(p); } +#else +# define default_malloc malloc +# define default_realloc realloc +# define default_free free +#endif +void *(*ares_malloc)(size_t size) = default_malloc; +void *(*ares_realloc)(void *ptr, size_t size) = default_realloc; +void (*ares_free)(void *ptr) = default_free; #ifdef USE_WINSOCK static HMODULE hnd_iphlpapi; diff --git a/deps/cares/src/ares_options.c b/deps/cares/src/ares_options.c index c3cbd1df707566..de49de4625996f 100644 --- a/deps/cares/src/ares_options.c +++ b/deps/cares/src/ares_options.c @@ -153,6 +153,9 @@ int ares_set_servers(ares_channel channel, if (!channel) return ARES_ENODATA; + if (!ares__is_list_empty(&channel->all_queries)) + return ARES_ENOTIMP; + ares__destroy_servers_state(channel); for (srvr = servers; srvr; srvr = srvr->next) @@ -202,6 +205,9 @@ int ares_set_servers_ports(ares_channel channel, if (!channel) return ARES_ENODATA; + if (!ares__is_list_empty(&channel->all_queries)) + return ARES_ENOTIMP; + ares__destroy_servers_state(channel); for (srvr = servers; srvr; srvr = srvr->next) @@ -258,8 +264,6 @@ static int set_servers_csv(ares_channel channel, if (!channel) return ARES_ENODATA; - ares__destroy_servers_state(channel); - i = strlen(_csv); if (i == 0) return ARES_SUCCESS; /* blank all servers */ diff --git a/deps/cares/src/ares_parse_ptr_reply.c b/deps/cares/src/ares_parse_ptr_reply.c index 976a5311a24d79..29e22cb17b6bd6 100644 --- a/deps/cares/src/ares_parse_ptr_reply.c +++ b/deps/cares/src/ares_parse_ptr_reply.c @@ -52,6 +52,7 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, int aliascnt = 0; int alias_alloc = 8; char ** aliases; + size_t rr_data_len; /* Set *host to NULL for all failure cases. */ *host = NULL; @@ -124,14 +125,15 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, if (hostname) ares_free(hostname); hostname = rr_data; - aliases[aliascnt] = ares_malloc((strlen(rr_data)+1) * sizeof(char)); + rr_data_len = strlen(rr_data)+1; + aliases[aliascnt] = ares_malloc(rr_data_len * sizeof(char)); if (!aliases[aliascnt]) { ares_free(rr_name); status = ARES_ENOMEM; break; } - strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1); + strncpy(aliases[aliascnt], rr_data, rr_data_len); aliascnt++; if (aliascnt >= alias_alloc) { char **ptr; diff --git a/deps/cares/src/ares_private.h b/deps/cares/src/ares_private.h index 5d773869c72a97..1990f6902fc75e 100644 --- a/deps/cares/src/ares_private.h +++ b/deps/cares/src/ares_private.h @@ -52,18 +52,19 @@ #if defined(WIN32) && !defined(WATT32) -#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" -#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" -#define WIN_DNSCLIENT "Software\\Policies\\Microsoft\\System\\DNSClient" -#define NAMESERVER "NameServer" -#define DHCPNAMESERVER "DhcpNameServer" -#define DATABASEPATH "DatabasePath" -#define WIN_PATH_HOSTS "\\hosts" -#define SEARCHLIST_KEY "SearchList" +#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" +#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" +#define WIN_DNSCLIENT "Software\\Policies\\Microsoft\\System\\DNSClient" +#define WIN_NT_DNSCLIENT "Software\\Policies\\Microsoft\\Windows NT\\DNSClient" +#define NAMESERVER "NameServer" +#define DHCPNAMESERVER "DhcpNameServer" +#define DATABASEPATH "DatabasePath" +#define WIN_PATH_HOSTS "\\hosts" +#define SEARCHLIST_KEY "SearchList" #define PRIMARYDNSSUFFIX_KEY "PrimaryDNSSuffix" -#define INTERFACES_KEY "Interfaces" -#define DOMAIN_KEY "Domain" -#define DHCPDOMAIN_KEY "DhcpDomain" +#define INTERFACES_KEY "Interfaces" +#define DOMAIN_KEY "Domain" +#define DHCPDOMAIN_KEY "DhcpDomain" #elif defined(WATT32) @@ -100,6 +101,7 @@ #endif #include "ares_strdup.h" +#include "ares_strsplit.h" #ifndef HAVE_STRCASECMP # include "ares_strcasecmp.h" @@ -323,8 +325,14 @@ struct ares_channeldata { const struct ares_socket_functions * sock_funcs; void *sock_func_cb_data; + + /* Path for resolv.conf file, configurable via ares_options */ + char *resolvconf_path; }; +/* Does the domain end in ".onion" or ".onion."? Case-insensitive. */ +int ares__is_onion_domain(const char *name); + /* Memory management functions */ extern void *(*ares_malloc)(size_t size); extern void *(*ares_realloc)(void *ptr, size_t size); diff --git a/deps/cares/src/ares_process.c b/deps/cares/src/ares_process.c index df85524f624cfd..df9f290bb133a6 100644 --- a/deps/cares/src/ares_process.c +++ b/deps/cares/src/ares_process.c @@ -53,6 +53,7 @@ #include #include +#include #include "ares.h" #include "ares_dns.h" @@ -871,8 +872,32 @@ void ares__send_query(ares_channel channel, struct query *query, return; } } - timeplus = channel->timeout << (query->try_count / channel->nservers); - timeplus = (timeplus * (9 + (rand () & 7))) / 16; + + /* For each trip through the entire server list, double the channel's + * assigned timeout, avoiding overflow. If channel->timeout is negative, + * leave it as-is, even though that should be impossible here. + */ + timeplus = channel->timeout; + { + /* How many times do we want to double it? Presume sane values here. */ + const int shift = query->try_count / channel->nservers; + + /* Is there enough room to shift timeplus left that many times? + * + * To find out, confirm that all of the bits we'll shift away are zero. + * Stop considering a shift if we get to the point where we could shift + * a 1 into the sign bit (i.e. when shift is within two of the bit + * count). + * + * This has the side benefit of leaving negative numbers unchanged. + */ + if(shift <= (int)(sizeof(int) * CHAR_BIT - 1) + && (timeplus >> (sizeof(int) * CHAR_BIT - 1 - shift)) == 0) + { + timeplus <<= shift; + } + } + query->timeout = *now; timeadd(&query->timeout, timeplus); /* Keep track of queries bucketed by timeout, so we can process diff --git a/deps/cares/src/ares_search.c b/deps/cares/src/ares_search.c index 68e852574f0909..001c3482a7dd5d 100644 --- a/deps/cares/src/ares_search.c +++ b/deps/cares/src/ares_search.c @@ -54,6 +54,13 @@ void ares_search(ares_channel channel, const char *name, int dnsclass, const char *p; int status, ndots; + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + { + callback(arg, ARES_ENOTFOUND, 0, NULL, 0); + return; + } + /* If name only yields one domain to search, then we don't have * to keep extra state, so just do an ares_query(). */ diff --git a/deps/cares/src/ares_send.c b/deps/cares/src/ares_send.c index 88c0035520c504..f4f1f951197de8 100644 --- a/deps/cares/src/ares_send.c +++ b/deps/cares/src/ares_send.c @@ -60,6 +60,12 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, callback(arg, ARES_ENOMEM, 0, NULL, 0); return; } + if (channel->nservers < 1) + { + ares_free(query); + callback(arg, ARES_ESERVFAIL, 0, NULL, 0); + return; + } query->server_info = ares_malloc(channel->nservers * sizeof(query->server_info[0])); if (!query->server_info) diff --git a/deps/cares/src/ares_strsplit.c b/deps/cares/src/ares_strsplit.c new file mode 100644 index 00000000000000..b57a30f2a99c35 --- /dev/null +++ b/deps/cares/src/ares_strsplit.c @@ -0,0 +1,174 @@ +/* Copyright (C) 2018 by John Schember + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares_strsplit.h" +#include "ares.h" +#include "ares_private.h" + +static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive) +{ + size_t len; + size_t i; + + len = strlen(str); + for (i=0; i + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +/* Split a string on delem skipping empty elements. + * + * param in String to split. + * param delims String of characters to treat as a delimitor. + * Each character in the string is a delimitor so + * there can be multiple delimitors to split on. + * E.g. ", " will split on all comma's and spaces. + * param make_set Have the list be a Set where there are no + * duplicate entries. 1 for true, 0 or false. + * param num_elm Return parameter of the number of elements + * in the result array. + * + * returns an allocated array of allocated string elements. + * + */ +char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm); + +/* Frees the result returned from ares_strsplit(). */ +void ares_strsplit_free(char **elms, size_t num_elm); + + +#endif /* HEADER_CARES_STRSPLIT_H */ diff --git a/deps/cares/src/inet_ntop.c b/deps/cares/src/inet_ntop.c index ce3ce588d3c0bd..1935a871cede6d 100644 --- a/deps/cares/src/inet_ntop.c +++ b/deps/cares/src/inet_ntop.c @@ -180,8 +180,7 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size) tp += sprintf(tp, "%x", words[i]); } /* Was it a trailing run of 0x00's? */ - if (best.base != -1 && (best.base + best.len) == - (NS_IN6ADDRSZ / NS_INT16SZ)) + if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) *tp++ = ':'; *tp++ = '\0'; diff --git a/deps/llhttp/LICENSE-MIT b/deps/llhttp/LICENSE-MIT new file mode 100644 index 00000000000000..6c1512dd6bcd6d --- /dev/null +++ b/deps/llhttp/LICENSE-MIT @@ -0,0 +1,22 @@ +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2018. + +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/llhttp/README.md b/deps/llhttp/README.md new file mode 100644 index 00000000000000..bca973f80d0025 --- /dev/null +++ b/deps/llhttp/README.md @@ -0,0 +1,129 @@ +# llhttp +[![Build Status](https://secure.travis-ci.org/indutny/llhttp.svg)](http://travis-ci.org/indutny/llhttp) + +Port of [http_parser][0] to [llparse][1]. + +## Why? + +Let's face it, [http_parser][0] is practically unmaintainable. Even +introduction of a single new method results in a significant code churn. + +This project aims to: + +* Make it maintainable +* Verifiable +* Improving benchmarks where possible + +## How? + +Over time, different approaches for improving [http_parser][0]'s code base +were tried. However, all of them failed due to resulting significant performance +degradation. + +This project is a port of [http_parser][0] to TypeScript. [llparse][1] is used +to generate the output C and/or bitcode artifacts, which could be compiled and +linked with the embedder's program (like [Node.js][7]). + +## Peformance + +So far llhttp outperforms http_parser: + +| | input size | bandwidth | reqs/sec | time | +|:----------------|-----------:|-------------:|-----------:|--------:| +| **llhttp** _(C)_ | 8192.00 mb | 1497.88 mb/s | 3020458.87 ops/sec | 5.47 s | +| **llhttp** _(bitcode)_ | 8192.00 mb | 1131.75 mb/s | 2282171.24 ops/sec | 7.24 s | +| **http_parser** | 8192.00 mb | 694.66 mb/s | 1406180.33 req/sec | 11.79 s | + +llhttp is faster by approximately **116%**. + +## Maintenance + +llhttp project has about 1400 lines of TypeScript code describing the parser +itself and around 450 lines of C code and headers providing the helper methods. +The whole [http_parser][0] is implemented in approximately 2500 lines of C, and +436 lines of headers. + +All optimizations and multi-character matching in llhttp are generated +automatically, and thus doesn't add any extra maintenance cost. On the contrary, +most of http_parser's code is hand-optimized and unrolled. Instead describing +"how" it should parse the HTTP requests/responses, a maintainer should +implement the new features in [http_parser][0] cautiously, considering +possible performance degradation and manually optimizing the new code. + +## Verification + +The state machine graph is encoded explicitly in llhttp. The [llparse][1] +automatically checks the graph for absence of loops and correct reporting of the +input ranges (spans) like header names and values. In the future, additional +checks could be performed to get even stricter verification of the llhttp. + +## Usage + +```C +#include "llhttp.h" + +llhttp_t parser; +llhttp_settings_t settings; + +/* Initialize user callbacks and settings */ +llhttp_settings_init(&settings); + +/* Set user callback */ +settings.on_message_complete = handle_on_message_complete; + +/* Initialize the parser in HTTP_BOTH mode, meaning that it will select between + * HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first + * input. + */ +llhttp_init(&parser, HTTP_BOTH, &settings); + +/* Use `llhttp_set_type(&parser, HTTP_REQUEST);` to override the mode */ + +/* Parse request! */ +const char* request = "GET / HTTP/1.1\r\n\r\n"; +int request_len = strlen(request); + +enum llhttp_errno err = llhttp_execute(&parser, request, request_len); +if (err == HPE_OK) { + /* Successfully parsed! */ +} else { + fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), + parser.reason); +} +``` + +--- + +#### LICENSE + +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2018. + +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. + +[0]: https://github.com/nodejs/http-parser +[1]: https://github.com/indutny/llparse +[2]: https://en.wikipedia.org/wiki/Register_allocation#Spilling +[3]: https://en.wikipedia.org/wiki/Tail_call +[4]: https://llvm.org/docs/LangRef.html +[5]: https://llvm.org/docs/LangRef.html#call-instruction +[6]: https://clang.llvm.org/ +[7]: https://github.com/nodejs/node diff --git a/deps/llhttp/common.gypi b/deps/llhttp/common.gypi new file mode 100644 index 00000000000000..ef7549f809df26 --- /dev/null +++ b/deps/llhttp/common.gypi @@ -0,0 +1,46 @@ +{ + 'target_defaults': { + 'default_configuration': 'Debug', + 'configurations': { + # TODO: hoist these out and put them somewhere common, because + # RuntimeLibrary MUST MATCH across the entire project + 'Debug': { + 'defines': [ 'DEBUG', '_DEBUG' ], + 'cflags': [ '-Wall', '-Wextra', '-O0', '-g', '-ftrapv' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 1, # static debug + }, + }, + }, + 'Release': { + 'defines': [ 'NDEBUG' ], + 'cflags': [ '-Wall', '-Wextra', '-O3' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 0, # static release + }, + }, + } + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + # Compile as C++. llhttp.c is actually C99, but C++ is + # close enough in this case. + 'CompileAs': 2, + }, + 'VCLibrarianTool': { + }, + 'VCLinkerTool': { + 'GenerateDebugInformation': 'true', + }, + }, + 'conditions': [ + ['OS == "win"', { + 'defines': [ + 'WIN32' + ], + }] + ], + }, +} diff --git a/deps/llhttp/include/llhttp.h b/deps/llhttp/include/llhttp.h new file mode 100644 index 00000000000000..c114d11ffa9353 --- /dev/null +++ b/deps/llhttp/include/llhttp.h @@ -0,0 +1,353 @@ +#ifndef INCLUDE_LLHTTP_H_ +#define INCLUDE_LLHTTP_H_ + +#define LLHTTP_VERSION_MAJOR 1 +#define LLHTTP_VERSION_MINOR 0 +#define LLHTTP_VERSION_PATCH 0 + +#ifndef INCLUDE_LLHTTP_ITSELF_H_ +#define INCLUDE_LLHTTP_ITSELF_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct llhttp__internal_s llhttp__internal_t; +struct llhttp__internal_s { + int32_t _index; + void* _span_pos0; + void* _span_cb0; + int32_t error; + const char* reason; + const char* error_pos; + void* data; + void* _current; + uint64_t content_length; + uint8_t type; + uint8_t method; + uint8_t http_major; + uint8_t http_minor; + uint8_t header_state; + uint8_t flags; + uint8_t upgrade; + uint16_t status_code; + uint8_t finish; + void* settings; +}; + +int llhttp__internal_init(llhttp__internal_t* s); +int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_ITSELF_H_ */ + +#ifndef LLLLHTTP_C_HEADERS_ +#define LLLLHTTP_C_HEADERS_ +#ifdef __cplusplus +extern "C" { +#endif + +enum llhttp_errno { + HPE_OK = 0, + HPE_INTERNAL = 1, + HPE_STRICT = 2, + HPE_LF_EXPECTED = 3, + HPE_UNEXPECTED_CONTENT_LENGTH = 4, + HPE_CLOSED_CONNECTION = 5, + HPE_INVALID_METHOD = 6, + HPE_INVALID_URL = 7, + HPE_INVALID_CONSTANT = 8, + HPE_INVALID_VERSION = 9, + HPE_INVALID_HEADER_TOKEN = 10, + HPE_INVALID_CONTENT_LENGTH = 11, + HPE_INVALID_CHUNK_SIZE = 12, + HPE_INVALID_STATUS = 13, + HPE_INVALID_EOF_STATE = 14, + HPE_CB_MESSAGE_BEGIN = 15, + HPE_CB_HEADERS_COMPLETE = 16, + HPE_CB_MESSAGE_COMPLETE = 17, + HPE_CB_CHUNK_HEADER = 18, + HPE_CB_CHUNK_COMPLETE = 19, + HPE_PAUSED = 20, + HPE_PAUSED_UPGRADE = 21, + HPE_USER = 22 +}; +typedef enum llhttp_errno llhttp_errno_t; + +enum llhttp_flags { + F_CONNECTION_KEEP_ALIVE = 0x1, + F_CONNECTION_CLOSE = 0x2, + F_CONNECTION_UPGRADE = 0x4, + F_CHUNKED = 0x8, + F_UPGRADE = 0x10, + F_CONTENT_LENGTH = 0x20, + F_SKIPBODY = 0x40, + F_TRAILING = 0x80 +}; +typedef enum llhttp_flags llhttp_flags_t; + +enum llhttp_type { + HTTP_BOTH = 0, + HTTP_REQUEST = 1, + HTTP_RESPONSE = 2 +}; +typedef enum llhttp_type llhttp_type_t; + +enum llhttp_finish { + HTTP_FINISH_SAFE = 0, + HTTP_FINISH_SAFE_WITH_CB = 1, + HTTP_FINISH_UNSAFE = 2 +}; +typedef enum llhttp_finish llhttp_finish_t; + +enum llhttp_method { + HTTP_DELETE = 0, + HTTP_GET = 1, + HTTP_HEAD = 2, + HTTP_POST = 3, + HTTP_PUT = 4, + HTTP_CONNECT = 5, + HTTP_OPTIONS = 6, + HTTP_TRACE = 7, + HTTP_COPY = 8, + HTTP_LOCK = 9, + HTTP_MKCOL = 10, + HTTP_MOVE = 11, + HTTP_PROPFIND = 12, + HTTP_PROPPATCH = 13, + HTTP_SEARCH = 14, + HTTP_UNLOCK = 15, + HTTP_BIND = 16, + HTTP_REBIND = 17, + HTTP_UNBIND = 18, + HTTP_ACL = 19, + HTTP_REPORT = 20, + HTTP_MKACTIVITY = 21, + HTTP_CHECKOUT = 22, + HTTP_MERGE = 23, + HTTP_MSEARCH = 24, + HTTP_NOTIFY = 25, + HTTP_SUBSCRIBE = 26, + HTTP_UNSUBSCRIBE = 27, + HTTP_PATCH = 28, + HTTP_PURGE = 29, + HTTP_MKCALENDAR = 30, + HTTP_LINK = 31, + HTTP_UNLINK = 32, + HTTP_SOURCE = 33 +}; +typedef enum llhttp_method llhttp_method_t; + +#define HTTP_ERRNO_MAP(XX) \ + XX(0, OK, OK) \ + XX(1, INTERNAL, INTERNAL) \ + XX(2, STRICT, STRICT) \ + XX(3, LF_EXPECTED, LF_EXPECTED) \ + XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \ + XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \ + XX(6, INVALID_METHOD, INVALID_METHOD) \ + XX(7, INVALID_URL, INVALID_URL) \ + XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \ + XX(9, INVALID_VERSION, INVALID_VERSION) \ + XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \ + XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \ + XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \ + XX(13, INVALID_STATUS, INVALID_STATUS) \ + XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \ + XX(15, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \ + XX(16, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \ + XX(17, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \ + XX(18, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \ + XX(19, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \ + XX(20, PAUSED, PAUSED) \ + XX(21, PAUSED_UPGRADE, PAUSED_UPGRADE) \ + XX(22, USER, USER) \ + + +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + XX(30, MKCALENDAR, MKCALENDAR) \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + XX(33, SOURCE, SOURCE) \ + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* LLLLHTTP_C_HEADERS_ */ + +#ifndef INCLUDE_LLHTTP_API_H_ +#define INCLUDE_LLHTTP_API_H_ +#ifdef __cplusplus +extern "C" { +#endif + +typedef llhttp__internal_t llhttp_t; +typedef struct llhttp_settings_s llhttp_settings_t; + +typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length); +typedef int (*llhttp_cb)(llhttp_t*); + +struct llhttp_settings_s { + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_begin; + + llhttp_data_cb on_url; + llhttp_data_cb on_status; + llhttp_data_cb on_header_field; + llhttp_data_cb on_header_value; + + /* Possible return values: + * 0 - Proceed normally + * 1 - Assume that request/response has no body, and proceed to parsing the + * next message + * 2 - Assume absence of body (as above) and make `llhttp_execute()` return + * `HPE_PAUSED_UPGRADE` + * -1 - Error + * `HPE_PAUSED` + */ + llhttp_cb on_headers_complete; + + llhttp_data_cb on_body; + + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_complete; + + /* When on_chunk_header is called, the current chunk length is stored + * in parser->content_length. + * Possible return values 0, -1, `HPE_PAUSED` + */ + llhttp_cb on_chunk_header; + llhttp_cb on_chunk_complete; +}; + +/* Initialize the parser with specific type and user settings */ +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings); + +/* Initialize the settings object */ +void llhttp_settings_init(llhttp_settings_t* settings); + +/* Parse full or partial request/response, invoking user callbacks along the + * way. + * + * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing + * interrupts, and such errno is returned from `llhttp_execute()`. If + * `HPE_PAUSED` was used as a errno, the execution can be resumed with + * `llhttp_resume()` call. + * + * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE` + * is returned after fully parsing the request/response. If the user wishes to + * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`. + */ +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len); + +/* This method should be called when the other side has no further bytes to + * send (e.g. shutdown of readable side of the TCP connection.) + * + * Requests without `Content-Length` and other messages might require treating + * all incoming bytes as the part of the body, up to the last byte of the + * connection. This method will invoke `on_message_complete()` callback if the + * request was terminated safely. Otherwise a error code would be returned. + */ +llhttp_errno_t llhttp_finish(llhttp_t* parser); + +/* Returns `1` if the incoming message is parsed until the last byte, and has + * to be completed by calling `llhttp_finish()` on EOF + */ +int llhttp_message_needs_eof(const llhttp_t* parser); + +/* Returns `1` if there might be any other messages following the last that was + * successfuly parsed. + */ +int llhttp_should_keep_alive(const llhttp_t* parser); + +/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set + * appropriate error reason. + * + * Important: do not call this from user callbacks! User callbacks must return + * `HPE_PAUSED` if pausing is required. + */ +void llhttp_pause(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED`. + */ +void llhttp_resume(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE` + */ +void llhttp_resume_after_upgrade(llhttp_t* parser); + +/* Returns the latest return error */ +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser); + +/* Returns the verbal explanation of the latest returned error. + * + * Note: User callback should set error reason when returning the error. See + * `llhttp_set_error_reason()` for details. + */ +const char* llhttp_get_error_reason(const llhttp_t* parser); + +/* Assign verbal description to the returned error. Must be called in user + * callbacks right before returning the errno. + * + * Note: `HPE_USER` error code might be useful in user callbacks. + */ +void llhttp_set_error_reason(llhttp_t* parser, const char* reason); + +/* Returns the pointer to the last parsed byte before the returned error. The + * pointer is relative to the `data` argument of `llhttp_execute()`. + * + * Note: this method might be useful for counting the number of parsed bytes. + */ +const char* llhttp_get_error_pos(const llhttp_t* parser); + +/* Returns textual name of error code */ +const char* llhttp_errno_name(llhttp_errno_t err); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_API_H_ */ + +#endif /* INCLUDE_LLHTTP_H_ */ diff --git a/deps/llhttp/llhttp.gyp b/deps/llhttp/llhttp.gyp new file mode 100644 index 00000000000000..4acc79bdf399fc --- /dev/null +++ b/deps/llhttp/llhttp.gyp @@ -0,0 +1,13 @@ +{ + 'targets': [ + { + 'target_name': 'llhttp', + 'type': 'static_library', + 'include_dirs': [ '.', 'include' ], + 'direct_dependent_settings': { + 'include_dirs': [ 'include' ], + }, + 'sources': [ 'src/llhttp.c', 'src/api.c', 'src/http.c' ], + }, + ] +} diff --git a/deps/llhttp/src/api.c b/deps/llhttp/src/api.c new file mode 100644 index 00000000000000..37a5dcd183e0f6 --- /dev/null +++ b/deps/llhttp/src/api.c @@ -0,0 +1,205 @@ +#include +#include +#include + +#include "llhttp.h" + +#define CALLBACK_MAYBE(PARSER, NAME, ...) \ + do { \ + llhttp_settings_t* settings; \ + settings = (llhttp_settings_t*) (PARSER)->settings; \ + if (settings == NULL || settings->NAME == NULL) { \ + err = 0; \ + break; \ + } \ + err = settings->NAME(__VA_ARGS__); \ + } while (0) + +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings) { + llhttp__internal_init(parser); + + parser->type = type; + parser->settings = (void*) settings; +} + + +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) { + return llhttp__internal_execute(parser, data, data + len); +} + + +void llhttp_settings_init(llhttp_settings_t* settings) { + memset(settings, 0, sizeof(*settings)); +} + + +llhttp_errno_t llhttp_finish(llhttp_t* parser) { + int err; + + /* We're in an error state. Don't bother doing anything. */ + if (parser->error != 0) { + return 0; + } + + switch (parser->finish) { + case HTTP_FINISH_SAFE_WITH_CB: + CALLBACK_MAYBE(parser, on_message_complete, parser); + if (err != HPE_OK) return err; + + /* FALLTHROUGH */ + case HTTP_FINISH_SAFE: + return HPE_OK; + case HTTP_FINISH_UNSAFE: + parser->reason = "Invalid EOF state"; + return HPE_INVALID_EOF_STATE; + default: + abort(); + } +} + + +void llhttp_pause(llhttp_t* parser) { + if (parser->error != HPE_OK) { + return; + } + + parser->error = HPE_PAUSED; + parser->reason = "Paused"; +} + + +void llhttp_resume(llhttp_t* parser) { + if (parser->error != HPE_PAUSED) { + return; + } + + parser->error = 0; +} + + +void llhttp_resume_after_upgrade(llhttp_t* parser) { + if (parser->error != HPE_PAUSED_UPGRADE) { + return; + } + + parser->error = 0; +} + + +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) { + return parser->error; +} + + +const char* llhttp_get_error_reason(const llhttp_t* parser) { + return parser->reason; +} + + +void llhttp_set_error_reason(llhttp_t* parser, const char* reason) { + parser->reason = reason; +} + + +const char* llhttp_get_error_pos(const llhttp_t* parser) { + return parser->error_pos; +} + + +const char* llhttp_errno_name(llhttp_errno_t err) { +#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME; + switch (err) { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) + default: abort(); + } +#undef HTTP_ERRNO_GEN +} + + +/* Callbacks */ + + +int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_begin, s); + return err; +} + + +int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_url, s, p, endp - p); + return err; +} + + +int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_status, s, p, endp - p); + return err; +} + + +int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_field, s, p, endp - p); + return err; +} + + +int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_value, s, p, endp - p); + return err; +} + + +int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_headers_complete, s); + return err; +} + + +int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_complete, s); + return err; +} + + +int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_body, s, p, endp - p); + return err; +} + + +int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_header, s); + return err; +} + + +int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_complete, s); + return err; +} + + +/* Private */ + + +void llhttp__debug(llhttp_t* s, const char* p, const char* endp, + const char* msg) { + if (p == endp) { + fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type, + s->flags, msg); + } else { + fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s, + s->type, s->flags, *p, msg); + } +} diff --git a/deps/llhttp/src/http.c b/deps/llhttp/src/http.c new file mode 100644 index 00000000000000..67834c2d377c49 --- /dev/null +++ b/deps/llhttp/src/http.c @@ -0,0 +1,120 @@ +#include +#ifndef LLHTTP__TEST +# include "llhttp.h" +#else +# define llhttp_t llparse_t +#endif /* */ + +int llhttp_message_needs_eof(const llhttp_t* parser); +int llhttp_should_keep_alive(const llhttp_t* parser); + +int llhttp__before_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + /* Set this here so that on_headers_complete() callbacks can see it */ + if ((parser->flags & F_UPGRADE) && + (parser->flags & F_CONNECTION_UPGRADE)) { + /* For responses, "Upgrade: foo" and "Connection: upgrade" are + * mandatory only when it is a 101 Switching Protocols response, + * otherwise it is purely informational, to announce support. + */ + parser->upgrade = + (parser->type == HTTP_REQUEST || parser->status_code == 101); + } else { + parser->upgrade = (parser->method == HTTP_CONNECT); + } + return 0; +} + + +/* Return values: + * 0 - No body, `restart`, message_complete + * 1 - CONNECT request, `restart`, message_complete, and pause + * 2 - chunk_size_start + * 3 - body_identity + * 4 - body_identity_eof + */ +int llhttp__after_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + int hasBody; + + hasBody = parser->flags & F_CHUNKED || parser->content_length > 0; + if (parser->upgrade && (parser->method == HTTP_CONNECT || + (parser->flags & F_SKIPBODY) || !hasBody)) { + /* Exit, the rest of the message is in a different protocol. */ + return 1; + } + + if (parser->flags & F_SKIPBODY) { + return 0; + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header */ + return 2; + } else { + if (!(parser->flags & F_CONTENT_LENGTH)) { + if (!llhttp_message_needs_eof(parser)) { + /* Assume content-length 0 - read the next */ + return 0; + } else { + /* Read body until EOF */ + return 4; + } + } else if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + return 0; + } else { + /* Content-Length header given and non-zero */ + return 3; + } + } +} + + +int llhttp__after_message_complete(llhttp_t* parser, const char* p, + const char* endp) { + int should_keep_alive; + + should_keep_alive = llhttp_should_keep_alive(parser); + parser->flags = 0; + parser->finish = HTTP_FINISH_SAFE; + + /* NOTE: this is ignored in loose parsing mode */ + return should_keep_alive; +} + + +int llhttp_message_needs_eof(const llhttp_t* parser) { + if (parser->type == HTTP_REQUEST) { + return 0; + } + + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + (parser->flags & F_SKIPBODY)) { /* response to a HEAD request */ + return 0; + } + + if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) { + return 0; + } + + return 1; +} + + +int llhttp_should_keep_alive(const llhttp_t* parser) { + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } + } else { + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { + return 0; + } + } + + return !llhttp_message_needs_eof(parser); +} diff --git a/deps/llhttp/src/llhttp.c b/deps/llhttp/src/llhttp.c new file mode 100644 index 00000000000000..cb12c8dfd0f182 --- /dev/null +++ b/deps/llhttp/src/llhttp.c @@ -0,0 +1,6044 @@ +#include +#include +#include + +#include "llhttp.h" + +typedef int (*llhttp__internal__span_cb)( + llhttp__internal_t*, const char*, const char*); + +static const unsigned char llparse_blob0[] = { + 'C', 'L' +}; +static const unsigned char llparse_blob1[] = { + 'o', 'n' +}; +static const unsigned char llparse_blob2[] = { + 'e', 'c', 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob3[] = { + 'l', 'o', 's', 'e' +}; +static const unsigned char llparse_blob4[] = { + 'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e' +}; +static const unsigned char llparse_blob5[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob6[] = { + 'h', 'u', 'n', 'k', 'e', 'd' +}; +static const unsigned char llparse_blob7[] = { + 'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h' +}; +static const unsigned char llparse_blob8[] = { + 'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c', + 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob9[] = { + 'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c', + 'o', 'd', 'i', 'n', 'g' +}; +static const unsigned char llparse_blob10[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob11[] = { + 0xd, 0xa +}; +static const unsigned char llparse_blob12[] = { + 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob13[] = { + 'C', 'E', '/' +}; +static const unsigned char llparse_blob14[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob15[] = { + 'E', 'C', 'K', 'O', 'U', 'T' +}; +static const unsigned char llparse_blob16[] = { + 'N', 'E', 'C', 'T' +}; +static const unsigned char llparse_blob17[] = { + 'E', 'L', 'E', 'T', 'E' +}; +static const unsigned char llparse_blob18[] = { + 'E', 'T' +}; +static const unsigned char llparse_blob19[] = { + 'E', 'A', 'D' +}; +static const unsigned char llparse_blob20[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob21[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob22[] = { + 'S', 'E', 'A', 'R', 'C', 'H' +}; +static const unsigned char llparse_blob23[] = { + 'R', 'G', 'E' +}; +static const unsigned char llparse_blob24[] = { + 'C', 'T', 'I', 'V', 'I', 'T', 'Y' +}; +static const unsigned char llparse_blob25[] = { + 'L', 'E', 'N', 'D', 'A', 'R' +}; +static const unsigned char llparse_blob26[] = { + 'V', 'E' +}; +static const unsigned char llparse_blob27[] = { + 'O', 'T', 'I', 'F', 'Y' +}; +static const unsigned char llparse_blob28[] = { + 'P', 'T', 'I', 'O', 'N', 'S' +}; +static const unsigned char llparse_blob29[] = { + 'T', 'C', 'H' +}; +static const unsigned char llparse_blob30[] = { + 'S', 'T' +}; +static const unsigned char llparse_blob31[] = { + 'O', 'P' +}; +static const unsigned char llparse_blob32[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob33[] = { + 'A', 'T', 'C', 'H' +}; +static const unsigned char llparse_blob34[] = { + 'G', 'E' +}; +static const unsigned char llparse_blob35[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob36[] = { + 'O', 'R', 'T' +}; +static const unsigned char llparse_blob37[] = { + 'A', 'R', 'C', 'H' +}; +static const unsigned char llparse_blob38[] = { + 'U', 'R', 'C', 'E' +}; +static const unsigned char llparse_blob39[] = { + 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob40[] = { + 'R', 'A', 'C', 'E' +}; +static const unsigned char llparse_blob41[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob42[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob43[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob44[] = { + 'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob45[] = { + 'H', 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob46[] = { + 'A', 'D' +}; +static const unsigned char llparse_blob47[] = { + 'T', 'P', '/' +}; + +enum llparse_match_status_e { + kMatchComplete, + kMatchPause, + kMatchMismatch +}; +typedef enum llparse_match_status_e llparse_match_status_t; + +struct llparse_match_s { + llparse_match_status_t status; + const unsigned char* current; +}; +typedef struct llparse_match_s llparse_match_t; + +static llparse_match_t llparse__match_sequence_id( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = *p; + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +static llparse_match_t llparse__match_sequence_to_lower_unsafe( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = ((*p) | 0x20); + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +enum llparse_state_e { + s_error, + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete, + s_n_llhttp__internal__n_pause_1, + s_n_llhttp__internal__n_invoke_is_equal_upgrade, + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2, + s_n_llhttp__internal__n_chunk_data_almost_done_skip, + s_n_llhttp__internal__n_chunk_data_almost_done, + s_n_llhttp__internal__n_consume_content_length, + s_n_llhttp__internal__n_span_start_llhttp__on_body, + s_n_llhttp__internal__n_invoke_is_equal_content_length, + s_n_llhttp__internal__n_chunk_size_almost_done, + s_n_llhttp__internal__n_chunk_parameters, + s_n_llhttp__internal__n_chunk_size_otherwise, + s_n_llhttp__internal__n_chunk_size, + s_n_llhttp__internal__n_invoke_update_content_length, + s_n_llhttp__internal__n_consume_content_length_1, + s_n_llhttp__internal__n_span_start_llhttp__on_body_1, + s_n_llhttp__internal__n_eof, + s_n_llhttp__internal__n_span_start_llhttp__on_body_2, + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete, + s_n_llhttp__internal__n_headers_almost_done, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value, + s_n_llhttp__internal__n_header_value_discard_lws, + s_n_llhttp__internal__n_header_value_discard_ws_almost_done, + s_n_llhttp__internal__n_header_value_lws, + s_n_llhttp__internal__n_header_value_almost_done, + s_n_llhttp__internal__n_header_value_otherwise, + s_n_llhttp__internal__n_header_value_connection_token, + s_n_llhttp__internal__n_header_value_connection_ws, + s_n_llhttp__internal__n_header_value_connection_1, + s_n_llhttp__internal__n_header_value_connection_2, + s_n_llhttp__internal__n_header_value_connection_3, + s_n_llhttp__internal__n_header_value_connection, + s_n_llhttp__internal__n_error_14, + s_n_llhttp__internal__n_header_value, + s_n_llhttp__internal__n_header_value_discard_rws, + s_n_llhttp__internal__n_error_15, + s_n_llhttp__internal__n_header_value_content_length_ws, + s_n_llhttp__internal__n_header_value_content_length, + s_n_llhttp__internal__n_header_value_te_chunked_1, + s_n_llhttp__internal__n_header_value_te_chunked, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1, + s_n_llhttp__internal__n_header_value_discard_ws, + s_n_llhttp__internal__n_header_field_general_otherwise, + s_n_llhttp__internal__n_header_field_general, + s_n_llhttp__internal__n_header_field_colon, + s_n_llhttp__internal__n_header_field_3, + s_n_llhttp__internal__n_header_field_4, + s_n_llhttp__internal__n_header_field_2, + s_n_llhttp__internal__n_header_field_1, + s_n_llhttp__internal__n_header_field_5, + s_n_llhttp__internal__n_header_field_6, + s_n_llhttp__internal__n_header_field_7, + s_n_llhttp__internal__n_header_field, + s_n_llhttp__internal__n_span_start_llhttp__on_header_field, + s_n_llhttp__internal__n_header_field_start, + s_n_llhttp__internal__n_url_skip_to_http09, + s_n_llhttp__internal__n_url_skip_lf_to_http09, + s_n_llhttp__internal__n_req_http_end_1, + s_n_llhttp__internal__n_req_http_end, + s_n_llhttp__internal__n_req_http_minor, + s_n_llhttp__internal__n_req_http_dot, + s_n_llhttp__internal__n_req_http_major, + s_n_llhttp__internal__n_req_http_start_1, + s_n_llhttp__internal__n_req_http_start_2, + s_n_llhttp__internal__n_req_http_start, + s_n_llhttp__internal__n_url_skip_to_http, + s_n_llhttp__internal__n_url_fragment, + s_n_llhttp__internal__n_span_end_stub_query_3, + s_n_llhttp__internal__n_url_query, + s_n_llhttp__internal__n_url_query_or_fragment, + s_n_llhttp__internal__n_url_path, + s_n_llhttp__internal__n_span_start_stub_path_2, + s_n_llhttp__internal__n_span_start_stub_path, + s_n_llhttp__internal__n_span_start_stub_path_1, + s_n_llhttp__internal__n_url_server_with_at, + s_n_llhttp__internal__n_url_server, + s_n_llhttp__internal__n_url_schema_delim_1, + s_n_llhttp__internal__n_url_schema_delim, + s_n_llhttp__internal__n_span_end_stub_schema, + s_n_llhttp__internal__n_url_schema, + s_n_llhttp__internal__n_url_start, + s_n_llhttp__internal__n_span_start_llhttp__on_url_1, + s_n_llhttp__internal__n_span_start_llhttp__on_url, + s_n_llhttp__internal__n_req_spaces_before_url, + s_n_llhttp__internal__n_req_first_space_before_url, + s_n_llhttp__internal__n_start_req_1, + s_n_llhttp__internal__n_start_req_2, + s_n_llhttp__internal__n_start_req_4, + s_n_llhttp__internal__n_start_req_6, + s_n_llhttp__internal__n_start_req_7, + s_n_llhttp__internal__n_start_req_5, + s_n_llhttp__internal__n_start_req_3, + s_n_llhttp__internal__n_start_req_8, + s_n_llhttp__internal__n_start_req_9, + s_n_llhttp__internal__n_start_req_10, + s_n_llhttp__internal__n_start_req_12, + s_n_llhttp__internal__n_start_req_13, + s_n_llhttp__internal__n_start_req_11, + s_n_llhttp__internal__n_start_req_15, + s_n_llhttp__internal__n_start_req_16, + s_n_llhttp__internal__n_start_req_18, + s_n_llhttp__internal__n_start_req_20, + s_n_llhttp__internal__n_start_req_21, + s_n_llhttp__internal__n_start_req_19, + s_n_llhttp__internal__n_start_req_17, + s_n_llhttp__internal__n_start_req_22, + s_n_llhttp__internal__n_start_req_14, + s_n_llhttp__internal__n_start_req_23, + s_n_llhttp__internal__n_start_req_24, + s_n_llhttp__internal__n_start_req_26, + s_n_llhttp__internal__n_start_req_27, + s_n_llhttp__internal__n_start_req_30, + s_n_llhttp__internal__n_start_req_31, + s_n_llhttp__internal__n_start_req_29, + s_n_llhttp__internal__n_start_req_28, + s_n_llhttp__internal__n_start_req_33, + s_n_llhttp__internal__n_start_req_32, + s_n_llhttp__internal__n_start_req_25, + s_n_llhttp__internal__n_start_req_36, + s_n_llhttp__internal__n_start_req_37, + s_n_llhttp__internal__n_start_req_35, + s_n_llhttp__internal__n_start_req_34, + s_n_llhttp__internal__n_start_req_39, + s_n_llhttp__internal__n_start_req_40, + s_n_llhttp__internal__n_start_req_41, + s_n_llhttp__internal__n_start_req_38, + s_n_llhttp__internal__n_start_req_42, + s_n_llhttp__internal__n_start_req_45, + s_n_llhttp__internal__n_start_req_47, + s_n_llhttp__internal__n_start_req_48, + s_n_llhttp__internal__n_start_req_46, + s_n_llhttp__internal__n_start_req_49, + s_n_llhttp__internal__n_start_req_44, + s_n_llhttp__internal__n_start_req_43, + s_n_llhttp__internal__n_start_req, + s_n_llhttp__internal__n_res_line_almost_done, + s_n_llhttp__internal__n_res_status, + s_n_llhttp__internal__n_span_start_llhttp__on_status, + s_n_llhttp__internal__n_res_status_start, + s_n_llhttp__internal__n_res_status_code_otherwise, + s_n_llhttp__internal__n_res_status_code, + s_n_llhttp__internal__n_res_http_end, + s_n_llhttp__internal__n_res_http_minor, + s_n_llhttp__internal__n_res_http_dot, + s_n_llhttp__internal__n_res_http_major, + s_n_llhttp__internal__n_start_res, + s_n_llhttp__internal__n_req_or_res_method_2, + s_n_llhttp__internal__n_req_or_res_method_3, + s_n_llhttp__internal__n_req_or_res_method_1, + s_n_llhttp__internal__n_req_or_res_method, + s_n_llhttp__internal__n_start_req_or_res, + s_n_llhttp__internal__n_invoke_load_type, + s_n_llhttp__internal__n_start, +}; +typedef enum llparse_state_e llparse_state_t; + +int llhttp__on_url( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_field( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_value( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_body( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_status( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_finish( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 2; + return 0; +} + +int llhttp__on_message_begin( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->type; +} + +int llhttp__internal__c_store_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->method = match; + return 0; +} + +int llhttp__internal__c_is_equal_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method == 5; +} + +int llhttp__internal__c_update_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_major = 0; + return 0; +} + +int llhttp__internal__c_update_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_minor = 9; + return 0; +} + +int llhttp__internal__c_test_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 128) == 128; +} + +int llhttp__on_chunk_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->upgrade == 1; +} + +int llhttp__after_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_test_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 40) == 40; +} + +int llhttp__before_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__after_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->content_length = 0; + return 0; +} + +int llhttp__internal__c_mul_add_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 16) { + return 1; + } + + state->content_length *= 16; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__on_chunk_header( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->content_length == 0; +} + +int llhttp__internal__c_or_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 128; + return 0; +} + +int llhttp__internal__c_update_finish_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 1; + return 0; +} + +int llhttp__internal__c_or_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 64; + return 0; +} + +int llhttp__internal__c_update_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->upgrade = 1; + return 0; +} + +int llhttp__internal__c_store_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->header_state = match; + return 0; +} + +int llhttp__internal__c_load_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->header_state; +} + +int llhttp__internal__c_or_flags_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 1; + return 0; +} + +int llhttp__internal__c_update_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 1; + return 0; +} + +int llhttp__internal__c_or_flags_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 2; + return 0; +} + +int llhttp__internal__c_or_flags_5( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 4; + return 0; +} + +int llhttp__internal__c_or_flags_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 8; + return 0; +} + +int llhttp__internal__c_update_header_state_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 6; + return 0; +} + +int llhttp__internal__c_update_header_state_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 0; + return 0; +} + +int llhttp__internal__c_update_header_state_5( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 5; + return 0; +} + +int llhttp__internal__c_update_header_state_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 7; + return 0; +} + +int llhttp__internal__c_test_flags_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 32) == 32; +} + +int llhttp__internal__c_mul_add_content_length_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 10) { + return 1; + } + + state->content_length *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__internal__c_or_flags_15( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 32; + return 0; +} + +int llhttp__internal__c_update_header_state_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 8; + return 0; +} + +int llhttp__internal__c_or_flags_16( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 16; + return 0; +} + +int llhttp__internal__c_store_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_major = match; + return 0; +} + +int llhttp__internal__c_store_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_minor = match; + return 0; +} + +int llhttp__internal__c_is_equal_method_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method == 33; +} + +int llhttp__internal__c_update_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->status_code = 0; + return 0; +} + +int llhttp__internal__c_mul_add_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->status_code > 0xffff / 10) { + return 1; + } + + state->status_code *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->status_code > 0xffff - match) { + return 1; + } + } else { + if (state->status_code < 0 - match) { + return 1; + } + } + state->status_code += match; + + /* Enforce maximum */ + if (state->status_code > 999) { + return 1; + } + return 0; +} + +int llhttp__internal__c_update_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 1; + return 0; +} + +int llhttp__internal__c_update_type_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 2; + return 0; +} + +int llhttp__internal_init(llhttp__internal_t* state) { + memset(state, 0, sizeof(*state)); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start; + return 0; +} + +static llparse_state_t llhttp__internal__run( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + int match; + switch ((llparse_state_t) (intptr_t) state->_current) { + case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: { + switch (llhttp__after_message_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_start; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_pause_1: + s_n_llhttp__internal__n_pause_1: { + state->error = 0x15; + state->reason = "Pause on CONNECT/Upgrade"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_upgrade: + s_n_llhttp__internal__n_invoke_is_equal_upgrade: { + switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + default: + goto s_n_llhttp__internal__n_pause_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_upgrade; + case 20: + goto s_n_llhttp__internal__n_pause_5; + default: + goto s_n_llhttp__internal__n_error_8; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done_skip: + s_n_llhttp__internal__n_chunk_data_almost_done_skip: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done_skip; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done: + s_n_llhttp__internal__n_chunk_data_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done; + } + p++; + goto s_n_llhttp__internal__n_chunk_data_almost_done_skip; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length: + s_n_llhttp__internal__n_consume_content_length: { + size_t avail; + size_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body: + s_n_llhttp__internal__n_span_start_llhttp__on_body: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_content_length: + s_n_llhttp__internal__n_invoke_is_equal_content_length: { + switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body; + default: + goto s_n_llhttp__internal__n_invoke_or_flags; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_almost_done: + s_n_llhttp__internal__n_chunk_size_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_almost_done; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_parameters: + s_n_llhttp__internal__n_chunk_parameters: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_parameters; + } + switch (*p) { + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + default: { + p++; + goto s_n_llhttp__internal__n_chunk_parameters; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_otherwise: + s_n_llhttp__internal__n_chunk_size_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_otherwise; + } + switch (*p) { + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_chunk_parameters; + } + case ';': { + p++; + goto s_n_llhttp__internal__n_chunk_parameters; + } + default: { + goto s_n_llhttp__internal__n_error_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size: + s_n_llhttp__internal__n_chunk_size: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'A': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'B': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'C': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'D': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'E': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'F': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'a': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'b': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'c': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'd': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'e': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'f': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + default: { + goto s_n_llhttp__internal__n_chunk_size_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_content_length: + s_n_llhttp__internal__n_invoke_update_content_length: { + switch (llhttp__internal__c_update_content_length(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_chunk_size; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length_1: + s_n_llhttp__internal__n_consume_content_length_1: { + size_t avail; + size_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_1: + s_n_llhttp__internal__n_span_start_llhttp__on_body_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_eof: + s_n_llhttp__internal__n_eof: { + if (p == endp) { + return s_n_llhttp__internal__n_eof; + } + p++; + goto s_n_llhttp__internal__n_eof; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_2: + s_n_llhttp__internal__n_span_start_llhttp__on_body_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_invoke_update_finish_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: { + switch (llhttp__after_headers_complete(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_content_length; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + case 4: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_headers_almost_done: + s_n_llhttp__internal__n_headers_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_headers_almost_done; + } + p++; + goto s_n_llhttp__internal__n_invoke_test_flags; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_lws: + s_n_llhttp__internal__n_header_value_discard_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_lws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws_almost_done: + s_n_llhttp__internal__n_header_value_discard_ws_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + p++; + goto s_n_llhttp__internal__n_header_value_discard_lws; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_lws: + s_n_llhttp__internal__n_header_value_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_lws; + } + switch (*p) { + case 9: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + case ' ': { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_almost_done: + s_n_llhttp__internal__n_header_value_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_lws; + } + default: { + goto s_n_llhttp__internal__n_error_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_otherwise: + s_n_llhttp__internal__n_header_value_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_otherwise; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2; + } + default: { + goto s_n_llhttp__internal__n_error_12; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_token: + s_n_llhttp__internal__n_header_value_connection_token: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_token; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value_connection_token; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_ws: + s_n_llhttp__internal__n_header_value_connection_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + case ',': { + p++; + goto s_n_llhttp__internal__n_invoke_load_header_state_3; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_1: + s_n_llhttp__internal__n_header_value_connection_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_1; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob3, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_2: + s_n_llhttp__internal__n_header_value_connection_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_2; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob4, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_5; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_3: + s_n_llhttp__internal__n_header_value_connection_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_3; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_6; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection: + s_n_llhttp__internal__n_header_value_connection: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection; + } + switch (((*p) | 0x20)) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_1; + } + case 'k': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_2; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_3; + } + default: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_14: + s_n_llhttp__internal__n_error_14: { + state->error = 0xb; + state->reason = "Content-Length overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value: + s_n_llhttp__internal__n_header_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_rws: + s_n_llhttp__internal__n_header_value_discard_rws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_rws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_15: + s_n_llhttp__internal__n_error_15: { + state->error = 0xb; + state->reason = "Invalid character in Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length_ws: + s_n_llhttp__internal__n_header_value_content_length_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_or_flags_15; + } + case 13: { + goto s_n_llhttp__internal__n_invoke_or_flags_15; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length: + s_n_llhttp__internal__n_header_value_content_length: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + default: { + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked_1: + s_n_llhttp__internal__n_header_value_te_chunked_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked_1; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob6, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_8; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_te_chunked_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked: + s_n_llhttp__internal__n_header_value_te_chunked: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked; + } + switch (((*p) | 0x20)) { + case 10: { + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + case ' ': { + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_value_te_chunked_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_invoke_load_header_state_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws: + s_n_llhttp__internal__n_header_value_discard_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_lws; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general_otherwise: + s_n_llhttp__internal__n_header_field_general_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general_otherwise; + } + switch (*p) { + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1; + } + default: { + goto s_n_llhttp__internal__n_error_16; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general: + s_n_llhttp__internal__n_header_field_general: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_field_general; + } + default: { + goto s_n_llhttp__internal__n_header_field_general_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_colon: + s_n_llhttp__internal__n_header_field_colon: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_colon; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_field_colon; + } + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_9; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_3: + s_n_llhttp__internal__n_header_field_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_3; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob2, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_4: + s_n_llhttp__internal__n_header_field_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_4; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob7, 10); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_2: + s_n_llhttp__internal__n_header_field_2: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_2; + } + switch (((*p) | 0x20)) { + case 'n': { + p++; + goto s_n_llhttp__internal__n_header_field_3; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_4; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_1: + s_n_llhttp__internal__n_header_field_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_1; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob1, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_header_field_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_5: + s_n_llhttp__internal__n_header_field_5: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_5; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob8, 15); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_5; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_6: + s_n_llhttp__internal__n_header_field_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_6; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob9, 16); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_7: + s_n_llhttp__internal__n_header_field_7: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_7; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob10, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_7; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field: + s_n_llhttp__internal__n_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field; + } + switch (((*p) | 0x20)) { + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_field_1; + } + case 'p': { + p++; + goto s_n_llhttp__internal__n_header_field_5; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_6; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_field_7; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_field: + s_n_llhttp__internal__n_span_start_llhttp__on_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_field; + goto s_n_llhttp__internal__n_header_field; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_start: + s_n_llhttp__internal__n_header_field_start: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_start; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_headers_almost_done; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_headers_almost_done; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http09: + s_n_llhttp__internal__n_url_skip_to_http09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http09; + } + p++; + goto s_n_llhttp__internal__n_invoke_update_http_major; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_lf_to_http09: + s_n_llhttp__internal__n_url_skip_lf_to_http09: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_lf_to_http09; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob11, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_http_major; + } + case kMatchPause: { + return s_n_llhttp__internal__n_url_skip_lf_to_http09; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_17; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_end_1: + s_n_llhttp__internal__n_req_http_end_1: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_end_1; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_field_start; + } + default: { + goto s_n_llhttp__internal__n_error_18; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_end: + s_n_llhttp__internal__n_req_http_end: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_end; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_field_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_req_http_end_1; + } + default: { + goto s_n_llhttp__internal__n_error_18; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_minor: + s_n_llhttp__internal__n_req_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + default: { + goto s_n_llhttp__internal__n_error_19; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_dot: + s_n_llhttp__internal__n_req_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_req_http_minor; + } + default: { + goto s_n_llhttp__internal__n_error_20; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_major: + s_n_llhttp__internal__n_req_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + default: { + goto s_n_llhttp__internal__n_error_21; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_1: + s_n_llhttp__internal__n_req_http_start_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_1; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob12, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_req_http_major; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_23; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_2: + s_n_llhttp__internal__n_req_http_start_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_is_equal_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_23; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start: + s_n_llhttp__internal__n_req_http_start: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_http_start; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_http_start_1; + } + case 'I': { + p++; + goto s_n_llhttp__internal__n_req_http_start_2; + } + default: { + goto s_n_llhttp__internal__n_error_23; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http: + s_n_llhttp__internal__n_url_skip_to_http: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http; + } + p++; + goto s_n_llhttp__internal__n_req_http_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_fragment: + s_n_llhttp__internal__n_url_fragment: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_fragment; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8; + } + default: { + goto s_n_llhttp__internal__n_error_24; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_query_3: + s_n_llhttp__internal__n_span_end_stub_query_3: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_query_3; + } + p++; + goto s_n_llhttp__internal__n_url_fragment; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query: + s_n_llhttp__internal__n_url_query: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_query; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11; + } + case 5: { + goto s_n_llhttp__internal__n_span_end_stub_query_3; + } + default: { + goto s_n_llhttp__internal__n_error_25; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query_or_fragment: + s_n_llhttp__internal__n_url_query_or_fragment: { + if (p == endp) { + return s_n_llhttp__internal__n_url_query_or_fragment; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4; + } + case ' ': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5; + } + case '#': { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + case '?': { + p++; + goto s_n_llhttp__internal__n_url_query; + } + default: { + goto s_n_llhttp__internal__n_error_26; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_path: + s_n_llhttp__internal__n_url_path: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_path; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_url_path; + } + default: { + goto s_n_llhttp__internal__n_url_query_or_fragment; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_2: + s_n_llhttp__internal__n_span_start_stub_path_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_2; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path: + s_n_llhttp__internal__n_span_start_stub_path: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_1: + s_n_llhttp__internal__n_span_start_stub_path_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_1; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server_with_at: + s_n_llhttp__internal__n_url_server_with_at: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6, + 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4, + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server_with_at; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14; + } + case 4: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 5: { + goto s_n_llhttp__internal__n_span_start_stub_path_1; + } + case 6: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_error_27; + } + default: { + goto s_n_llhttp__internal__n_error_28; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server: + s_n_llhttp__internal__n_url_server: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6, + 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4, + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2; + } + case 4: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 5: { + goto s_n_llhttp__internal__n_span_start_stub_path; + } + case 6: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_url_server_with_at; + } + default: { + goto s_n_llhttp__internal__n_error_29; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim_1: + s_n_llhttp__internal__n_url_schema_delim_1: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim_1; + } + switch (*p) { + case '/': { + p++; + goto s_n_llhttp__internal__n_url_server; + } + default: { + goto s_n_llhttp__internal__n_error_31; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim: + s_n_llhttp__internal__n_url_schema_delim: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case '/': { + p++; + goto s_n_llhttp__internal__n_url_schema_delim_1; + } + default: { + goto s_n_llhttp__internal__n_error_31; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_schema: + s_n_llhttp__internal__n_span_end_stub_schema: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_schema; + } + p++; + goto s_n_llhttp__internal__n_url_schema_delim; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema: + s_n_llhttp__internal__n_url_schema: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_schema; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_stub_schema; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_32; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_start: + s_n_llhttp__internal__n_url_start: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_start; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case 2: { + goto s_n_llhttp__internal__n_span_start_stub_path_2; + } + case 3: { + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_33; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url_1: + s_n_llhttp__internal__n_span_start_llhttp__on_url_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url: + s_n_llhttp__internal__n_span_start_llhttp__on_url: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_server; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_spaces_before_url: + s_n_llhttp__internal__n_req_spaces_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_spaces_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_invoke_is_equal_method; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_first_space_before_url: + s_n_llhttp__internal__n_req_first_space_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_first_space_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_error_34; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_1: + s_n_llhttp__internal__n_start_req_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_1; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob0, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 19; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_2: + s_n_llhttp__internal__n_start_req_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 16; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_4: + s_n_llhttp__internal__n_start_req_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_4; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 22; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_6: + s_n_llhttp__internal__n_start_req_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_6; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_7: + s_n_llhttp__internal__n_start_req_7: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_7; + } + switch (*p) { + case 'Y': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_5: + s_n_llhttp__internal__n_start_req_5: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_5; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_start_req_6; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_7; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_3: + s_n_llhttp__internal__n_start_req_3: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_3; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_start_req_4; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_5; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_8: + s_n_llhttp__internal__n_start_req_8: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_8; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_8; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_9: + s_n_llhttp__internal__n_start_req_9: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_9; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_9; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_10: + s_n_llhttp__internal__n_start_req_10: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_10; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_10; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_12: + s_n_llhttp__internal__n_start_req_12: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_12; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 31; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_12; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_13: + s_n_llhttp__internal__n_start_req_13: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_13; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_13; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_11: + s_n_llhttp__internal__n_start_req_11: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_11; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_start_req_12; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_13; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_15: + s_n_llhttp__internal__n_start_req_15: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_15; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 24; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_15; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_16: + s_n_llhttp__internal__n_start_req_16: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_16; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 23; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_16; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_18: + s_n_llhttp__internal__n_start_req_18: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_18; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 21; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_18; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_20: + s_n_llhttp__internal__n_start_req_20: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_20; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 30; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_20; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_21: + s_n_llhttp__internal__n_start_req_21: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_21; + } + switch (*p) { + case 'L': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_19: + s_n_llhttp__internal__n_start_req_19: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_19; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_20; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_21; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_17: + s_n_llhttp__internal__n_start_req_17: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_17; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_18; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_start_req_19; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_22: + s_n_llhttp__internal__n_start_req_22: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_22; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_22; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_14: + s_n_llhttp__internal__n_start_req_14: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_14; + } + switch (*p) { + case '-': { + p++; + goto s_n_llhttp__internal__n_start_req_15; + } + case 'E': { + p++; + goto s_n_llhttp__internal__n_start_req_16; + } + case 'K': { + p++; + goto s_n_llhttp__internal__n_start_req_17; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_22; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_23: + s_n_llhttp__internal__n_start_req_23: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_23; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 25; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_23; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_24: + s_n_llhttp__internal__n_start_req_24: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_24; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_24; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_26: + s_n_llhttp__internal__n_start_req_26: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_26; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 28; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_26; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_27: + s_n_llhttp__internal__n_start_req_27: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_27; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_27; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_30: + s_n_llhttp__internal__n_start_req_30: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_30; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_30; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_31: + s_n_llhttp__internal__n_start_req_31: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_31; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_31; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_29: + s_n_llhttp__internal__n_start_req_29: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_29; + } + switch (*p) { + case 'F': { + p++; + goto s_n_llhttp__internal__n_start_req_30; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_31; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_28: + s_n_llhttp__internal__n_start_req_28: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_28; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_start_req_29; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_28; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_33: + s_n_llhttp__internal__n_start_req_33: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_33; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 29; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_33; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_32: + s_n_llhttp__internal__n_start_req_32: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_32; + } + switch (*p) { + case 'R': { + p++; + goto s_n_llhttp__internal__n_start_req_33; + } + case 'T': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_25: + s_n_llhttp__internal__n_start_req_25: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_25; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_26; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_27; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_start_req_28; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_start_req_32; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_36: + s_n_llhttp__internal__n_start_req_36: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_36; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 17; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_36; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_37: + s_n_llhttp__internal__n_start_req_37: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_37; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 20; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_37; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_35: + s_n_llhttp__internal__n_start_req_35: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_35; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_start_req_36; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_37; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_34: + s_n_llhttp__internal__n_start_req_34: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_34; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_start_req_35; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_39: + s_n_llhttp__internal__n_start_req_39: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_39; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_39; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_40: + s_n_llhttp__internal__n_start_req_40: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_40; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 33; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_40; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_41: + s_n_llhttp__internal__n_start_req_41: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_41; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 26; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_41; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_38: + s_n_llhttp__internal__n_start_req_38: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_38; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_start_req_39; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_40; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_start_req_41; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_42: + s_n_llhttp__internal__n_start_req_42: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_42; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_42; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_45: + s_n_llhttp__internal__n_start_req_45: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_45; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 18; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_45; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_47: + s_n_llhttp__internal__n_start_req_47: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_47; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 32; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_47; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_48: + s_n_llhttp__internal__n_start_req_48: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_48; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_48; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_46: + s_n_llhttp__internal__n_start_req_46: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_46; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_start_req_47; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_48; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_49: + s_n_llhttp__internal__n_start_req_49: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_49; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 8); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 27; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_49; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_44: + s_n_llhttp__internal__n_start_req_44: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_44; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_start_req_45; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_start_req_46; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_start_req_49; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_43: + s_n_llhttp__internal__n_start_req_43: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_43; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_start_req_44; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req: + s_n_llhttp__internal__n_start_req: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_1; + } + case 'B': { + p++; + goto s_n_llhttp__internal__n_start_req_2; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_start_req_3; + } + case 'D': { + p++; + goto s_n_llhttp__internal__n_start_req_8; + } + case 'G': { + p++; + goto s_n_llhttp__internal__n_start_req_9; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_start_req_10; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_start_req_11; + } + case 'M': { + p++; + goto s_n_llhttp__internal__n_start_req_14; + } + case 'N': { + p++; + goto s_n_llhttp__internal__n_start_req_23; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_24; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_25; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_start_req_34; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_start_req_38; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_start_req_42; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_start_req_43; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_line_almost_done: + s_n_llhttp__internal__n_res_line_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_res_line_almost_done; + } + p++; + goto s_n_llhttp__internal__n_header_field_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status: + s_n_llhttp__internal__n_res_status: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1; + } + default: { + p++; + goto s_n_llhttp__internal__n_res_status; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_status: + s_n_llhttp__internal__n_span_start_llhttp__on_status: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_status; + goto s_n_llhttp__internal__n_res_status; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_start: + s_n_llhttp__internal__n_res_status_start: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_field_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_otherwise: + s_n_llhttp__internal__n_res_status_code_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_otherwise; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_res_status_start; + } + case 13: { + goto s_n_llhttp__internal__n_res_status_start; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_res_status_start; + } + default: { + goto s_n_llhttp__internal__n_error_36; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code: + s_n_llhttp__internal__n_res_status_code: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + default: { + goto s_n_llhttp__internal__n_res_status_code_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_end: + s_n_llhttp__internal__n_res_http_end: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_end; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_update_status_code; + } + default: { + goto s_n_llhttp__internal__n_error_37; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_minor: + s_n_llhttp__internal__n_res_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + default: { + goto s_n_llhttp__internal__n_error_38; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_dot: + s_n_llhttp__internal__n_res_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_res_http_minor; + } + default: { + goto s_n_llhttp__internal__n_error_39; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_major: + s_n_llhttp__internal__n_res_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + default: { + goto s_n_llhttp__internal__n_error_40; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_res: + s_n_llhttp__internal__n_start_res: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_res; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_res_http_major; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_res; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_43; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_2: + s_n_llhttp__internal__n_req_or_res_method_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_3: + s_n_llhttp__internal__n_req_or_res_method_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_type_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_1: + s_n_llhttp__internal__n_req_or_res_method_1: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_1; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_2; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_3; + } + default: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method: + s_n_llhttp__internal__n_req_or_res_method: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_or_res: + s_n_llhttp__internal__n_start_req_or_res: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_or_res; + } + switch (*p) { + case 'H': { + goto s_n_llhttp__internal__n_req_or_res_method; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_type_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_type: + s_n_llhttp__internal__n_invoke_load_type: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_start_req; + case 2: + goto s_n_llhttp__internal__n_start_res; + default: + goto s_n_llhttp__internal__n_start_req_or_res; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start: + s_n_llhttp__internal__n_start: { + if (p == endp) { + return s_n_llhttp__internal__n_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_start; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_finish; + } + } + /* UNREACHABLE */; + abort(); + } + default: + /* UNREACHABLE */ + abort(); + } + s_n_llhttp__internal__n_error_30: { + state->error = 0x7; + state->reason = "Invalid characters in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_5: { + state->error = 0x14; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_8: { + state->error = 0x11; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_7: { + state->error = 0x14; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_10: { + state->error = 0x13; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + case 20: + goto s_n_llhttp__internal__n_pause_7; + default: + goto s_n_llhttp__internal__n_error_10; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_9: { + state->error = 0x4; + state->reason = "Content-Length can't be present with chunked encoding"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_2: { + state->error = 0x14; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_3: { + state->error = 0x11; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_pause_1; + case 20: + goto s_n_llhttp__internal__n_pause_2; + default: + goto s_n_llhttp__internal__n_error_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_4: { + state->error = 0xc; + state->reason = "Chunk size overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length: { + switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_4; + default: + goto s_n_llhttp__internal__n_chunk_size; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_3: { + state->error = 0x14; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_6: { + state->error = 0x13; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_update_content_length; + case 20: + goto s_n_llhttp__internal__n_pause_3; + default: + goto s_n_llhttp__internal__n_error_6; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_chunk_data_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags: { + switch (llhttp__internal__c_or_flags(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_4: { + state->error = 0x14; + state->reason = "on_chunk_header pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_5: { + state->error = 0x12; + state->reason = "`on_chunk_header` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: { + switch (llhttp__on_chunk_header(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_content_length; + case 20: + goto s_n_llhttp__internal__n_pause_4; + default: + goto s_n_llhttp__internal__n_error_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_7: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_1: { + switch (llhttp__internal__c_update_finish_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_eof; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause: { + state->error = 0x14; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_2: { + state->error = 0x11; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + case 20: + goto s_n_llhttp__internal__n_pause; + default: + goto s_n_llhttp__internal__n_error_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_1: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_2: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_upgrade: { + switch (llhttp__internal__c_update_upgrade(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_or_flags_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_6: { + state->error = 0x14; + state->reason = "Paused by on_headers_complete"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_1: { + state->error = 0x10; + state->reason = "User callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: { + switch (llhttp__on_headers_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + case 1: + goto s_n_llhttp__internal__n_invoke_or_flags_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_upgrade; + case 20: + goto s_n_llhttp__internal__n_pause_6; + default: + goto s_n_llhttp__internal__n_error_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: { + switch (llhttp__before_headers_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_1: { + switch (llhttp__internal__c_test_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_error_9; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags: { + switch (llhttp__internal__c_test_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1; + default: + goto s_n_llhttp__internal__n_invoke_test_flags_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; + return s_error; + } + goto s_n_llhttp__internal__n_header_field_start; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_3: { + switch (llhttp__internal__c_or_flags_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_4: { + switch (llhttp__internal__c_or_flags_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_5: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_6: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_3; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_4; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_5; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_6; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_1: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_7: { + switch (llhttp__internal__c_or_flags_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_8: { + switch (llhttp__internal__c_or_flags_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_9: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_10: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_2: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_7; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_8; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_9; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_10; + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_11: { + state->error = 0x3; + state->reason = "Missing expected LF after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_12: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_3: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_11: { + switch (llhttp__internal__c_or_flags_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_12: { + switch (llhttp__internal__c_or_flags_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_13: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_14: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_3: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_11; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_12; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_13; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_14; + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_4: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_token; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_2: { + switch (llhttp__internal__c_update_header_state_2(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_5: { + switch (llhttp__internal__c_update_header_state_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_6: { + switch (llhttp__internal__c_update_header_state_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_14; + return s_error; + } + goto s_n_llhttp__internal__n_error_14; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length_1: { + switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3; + default: + goto s_n_llhttp__internal__n_header_value_content_length; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_7: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_15: { + switch (llhttp__internal__c_or_flags_15(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_15; + return s_error; + } + goto s_n_llhttp__internal__n_error_15; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_13: { + state->error = 0x4; + state->reason = "Duplicate Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_2: { + switch (llhttp__internal__c_test_flags_2(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_header_value_content_length; + default: + goto s_n_llhttp__internal__n_error_13; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_8: { + switch (llhttp__internal__c_update_header_state_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_16: { + switch (llhttp__internal__c_or_flags_16(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_1: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_connection; + case 2: + goto s_n_llhttp__internal__n_invoke_test_flags_2; + case 3: + goto s_n_llhttp__internal__n_header_value_te_chunked; + case 4: + goto s_n_llhttp__internal__n_invoke_or_flags_16; + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_discard_ws; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_discard_ws; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_16: { + state->error = 0xa; + state->reason = "Invalid header token"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_9: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_header_state: { + switch (llhttp__internal__c_store_header_state(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_header_field_colon; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_10: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_minor: { + switch (llhttp__internal__c_update_http_minor(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_major: { + switch (llhttp__internal__c_update_http_major(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_http_minor; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_17: { + state->error = 0x7; + state->reason = "Expected CRLF"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_18: { + state->error = 0x9; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_http_end; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_19: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_20: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_21: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_23: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_22: { + state->error = 0x8; + state->reason = "Expected SOURCE method for ICE/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_is_equal_method_1: { + switch (llhttp__internal__c_is_equal_method_1(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_error_22; + default: + goto s_n_llhttp__internal__n_req_http_major; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_24: { + state->error = 0x7; + state->reason = "Invalid char in url fragment start"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_10: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_11: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_25: { + state->error = 0x7; + state->reason = "Invalid char in url query"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_26: { + state->error = 0x7; + state->reason = "Invalid char in url path"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_12: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_13: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_14: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_27: { + state->error = 0x7; + state->reason = "Double @ in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_28: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_29: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_31: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_32: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_33: { + state->error = 0x7; + state->reason = "Unexpected start char in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_is_equal_method: { + switch (llhttp__internal__c_is_equal_method(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_34: { + state->error = 0x6; + state->reason = "Expected space after method"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method_1: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_first_space_before_url; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_42: { + state->error = 0x6; + state->reason = "Invalid method encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_35: { + state->error = 0xd; + state->reason = "Response overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_35; + default: + goto s_n_llhttp__internal__n_res_status_code; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_field_start; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_36: { + state->error = 0xd; + state->reason = "Invalid response status"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_status_code: { + switch (llhttp__internal__c_update_status_code(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_res_status_code; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_37: { + state->error = 0x9; + state->reason = "Expected space after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor_1: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_res_http_end; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_38: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_39: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major_1: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_res_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_40: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_43: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_req_first_space_before_url; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_update_type; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_41: { + state->error = 0x8; + state->reason = "Invalid word encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type_1: { + switch (llhttp__internal__c_update_type_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_res_http_major; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type_2: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_start_req; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_8: { + state->error = 0x14; + state->reason = "on_message_begin pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error: { + state->error = 0xf; + state->reason = "`on_message_begin` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: { + switch (llhttp__on_message_begin(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_type; + case 20: + goto s_n_llhttp__internal__n_pause_8; + default: + goto s_n_llhttp__internal__n_error; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish: { + switch (llhttp__internal__c_update_finish(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin; + } + /* UNREACHABLE */; + abort(); + } +} + +int llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) { + llparse_state_t next; + + /* check lingering errors */ + if (state->error != 0) { + return state->error; + } + + /* restart spans */ + if (state->_span_pos0 != NULL) { + state->_span_pos0 = (void*) p; + } + + next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp); + if (next == s_error) { + return state->error; + } + state->_current = (void*) (intptr_t) next; + + /* execute spans */ + if (state->_span_pos0 != NULL) { + int error; + + error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp); + if (error != 0) { + state->error = error; + state->error_pos = endp; + } + } + + return 0; +} \ No newline at end of file diff --git a/deps/openssl/openssl.gyp b/deps/openssl/openssl.gyp index 6b0770ebbc1b0e..4a6b55686679d4 100644 --- a/deps/openssl/openssl.gyp +++ b/deps/openssl/openssl.gyp @@ -1,7 +1,4 @@ { - 'variables': { - 'openssl_no_asm%': 0, - }, 'targets': [ { 'target_name': 'openssl', diff --git a/deps/v8/gypfiles/toolchain.gypi b/deps/v8/gypfiles/toolchain.gypi index ea8f1c2f00da56..4860c5b7724e20 100644 --- a/deps/v8/gypfiles/toolchain.gypi +++ b/deps/v8/gypfiles/toolchain.gypi @@ -1134,121 +1134,7 @@ }], ], # conditions 'configurations': { - # Abstract configuration for v8_optimized_debug == 0. - 'DebugBase0': { - 'abstract': 1, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '0', - 'conditions': [ - ['component=="shared_library" or force_dynamic_crt==1', { - 'RuntimeLibrary': '3', # /MDd - }, { - 'RuntimeLibrary': '1', # /MTd - }], - ], - }, - 'VCLinkerTool': { - 'LinkIncremental': '2', - }, - }, - 'variables': { - 'v8_enable_slow_dchecks%': 1, - }, - 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix"', { - 'cflags!': [ - '-O3', - '-O2', - '-O1', - '-Os', - ], - 'cflags': [ - '-fdata-sections', - '-ffunction-sections', - ], - }], - ['OS=="mac"', { - 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '0', # -O0 - }, - }], - ['v8_enable_slow_dchecks==1', { - 'defines': [ - 'ENABLE_SLOW_DCHECKS', - ], - }], - ], - }, # DebugBase0 - # Abstract configuration for v8_optimized_debug == 1. - 'DebugBase1': { - 'abstract': 1, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '2', - 'InlineFunctionExpansion': '2', - 'EnableIntrinsicFunctions': 'true', - 'FavorSizeOrSpeed': '0', - 'StringPooling': 'true', - 'BasicRuntimeChecks': '0', - 'conditions': [ - ['component=="shared_library" or force_dynamic_crt==1', { - 'RuntimeLibrary': '3', #/MDd - }, { - 'RuntimeLibrary': '1', #/MTd - }], - ], - }, - 'VCLinkerTool': { - 'LinkIncremental': '1', - 'OptimizeReferences': '2', - 'EnableCOMDATFolding': '2', - }, - }, - 'variables': { - 'v8_enable_slow_dchecks%': 0, - }, - 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix"', { - 'cflags!': [ - '-O0', - '-O1', - '-Os', - ], - 'cflags': [ - '-fdata-sections', - '-ffunction-sections', - ], - 'conditions': [ - # Don't use -O3 with sanitizers. - ['asan==0 and msan==0 and lsan==0 \ - and tsan==0 and ubsan==0 and ubsan_vptr==0', { - 'cflags': ['-O3'], - 'cflags!': ['-O2'], - }, { - 'cflags': ['-O2'], - 'cflags!': ['-O3'], - }], - ], - }], - ['OS=="mac"', { - 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '3', # -O3 - 'GCC_STRICT_ALIASING': 'YES', - }, - }], - ['v8_enable_slow_dchecks==1', { - 'defines': [ - 'ENABLE_SLOW_DCHECKS', - ], - }], - ], - }, # DebugBase1 - # Common settings for the Debug configuration. - 'DebugBaseCommon': { - 'abstract': 1, + 'Debug': { 'defines': [ 'ENABLE_DISASSEMBLER', 'V8_ENABLE_CHECKS', @@ -1311,27 +1197,126 @@ }], ], }], - ], - }, # DebugBaseCommon - 'Debug': { - 'inherit_from': ['DebugBaseCommon'], - 'conditions': [ ['v8_optimized_debug==0', { - 'inherit_from': ['DebugBase0'], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '0', + 'conditions': [ + ['component=="shared_library" or force_dynamic_crt==1', { + 'RuntimeLibrary': '3', # /MDd + }, { + 'RuntimeLibrary': '1', # /MTd + }], + ], + }, + 'VCLinkerTool': { + 'LinkIncremental': '2', + }, + }, + 'variables': { + 'v8_enable_slow_dchecks%': 1, + }, + 'conditions': [ + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ + OS=="qnx" or OS=="aix"', { + 'cflags!': [ + '-O3', + '-O2', + '-O1', + '-Os', + ], + 'cflags': [ + '-fdata-sections', + '-ffunction-sections', + ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '0', # -O0 + }, + }], + ['v8_enable_slow_dchecks==1', { + 'defines': [ + 'ENABLE_SLOW_DCHECKS', + ], + }], + ], }, { - 'inherit_from': ['DebugBase1'], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '2', + 'InlineFunctionExpansion': '2', + 'EnableIntrinsicFunctions': 'true', + 'FavorSizeOrSpeed': '0', + 'StringPooling': 'true', + 'BasicRuntimeChecks': '0', + 'conditions': [ + ['component=="shared_library" or force_dynamic_crt==1', { + 'RuntimeLibrary': '3', #/MDd + }, { + 'RuntimeLibrary': '1', #/MTd + }], + ], + }, + 'VCLinkerTool': { + 'LinkIncremental': '1', + 'OptimizeReferences': '2', + 'EnableCOMDATFolding': '2', + }, + }, + 'variables': { + 'v8_enable_slow_dchecks%': 0, + }, + 'conditions': [ + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ + OS=="qnx" or OS=="aix"', { + 'cflags!': [ + '-O0', + '-O1', + '-Os', + ], + 'cflags': [ + '-fdata-sections', + '-ffunction-sections', + ], + 'conditions': [ + # Don't use -O3 with sanitizers. + ['asan==0 and msan==0 and lsan==0 \ + and tsan==0 and ubsan==0 and ubsan_vptr==0', { + 'cflags': ['-O3'], + 'cflags!': ['-O2'], + }, { + 'cflags': ['-O2'], + 'cflags!': ['-O3'], + }], + ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '3', # -O3 + 'GCC_STRICT_ALIASING': 'YES', + }, + }], + ['v8_enable_slow_dchecks==1', { + 'defines': [ + 'ENABLE_SLOW_DCHECKS', + ], + }], + ], }], # Temporary refs: https://github.com/nodejs/node/pull/23801 ['v8_enable_handle_zapping==1', { 'defines': ['ENABLE_HANDLE_ZAPPING',], }], ], - }, # Debug - 'ReleaseBase': { - 'abstract': 1, + + }, # DebugBaseCommon + 'Release': { 'variables': { 'v8_enable_slow_dchecks%': 0, }, + # Temporary refs: https://github.com/nodejs/node/pull/23801 + 'defines!': ['ENABLE_HANDLE_ZAPPING',], 'conditions': [ ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \ or OS=="aix"', { @@ -1407,29 +1392,6 @@ }], ], # conditions }, # Release - 'Release': { - 'inherit_from': ['ReleaseBase'], - # Temporary refs: https://github.com/nodejs/node/pull/23801 - 'defines!': ['ENABLE_HANDLE_ZAPPING',], - }, # Debug - 'conditions': [ - [ 'OS=="win"', { - # TODO(bradnelson): add a gyp mechanism to make this more graceful. - 'Debug_x64': { - 'inherit_from': ['DebugBaseCommon'], - 'conditions': [ - ['v8_optimized_debug==0', { - 'inherit_from': ['DebugBase0'], - }, { - 'inherit_from': ['DebugBase1'], - }], - ], - }, - 'Release_x64': { - 'inherit_from': ['ReleaseBase'], - }, - }], - ], }, # configurations 'msvs_disabled_warnings': [ 4245, # Conversion with signed/unsigned mismatch. diff --git a/deps/v8/gypfiles/v8.gyp b/deps/v8/gypfiles/v8.gyp index f47cf075bb63bf..0c257025caeae4 100644 --- a/deps/v8/gypfiles/v8.gyp +++ b/deps/v8/gypfiles/v8.gyp @@ -2539,23 +2539,10 @@ '_HAS_EXCEPTIONS=0', 'BUILDING_V8_SHARED=1', ], - # This is defined trough `configurations` for GYP+ninja compatibility - 'configurations': { - 'Debug': { - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeTypeInfo': 'true', - 'ExceptionHandling': 1, - }, - } - }, - 'Release': { - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeTypeInfo': 'true', - 'ExceptionHandling': 1, - }, - } + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeTypeInfo': 'true', + 'ExceptionHandling': 1, }, }, 'sources': [ diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 9981061a44bf06..3689a122725f89 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -341,6 +341,12 @@ class V8_EXPORT CpuProfiler { V8_DEPRECATED("Use Isolate::SetIdle(bool) instead.", void SetIdle(bool is_idle)); + /** + * Generate more detailed source positions to code objects. This results in + * better results when mapping profiling samples to script source. + */ + static void UseDetailedSourcePositionsForProfiling(Isolate* isolate); + private: CpuProfiler(); ~CpuProfiler(); diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 360d80865ca427..63dc5e7a7bab0f 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 7 #define V8_MINOR_VERSION 0 #define V8_BUILD_NUMBER 276 -#define V8_PATCH_LEVEL 32 +#define V8_PATCH_LEVEL 38 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index c48025871aa85b..e1951ec270597d 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -3779,6 +3779,12 @@ class V8_EXPORT Array : public Object { */ static Local New(Isolate* isolate, int length = 0); + /** + * Creates a JavaScript array out of a Local array in C++ + * with a known length. + */ + static Local New(Isolate* isolate, Local* elements, + size_t length); V8_INLINE static Array* Cast(Value* obj); private: Array(); diff --git a/deps/v8/infra/testing/builders.pyl b/deps/v8/infra/testing/builders.pyl index bf24d2c9954131..31aef9c3214d90 100644 --- a/deps/v8/infra/testing/builders.pyl +++ b/deps/v8/infra/testing/builders.pyl @@ -685,11 +685,6 @@ {'name': 'mozilla'}, ], }, - 'V8 Linux - presubmit': { - 'tests': [ - {'name': 'presubmit'}, - ], - }, 'V8 Linux - shared': { 'tests': [ {'name': 'mozilla'}, @@ -1514,7 +1509,6 @@ }, 'tests': [ {'name': 'mozilla'}, - {'name': 'presubmit'}, {'name': 'test262'}, {'name': 'v8testing'}, ], @@ -1527,7 +1521,6 @@ }, 'tests': [ {'name': 'mozilla'}, - {'name': 'presubmit'}, {'name': 'test262'}, {'name': 'v8testing', 'shards': 3}, ], @@ -1540,7 +1533,6 @@ }, 'tests': [ {'name': 'mozilla'}, - {'name': 'presubmit'}, {'name': 'test262'}, {'name': 'v8testing'}, ], @@ -1553,7 +1545,6 @@ }, 'tests': [ {'name': 'mozilla'}, - {'name': 'presubmit'}, {'name': 'test262'}, {'name': 'v8testing', 'shards': 3}, ], diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 54d1ba1afc7099..8f8aaf7bc628ac 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -6981,6 +6981,23 @@ Local v8::Array::New(Isolate* isolate, int length) { return Utils::ToLocal(obj); } +Local v8::Array::New(Isolate* isolate, Local* elements, + size_t length) { + i::Isolate* i_isolate = reinterpret_cast(isolate); + i::Factory* factory = i_isolate->factory(); + LOG_API(i_isolate, Array, New); + ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); + int len = static_cast(length); + + i::Handle result = factory->NewFixedArray(len); + for (int i = 0; i < len; i++) { + i::Handle element = Utils::OpenHandle(*elements[i]); + result->set(i, *element); + } + + return Utils::ToLocal( + factory->NewJSArrayWithElements(result, i::PACKED_ELEMENTS, len)); +} uint32_t v8::Array::Length() const { i::Handle obj = Utils::OpenHandle(this); @@ -10115,6 +10132,11 @@ void CpuProfiler::SetIdle(bool is_idle) { isolate->SetIdle(is_idle); } +void CpuProfiler::UseDetailedSourcePositionsForProfiling(Isolate* isolate) { + reinterpret_cast(isolate) + ->set_detailed_source_positions_for_profiling(true); +} + uintptr_t CodeEvent::GetCodeStartAddress() { return reinterpret_cast(this)->code_start_address; } diff --git a/deps/v8/src/base/debug/stack_trace_win.cc b/deps/v8/src/base/debug/stack_trace_win.cc index 6b221312332411..3fe66d97ada531 100644 --- a/deps/v8/src/base/debug/stack_trace_win.cc +++ b/deps/v8/src/base/debug/stack_trace_win.cc @@ -7,6 +7,13 @@ #include "src/base/debug/stack_trace.h" +// This file can't use "src/base/win32-headers.h" because it defines symbols +// that lead to compilation errors. But `NOMINMAX` should be defined to disable +// defining of the `min` and `max` MACROS. +#ifndef NOMINMAX +#define NOMINMAX +#endif + #include #include #include diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 89fecce80431c5..eed52d9c19fb1a 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -3257,7 +3257,8 @@ bool Isolate::use_optimizer() { } bool Isolate::NeedsDetailedOptimizedCodeLineInfo() const { - return NeedsSourcePositionsForProfiling() || FLAG_detailed_line_info; + return NeedsSourcePositionsForProfiling() || + detailed_source_positions_for_profiling(); } bool Isolate::NeedsSourcePositionsForProfiling() const { diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index e199a93ec47859..efd479c41ee4a5 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -553,7 +553,8 @@ typedef std::vector DebugObjectCache; V(int, last_console_context_id, 0) \ V(v8_inspector::V8Inspector*, inspector, nullptr) \ V(bool, next_v8_call_is_safe_for_termination, false) \ - V(bool, only_terminate_in_safe_scope, false) + V(bool, only_terminate_in_safe_scope, false) \ + V(bool, detailed_source_positions_for_profiling, FLAG_detailed_line_info) #define THREAD_LOCAL_TOP_ACCESSOR(type, name) \ inline void set_##name(type v) { thread_local_top_.name##_ = v; } \ diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index d4af74b2bd3983..811656ad9afa43 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -10266,15 +10266,22 @@ Handle DescriptorArray::CopyForFastObjectClone( Name* key = src->GetKey(i); PropertyDetails details = src->GetDetails(i); - SLOW_DCHECK(!key->IsPrivateField() && details.IsEnumerable() && - details.kind() == kData); + DCHECK(!key->IsPrivateField()); + DCHECK(details.IsEnumerable()); + DCHECK_EQ(details.kind(), kData); // Ensure the ObjectClone property details are NONE, and that all source // details did not contain DONT_ENUM. PropertyDetails new_details(kData, NONE, details.location(), details.constness(), details.representation(), details.field_index()); - descriptors->Set(i, key, src->GetValue(i), new_details); + // Do not propagate the field type of normal object fields from the + // original descriptors since FieldType changes don't create new maps. + MaybeObject* type = src->GetValue(i); + if (details.location() == PropertyLocation::kField) { + type = MaybeObject::FromObject(FieldType::Any()); + } + descriptors->Set(i, key, type, new_details); } descriptors->Sort(); diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc index 71e297c4bf1501..3a1df29bd47b54 100644 --- a/deps/v8/src/profiler/heap-profiler.cc +++ b/deps/v8/src/profiler/heap-profiler.cc @@ -23,9 +23,14 @@ HeapProfiler::~HeapProfiler() = default; void HeapProfiler::DeleteAllSnapshots() { snapshots_.clear(); - names_.reset(new StringsStorage()); + MaybeClearStringsStorage(); } +void HeapProfiler::MaybeClearStringsStorage() { + if (snapshots_.empty() && !sampling_heap_profiler_ && !allocation_tracker_) { + names_.reset(new StringsStorage()); + } +} void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) { snapshots_.erase( @@ -126,6 +131,7 @@ bool HeapProfiler::StartSamplingHeapProfiler( void HeapProfiler::StopSamplingHeapProfiler() { sampling_heap_profiler_.reset(); + MaybeClearStringsStorage(); } @@ -159,6 +165,7 @@ void HeapProfiler::StopHeapObjectsTracking() { ids_->StopHeapObjectsTracking(); if (allocation_tracker_) { allocation_tracker_.reset(); + MaybeClearStringsStorage(); heap()->RemoveHeapObjectAllocationTracker(this); } } diff --git a/deps/v8/src/profiler/heap-profiler.h b/deps/v8/src/profiler/heap-profiler.h index 8ce379d59df6ca..099c0e24fad7d8 100644 --- a/deps/v8/src/profiler/heap-profiler.h +++ b/deps/v8/src/profiler/heap-profiler.h @@ -92,6 +92,8 @@ class HeapProfiler : public HeapObjectAllocationTracker { v8::PersistentValueVector* objects); private: + void MaybeClearStringsStorage(); + Heap* heap() const; // Mapping from HeapObject addresses to objects' uids. diff --git a/deps/v8/src/runtime/runtime-array.cc b/deps/v8/src/runtime/runtime-array.cc index 31b03f6bb75044..d72159b0acf926 100644 --- a/deps/v8/src/runtime/runtime-array.cc +++ b/deps/v8/src/runtime/runtime-array.cc @@ -145,7 +145,15 @@ Object* RemoveArrayHolesGeneric(Isolate* isolate, Handle receiver, MAYBE_RETURN(delete_result, ReadOnlyRoots(isolate).exception()); } - return *isolate->factory()->NewNumberFromUint(result); + // TODO(jgruber, szuend, chromium:897512): This is a workaround to prevent + // returning a number greater than array.length to Array.p.sort, which could + // trigger OOB accesses. There is still a correctness bug here though in + // how we shift around undefineds and delete elements in the two blocks above. + // This needs to be fixed soon. + const uint32_t number_of_non_undefined_elements = std::min(limit, result); + + return *isolate->factory()->NewNumberFromUint( + number_of_non_undefined_elements); } // Collects all defined (non-hole) and non-undefined (array) elements at the @@ -162,6 +170,7 @@ Object* RemoveArrayHoles(Isolate* isolate, Handle receiver, Handle object = Handle::cast(receiver); if (object->HasStringWrapperElements()) { int len = String::cast(Handle::cast(object)->value())->length(); + DCHECK_LE(len, limit); return Smi::FromInt(len); } @@ -284,6 +293,7 @@ Object* RemoveArrayHoles(Isolate* isolate, Handle receiver, } } + DCHECK_LE(result, limit); return *isolate->factory()->NewNumberFromUint(result); } diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc index b950c590b5c6b2..892a4e980e8b55 100644 --- a/deps/v8/src/wasm/module-compiler.cc +++ b/deps/v8/src/wasm/module-compiler.cc @@ -2329,12 +2329,6 @@ void AsyncCompileJob::CancelPendingForegroundTask() { pending_foreground_task_ = nullptr; } -template -void AsyncCompileJob::DoSync(Args&&... args) { - NextStep(std::forward(args)...); - StartForegroundTask(); -} - void AsyncCompileJob::StartBackgroundTask() { auto task = base::make_unique(this, false); @@ -2347,6 +2341,18 @@ void AsyncCompileJob::StartBackgroundTask() { } } +template +void AsyncCompileJob::DoSync(Args&&... args) { + NextStep(std::forward(args)...); + StartForegroundTask(); +} + +template +void AsyncCompileJob::DoImmediately(Args&&... args) { + NextStep(std::forward(args)...); + ExecuteForegroundTaskImmediately(); +} + template void AsyncCompileJob::DoAsync(Args&&... args) { NextStep(std::forward(args)...); @@ -2686,11 +2692,10 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(size_t functions_count, FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false)); return false; } - job_->NextStep( - decoder_.shared_module(), false); // Execute the PrepareAndStartCompile step immediately and not in a separate // task. - job_->ExecuteForegroundTaskImmediately(); + job_->DoImmediately( + decoder_.shared_module(), false); job_->native_module_->compilation_state()->SetNumberOfFunctionsToCompile( functions_count); @@ -2734,25 +2739,26 @@ void AsyncStreamingProcessor::OnFinishedChunk() { // Finish the processing of the stream. void AsyncStreamingProcessor::OnFinishedStream(OwnedVector bytes) { TRACE_STREAMING("Finish stream...\n"); - if (job_->native_module_) { - job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector()); - job_->native_module_->set_wire_bytes(std::move(bytes)); - } ModuleResult result = decoder_.FinishDecoding(false); DCHECK(result.ok()); - if (job_->DecrementAndCheckFinisherCount()) { - if (job_->native_module_ == nullptr) { - // We are processing a WebAssembly module without code section. We need to - // prepare compilation first before we can finish it. - // {PrepareAndStartCompile} will call {FinishCompile} by itself if there - // is no code section. - job_->DoSync(result.val, true); - } else { - HandleScope scope(job_->isolate_); - SaveContext saved_context(job_->isolate_); - job_->isolate_->set_context(*job_->native_context_); - job_->FinishCompile(); - } + bool needs_finish = job_->DecrementAndCheckFinisherCount(); + if (job_->native_module_ == nullptr) { + // We are processing a WebAssembly module without code section. We need to + // prepare compilation first before we can finish it. + // {PrepareAndStartCompile} will call {FinishCompile} by itself if there + // is no code section. + DCHECK(needs_finish); + needs_finish = false; + job_->DoImmediately(result.val, + true); + } + job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector()); + job_->native_module_->set_wire_bytes(std::move(bytes)); + if (needs_finish) { + HandleScope scope(job_->isolate_); + SaveContext saved_context(job_->isolate_); + job_->isolate_->set_context(*job_->native_context_); + job_->FinishCompile(); } } diff --git a/deps/v8/src/wasm/module-compiler.h b/deps/v8/src/wasm/module-compiler.h index 57bbd883e21f30..934c978d491109 100644 --- a/deps/v8/src/wasm/module-compiler.h +++ b/deps/v8/src/wasm/module-compiler.h @@ -126,6 +126,10 @@ class AsyncCompileJob { template void DoSync(Args&&... args); + // Switches to the compilation step {Step} and immediately executes that step. + template + void DoImmediately(Args&&... args); + // Switches to the compilation step {Step} and starts a background task to // execute it. template diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index bf5aba2df66947..f7365c8f31a8c8 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -5247,6 +5247,22 @@ THREADED_TEST(Array) { CHECK_EQ(27u, array->Length()); array = v8::Array::New(context->GetIsolate(), -27); CHECK_EQ(0u, array->Length()); + + std::vector> vector = {v8_num(1), v8_num(2), v8_num(3)}; + array = v8::Array::New(context->GetIsolate(), vector.data(), vector.size()); + CHECK_EQ(vector.size(), array->Length()); + CHECK_EQ(1, arr->Get(context.local(), 0) + .ToLocalChecked() + ->Int32Value(context.local()) + .FromJust()); + CHECK_EQ(2, arr->Get(context.local(), 1) + .ToLocalChecked() + ->Int32Value(context.local()) + .FromJust()); + CHECK_EQ(3, arr->Get(context.local(), 2) + .ToLocalChecked() + ->Int32Value(context.local()) + .FromJust()); } diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index 75af3f6d98f127..851099607945e6 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -40,6 +40,7 @@ #include "src/objects-inl.h" #include "src/profiler/cpu-profiler-inl.h" #include "src/profiler/profiler-listener.h" +#include "src/source-position-table.h" #include "src/utils.h" #include "test/cctest/cctest.h" #include "test/cctest/profiler-extension.h" @@ -2544,6 +2545,46 @@ TEST(MultipleProfilers) { profiler2->StopProfiling("2"); } +UNINITIALIZED_TEST(DetailedSourcePositionAPI) { + i::FLAG_detailed_line_info = false; + i::FLAG_allow_natives_syntax = true; + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + + const char* source = + "function fib(i) {" + " if (i <= 1) return 1; " + " return fib(i - 1) +" + " fib(i - 2);" + "}" + "fib(5);" + "%OptimizeFunctionOnNextCall(fib);" + "fib(5);" + "fib"; + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Local context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); + i::Isolate* i_isolate = reinterpret_cast(isolate); + + CHECK(!i_isolate->NeedsDetailedOptimizedCodeLineInfo()); + + int non_detailed_positions = GetSourcePositionEntryCount(i_isolate, source); + + v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate); + CHECK(i_isolate->NeedsDetailedOptimizedCodeLineInfo()); + + int detailed_positions = GetSourcePositionEntryCount(i_isolate, source); + + CHECK((non_detailed_positions == -1 && detailed_positions == -1) || + non_detailed_positions < detailed_positions); + } + + isolate->Dispose(); +} + } // namespace test_cpu_profiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index 5d8094d6351f6b..e4e5f4c8dc0845 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -3900,3 +3900,45 @@ TEST(WeakReference) { const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); } + +TEST(Bug8373_1) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + heap_profiler->StartSamplingHeapProfiler(100); + + heap_profiler->TakeHeapSnapshot(); + // Causes the StringsStorage to be deleted. + heap_profiler->DeleteAllHeapSnapshots(); + + // Triggers an allocation sample that tries to use the StringsStorage. + for (int i = 0; i < 2 * 1024; ++i) { + CompileRun( + "new Array(64);" + "new Uint8Array(16);"); + } + + heap_profiler->StopSamplingHeapProfiler(); +} + +TEST(Bug8373_2) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + heap_profiler->StartTrackingHeapObjects(true); + + heap_profiler->TakeHeapSnapshot(); + // Causes the StringsStorage to be deleted. + heap_profiler->DeleteAllHeapSnapshots(); + + // Triggers an allocations that try to use the StringsStorage. + for (int i = 0; i < 2 * 1024; ++i) { + CompileRun( + "new Array(64);" + "new Uint8Array(16);"); + } + + heap_profiler->StopTrackingHeapObjects(); +} diff --git a/deps/v8/test/mjsunit/regress/regress-897366.js b/deps/v8/test/mjsunit/regress/regress-897366.js new file mode 100644 index 00000000000000..990e21590e5a7f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-897366.js @@ -0,0 +1,15 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --gc-interval=100 + +let xs = []; +for (let i = 0; i < 205; ++i) { + xs.push(i); +} +xs.sort((a, b) => { + xs.shift(); + xs[xs.length] = -246; + return a - b; +}); diff --git a/deps/v8/test/mjsunit/regress/regress-897512.js b/deps/v8/test/mjsunit/regress/regress-897512.js new file mode 100644 index 00000000000000..0e676a06c2a6d6 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-897512.js @@ -0,0 +1,24 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Fill up the Array prototype's elements. +for (let i = 0; i < 100; i++) Array.prototype.unshift(3.14); + +// Create a holey double elements array. +const o31 = [1.1]; +o31[37] = 2.2; + +// Concat converts to dictionary elements. +const o51 = o31.concat(false); + +// Set one element to undefined to trigger the movement bug. +o51[0] = undefined; + +assertEquals(o51.length, 39); + +// Sort triggers the bug. +o51.sort(); + +// TODO(chromium:897512): The length should be 39. +assertEquals(o51.length, 101); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-881247.js b/deps/v8/test/mjsunit/regress/regress-crbug-881247.js new file mode 100644 index 00000000000000..4605c3f51bc3b3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-881247.js @@ -0,0 +1,24 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const resolvedPromise = Promise.resolve(); + +function spread() { + const result = { ...resolvedPromise }; + %HeapObjectVerify(result); + return result; +} + +resolvedPromise[undefined] = {a:1}; +%HeapObjectVerify(resolvedPromise); + +spread(); + +resolvedPromise[undefined] = undefined; +%HeapObjectVerify(resolvedPromise); + +spread(); +%HeapObjectVerify(resolvedPromise); diff --git a/deps/v8/test/mjsunit/wasm/async-compile.js b/deps/v8/test/mjsunit/wasm/async-compile.js index e7f87c30e9e418..39a339aae63209 100644 --- a/deps/v8/test/mjsunit/wasm/async-compile.js +++ b/deps/v8/test/mjsunit/wasm/async-compile.js @@ -70,3 +70,10 @@ assertPromiseResult(async function badFunctionInTheMiddle() { let buffer = builder.toBuffer(); await assertCompileError(buffer); }()); + +assertPromiseResult(async function importWithoutCode() { + // Regression test for https://crbug.com/898310. + let builder = new WasmModuleBuilder(); + builder.addImport('m', 'q', kSig_i_i); + await builder.asyncInstantiate({'m': {'q': i => i}}); +}()); diff --git a/deps/v8/third_party/v8/builtins/array-sort.tq b/deps/v8/third_party/v8/builtins/array-sort.tq index a94b432935074c..65d0b8348bd210 100644 --- a/deps/v8/third_party/v8/builtins/array-sort.tq +++ b/deps/v8/third_party/v8/builtins/array-sort.tq @@ -826,7 +826,7 @@ module array { assert(i >= 0); assert(i == stack_size - 2 || i == stack_size - 3); - const elements: HeapObject = ReloadElements(sortState); + let elements: HeapObject = ReloadElements(sortState); const Load: LoadFn = GetLoadFn(sortState); const pending_runs: FixedArray = @@ -859,6 +859,7 @@ module array { const k: Smi = CallGallopRight( context, sortState, Load, key_right, base_a, length_a, 0, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(k >= 0); base_a = base_a + k; @@ -874,6 +875,7 @@ module array { length_b = CallGallopLeft( context, sortState, Load, key_left, base_b, length_b, length_b - 1, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(length_b >= 0); if (length_b == 0) return kSuccess; @@ -893,6 +895,12 @@ module array { } } + macro LoadElementsOrTempArray( + useTempArray: Boolean, sortState: FixedArray): HeapObject { + return useTempArray == True ? GetTempArray(sortState) : + ReloadElements(sortState); + } + // Locates the proper position of key in a sorted array; if the array contains // an element equal to key, return the position immediately to the left of // the leftmost equal element. (GallopRight does the same except returns the @@ -916,25 +924,17 @@ module array { assert(length > 0 && base >= 0); assert(0 <= hint && hint < length); - // We cannot leave a pointer to elements on the stack (see comment at - // ReloadElements). For this reason we pass a flag whether to reload - // and which array to use. - let elements: HeapObject = useTempArray == True ? GetTempArray(sortState) : - ReloadElements(sortState); - let last_ofs: Smi = 0; let offset: Smi = 1; try { - const base_hint_element: Object = - CallLoad(context, sortState, Load, elements, base + hint) + const base_hint_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + hint) otherwise Bailout; let order: Number = CallCompareFn(context, sortState, base_hint_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { // a[base + hint] < key: gallop right, until @@ -943,14 +943,13 @@ module array { // a[base + length - 1] is highest. let max_ofs: Smi = length - hint; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint + offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint + offset) otherwise Bailout; order = CallCompareFn(context, sortState, offset_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } // a[base + hint + offset] >= key? Break. if (order >= 0) break; @@ -975,14 +974,13 @@ module array { // a[base + hint] is lowest. let max_ofs: Smi = hint + 1; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint - offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint - offset) otherwise Bailout; order = CallCompareFn(context, sortState, offset_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) break; @@ -1011,14 +1009,12 @@ module array { while (last_ofs < offset) { const m: Smi = last_ofs + ((offset - last_ofs) >>> 1); - const base_m_element: Object = - CallLoad(context, sortState, Load, elements, base + m) + const base_m_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + m) otherwise Bailout; order = CallCompareFn(context, sortState, base_m_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { last_ofs = m + 1; // a[base + m] < key. @@ -1051,25 +1047,17 @@ module array { assert(length > 0 && base >= 0); assert(0 <= hint && hint < length); - // We cannot leave a pointer to elements on the stack (see comment at - // ReloadElements). For this reason we pass a flag whether to reload - // and which array to use. - let elements: HeapObject = useTempArray == True ? GetTempArray(sortState) : - ReloadElements(sortState); - let last_ofs: Smi = 0; let offset: Smi = 1; try { - const base_hint_element: Object = - CallLoad(context, sortState, Load, elements, base + hint) + const base_hint_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + hint) otherwise Bailout; let order: Number = CallCompareFn(context, sortState, key, base_hint_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { // key < a[base + hint]: gallop left, until @@ -1078,14 +1066,13 @@ module array { // a[base + hint] is lowest. let max_ofs: Smi = hint + 1; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint - offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint - offset) otherwise Bailout; order = CallCompareFn(context, sortState, key, offset_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order >= 0) break; @@ -1109,14 +1096,13 @@ module array { // a[base + length - 1] is highest. let max_ofs: Smi = length - hint; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint + offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint + offset) otherwise Bailout; order = CallCompareFn(context, sortState, key, offset_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } // a[base + hint + ofs] <= key. if (order < 0) break; @@ -1144,14 +1130,12 @@ module array { while (last_ofs < offset) { const m: Smi = last_ofs + ((offset - last_ofs) >>> 1); - const base_m_element: Object = - CallLoad(context, sortState, Load, elements, base + m) + const base_m_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + m) otherwise Bailout; order = CallCompareFn(context, sortState, key, base_m_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { offset = m; // key < a[base + m]. @@ -1288,6 +1272,7 @@ module array { nof_wins_a = CallGallopRight( context, sortState, Load, key_right, cursor_temp, length_a, 0, True) otherwise Bailout; + elements = ReloadElements(sortState); assert(nof_wins_a >= 0); if (nof_wins_a > 0) { @@ -1313,6 +1298,7 @@ module array { context, sortState, LoadF, temp_array[cursor_temp], cursor_b, length_b, 0, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(nof_wins_b >= 0); if (nof_wins_b > 0) { CallCopyWithinSortArray( @@ -1461,6 +1447,7 @@ module array { context, sortState, LoadF, temp_array[cursor_temp], baseA, length_a, length_a - 1, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(k >= 0); nof_wins_a = length_a - k; @@ -1487,6 +1474,7 @@ module array { k = CallGallopLeft( context, sortState, Load, key, 0, length_b, length_b - 1, True) otherwise Bailout; + elements = ReloadElements(sortState); assert(k >= 0); nof_wins_b = length_b - k; @@ -1742,35 +1730,35 @@ module array { // 2. Let obj be ? ToObject(this value). const obj: JSReceiver = ToObject(context, receiver); - let map: Map = obj.map; - const sort_state: FixedArray = - AllocateZeroedFixedArray(kSortStateSize); + const sort_state: FixedArray = AllocateZeroedFixedArray(kSortStateSize); FillFixedArrayWithSmiZero(sort_state, SmiTag(kSortStateSize)); sort_state[kReceiverIdx] = obj; sort_state[kUserCmpFnIdx] = comparefnObj; sort_state[kSortComparePtrIdx] = comparefnObj != Undefined ? SortCompareUserFn : SortCompareDefault; - sort_state[kInitialReceiverMapIdx] = map; sort_state[kBailoutStatusIdx] = kSuccess; + // 3. Let len be ? ToLength(? Get(obj, "length")). + const len: Number = + ToLength_Inline(context, GetProperty(context, obj, 'length')); + if (len < 2) return receiver; + + // TODO(szuend): Investigate performance tradeoff of skipping this step + // for PACKED_* and handling Undefineds during sorting. + const nofNonUndefined: Smi = PrepareElementsForSort(context, obj, len); + assert(nofNonUndefined <= len); + + let map: Map = obj.map; + sort_state[kInitialReceiverMapIdx] = map; + sort_state[kInitialReceiverLengthIdx] = len; + try { const a: JSArray = cast(obj) otherwise slow; const elementsKind: ElementsKind = map.elements_kind; if (!IsFastElementsKind(elementsKind)) goto slow; - // 3. Let len be ? ToLength(? Get(obj, "length")). - const len: Smi = a.length_fast; - if (len < 2) return receiver; - - // TODO(szuend): Investigate performance tradeoff of skipping this step - // for PACKED_* and handling Undefineds during sorting. - const nofNonUndefined: Smi = PrepareElementsForSort(context, obj, len); - assert(a.map == map); - - sort_state[kInitialReceiverLengthIdx] = len; - if (IsDoubleElementsKind(elementsKind)) { InitializeSortStateAccessor(sort_state); } else if (elementsKind == PACKED_SMI_ELEMENTS) { @@ -1781,19 +1769,6 @@ module array { ArrayTimSort(context, sort_state, nofNonUndefined); } label slow { - // 3. Let len be ? ToLength(? Get(obj, "length")). - const len: Number = - ToLength_Inline(context, GetProperty(context, obj, 'length')); - - if (len < 2) return receiver; - const nofNonUndefined: Smi = PrepareElementsForSort(context, obj, len); - - sort_state[kInitialReceiverLengthIdx] = len; - - // Reload the map, PrepareElementsForSort might have changed the - // elements kind. - map = obj.map; - if (map.elements_kind == DICTIONARY_ELEMENTS && IsExtensibleMap(map) && !IsCustomElementsReceiverInstanceType(map.instance_type)) { InitializeSortStateAccessor(sort_state); diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/v8_presubmit.py similarity index 100% rename from deps/v8/tools/presubmit.py rename to deps/v8/tools/v8_presubmit.py diff --git a/doc/api/addons.md b/doc/api/addons.md index 757f24c5194271..d993c72d346495 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -63,13 +63,15 @@ namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; void Method(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); + args.GetReturnValue().Set(String::NewFromUtf8( + isolate, "world", NewStringType::kNormal).ToLocalChecked()); } void Initialize(Local exports) { @@ -464,6 +466,7 @@ using v8::Exception; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Number; using v8::Object; using v8::String; @@ -479,14 +482,18 @@ void Add(const FunctionCallbackInfo& args) { if (args.Length() < 2) { // Throw an Error that is passed back to JavaScript isolate->ThrowException(Exception::TypeError( - String::NewFromUtf8(isolate, "Wrong number of arguments"))); + String::NewFromUtf8(isolate, + "Wrong number of arguments", + NewStringType::kNormal).ToLocalChecked())); return; } // Check the argument types if (!args[0]->IsNumber() || !args[1]->IsNumber()) { isolate->ThrowException(Exception::TypeError( - String::NewFromUtf8(isolate, "Wrong arguments"))); + String::NewFromUtf8(isolate, + "Wrong arguments", + NewStringType::kNormal).ToLocalChecked())); return; } @@ -530,10 +537,12 @@ to invoke such callbacks: namespace demo { +using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Null; using v8::Object; using v8::String; @@ -541,10 +550,14 @@ using v8::Value; void RunCallback(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); + Local context = isolate->GetCurrentContext(); Local cb = Local::Cast(args[0]); const unsigned argc = 1; - Local argv[argc] = { String::NewFromUtf8(isolate, "hello world") }; - cb->Call(Null(isolate), argc, argv); + Local argv[argc] = { + String::NewFromUtf8(isolate, + "hello world", + NewStringType::kNormal).ToLocalChecked() }; + cb->Call(context, Null(isolate), argc, argv).ToLocalChecked(); } void Init(Local exports, Local module) { @@ -591,6 +604,7 @@ using v8::Context; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -600,8 +614,12 @@ void CreateObject(const FunctionCallbackInfo& args) { Local context = isolate->GetCurrentContext(); Local obj = Object::New(isolate); - obj->Set(String::NewFromUtf8(isolate, "msg"), - args[0]->ToString(context).ToLocalChecked()); + obj->Set(context, + String::NewFromUtf8(isolate, + "msg", + NewStringType::kNormal).ToLocalChecked(), + args[0]->ToString(context).ToLocalChecked()) + .FromJust(); args.GetReturnValue().Set(obj); } @@ -644,13 +662,15 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; void MyFunction(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world")); + args.GetReturnValue().Set(String::NewFromUtf8( + isolate, "hello world", NewStringType::kNormal).ToLocalChecked()); } void CreateFunction(const FunctionCallbackInfo& args) { @@ -661,7 +681,8 @@ void CreateFunction(const FunctionCallbackInfo& args) { Local fn = tpl->GetFunction(context).ToLocalChecked(); // omit this to make it anonymous - fn->SetName(String::NewFromUtf8(isolate, "theFunction")); + fn->SetName(String::NewFromUtf8( + isolate, "theFunction", NewStringType::kNormal).ToLocalChecked()); args.GetReturnValue().Set(fn); } @@ -757,6 +778,7 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Number; using v8::Object; using v8::Persistent; @@ -776,7 +798,8 @@ void MyObject::Init(Local exports) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); + tpl->SetClassName(String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype @@ -784,8 +807,9 @@ void MyObject::Init(Local exports) { Local context = isolate->GetCurrentContext(); constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked()); - exports->Set(String::NewFromUtf8(isolate, "MyObject"), - tpl->GetFunction(context).ToLocalChecked()); + exports->Set(context, String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(), + tpl->GetFunction(context).ToLocalChecked()).FromJust(); } void MyObject::New(const FunctionCallbackInfo& args) { @@ -952,6 +976,7 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Number; using v8::Object; using v8::Persistent; @@ -969,7 +994,8 @@ MyObject::~MyObject() { void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); + tpl->SetClassName(String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype @@ -1167,6 +1193,7 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::Persistent; using v8::String; @@ -1183,7 +1210,8 @@ MyObject::~MyObject() { void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); + tpl->SetClassName(String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Local context = isolate->GetCurrentContext(); diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index ff3e14b96c250e..1529e33e474084 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -63,7 +63,7 @@ function init(asyncId, type, triggerAsyncId, resource) { } // before is called just before the resource's callback is called. It can be // called 0-N times for handles (e.g. TCPWrap), and will be called exactly 1 -// time for requests (e.g. FSReqWrap). +// time for requests (e.g. FSReqCallback). function before(asyncId) { } // after is called just after the resource's callback has finished. @@ -236,9 +236,9 @@ The `type` is a string identifying the type of resource that caused resource's constructor. ```text -FSEVENTWRAP, FSREQWRAP, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPPARSER, +FSEVENTWRAP, FSREQCALLBACK, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPPARSER, JSSTREAM, PIPECONNECTWRAP, PIPEWRAP, PROCESSWRAP, QUERYWRAP, SHUTDOWNWRAP, -SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVER, TCPWRAP, TTYWRAP, +SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVERWRAP, TCPWRAP, TTYWRAP, UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST, RANDOMBYTESREQUEST, TLSWRAP, Microtask, Timeout, Immediate, TickObject ``` @@ -276,8 +276,8 @@ require('net').createServer((conn) => {}).listen(8080); Output when hitting the server with `nc localhost 8080`: ```console -TCPSERVERWRAP(2): trigger: 1 execution: 1 -TCPWRAP(4): trigger: 2 execution: 0 +TCPSERVERWRAP(5): trigger: 1 execution: 1 +TCPWRAP(7): trigger: 5 execution: 0 ``` The `TCPSERVERWRAP` is the server which receives the connections. @@ -296,7 +296,7 @@ of propagating what resource is responsible for the new resource's existence. been initialized. This can contain useful information that can vary based on the value of `type`. For instance, for the `GETADDRINFOREQWRAP` resource type, `resource` provides the hostname used when looking up the IP address for the -hostname in `net.Server.listen()`. The API for accessing this information is +host in `net.Server.listen()`. The API for accessing this information is currently not considered public, but using the Embedder API, users can provide and document their own resource objects. For example, such a resource object could contain the SQL query being executed. @@ -355,27 +355,18 @@ require('net').createServer(() => {}).listen(8080, () => { Output from only starting the server: ```console -TCPSERVERWRAP(2): trigger: 1 execution: 1 -TickObject(3): trigger: 2 execution: 1 -before: 3 - Timeout(4): trigger: 3 execution: 3 - TIMERWRAP(5): trigger: 3 execution: 3 -after: 3 -destroy: 3 -before: 5 - before: 4 - TTYWRAP(6): trigger: 4 execution: 4 - SIGNALWRAP(7): trigger: 4 execution: 4 - TTYWRAP(8): trigger: 4 execution: 4 ->>> 4 - TickObject(9): trigger: 4 execution: 4 - after: 4 -after: 5 -before: 9 -after: 9 -destroy: 4 -destroy: 9 -destroy: 5 +TCPSERVERWRAP(5): trigger: 1 execution: 1 +TickObject(6): trigger: 5 execution: 1 +before: 6 + Timeout(7): trigger: 6 execution: 6 +after: 6 +destroy: 6 +before: 7 +>>> 7 + TickObject(8): trigger: 7 execution: 7 +after: 7 +before: 8 +after: 8 ``` As illustrated in the example, `executionAsyncId()` and `execution` each specify @@ -385,7 +376,7 @@ the value of the current execution context; which is delineated by calls to Only using `execution` to graph resource allocation results in the following: ```console -TTYWRAP(6) -> Timeout(4) -> TIMERWRAP(5) -> TickObject(3) -> root(1) +Timeout(7) -> TickObject(6) -> root(1) ``` The `TCPSERVERWRAP` is not part of this graph, even though it was the reason for @@ -704,6 +695,8 @@ alternative. #### asyncResource.emitDestroy() +* Returns: {AsyncResource} A reference to `asyncResource`. + Call all `destroy` hooks. This should only ever be called once. An error will be thrown if it is called more than once. This **must** be manually called. If the resource is left to be collected by the GC then the `destroy` hooks will diff --git a/doc/api/child_process.md b/doc/api/child_process.md index b2a6e443f964e0..7ba83b3528f8ef 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -131,9 +131,6 @@ exec('"my script.cmd" a b', (err, stdout, stderr) => { * `spkac` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `spkac` string. * Returns: {Buffer} The public key component of the `spkac` data structure, which includes a public key and a challenge. @@ -231,9 +231,9 @@ console.log(encrypted); -* `outputEncoding` {string} +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Any remaining enciphered contents. - If `outputEncoding` is one of `'latin1'`, `'base64'` or `'hex'`, a string is + If `outputEncoding` is specified, a string is returned. If an `outputEncoding` is not provided, a [`Buffer`][] is returned. Once the `cipher.final()` method has been called, the `Cipher` object can no @@ -299,19 +299,19 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the data. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Updates the cipher with `data`. If the `inputEncoding` argument is given, -its value must be one of `'utf8'`, `'ascii'`, or `'latin1'` and the `data` +the `data` argument is a string using the specified encoding. If the `inputEncoding` argument is not given, `data` must be a [`Buffer`][], `TypedArray`, or `DataView`. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. The `outputEncoding` specifies the output format of the enciphered -data, and can be `'latin1'`, `'base64'` or `'hex'`. If the `outputEncoding` +data. If the `outputEncoding` is specified, a string using the specified encoding is returned. If no `outputEncoding` is provided, a [`Buffer`][] is returned. @@ -390,9 +390,9 @@ console.log(decrypted); -* `outputEncoding` {string} +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Any remaining deciphered contents. - If `outputEncoding` is one of `'latin1'`, `'ascii'` or `'utf8'`, a string is + If `outputEncoding` is specified, a string is returned. If an `outputEncoding` is not provided, a [`Buffer`][] is returned. Once the `decipher.final()` method has been called, the `Decipher` object can @@ -473,18 +473,18 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Updates the decipher with `data`. If the `inputEncoding` argument is given, -its value must be one of `'latin1'`, `'base64'`, or `'hex'` and the `data` +the `data` argument is a string using the specified encoding. If the `inputEncoding` argument is not given, `data` must be a [`Buffer`][]. If `data` is a [`Buffer`][] then `inputEncoding` is ignored. The `outputEncoding` specifies the output format of the enciphered -data, and can be `'latin1'`, `'ascii'` or `'utf8'`. If the `outputEncoding` +data. If the `outputEncoding` is specified, a string using the specified encoding is returned. If no `outputEncoding` is provided, a [`Buffer`][] is returned. @@ -528,15 +528,15 @@ assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex')); added: v0.5.0 --> * `otherPublicKey` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of an `otherPublicKey` string. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Computes the shared secret using `otherPublicKey` as the other party's public key and returns the computed shared secret. The supplied key is interpreted using the specified `inputEncoding`, and secret is -encoded using specified `outputEncoding`. Encodings can be -`'latin1'`, `'hex'`, or `'base64'`. If the `inputEncoding` is not +encoded using specified `outputEncoding`. +If the `inputEncoding` is not provided, `otherPublicKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -547,57 +547,57 @@ If `outputEncoding` is given a string is returned; otherwise, a -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Generates private and public Diffie-Hellman key values, and returns the public key in the specified `encoding`. This key should be -transferred to the other party. Encoding can be `'latin1'`, `'hex'`, -or `'base64'`. If `encoding` is provided a string is returned; otherwise a +transferred to the other party. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getGenerator([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman generator in the specified `encoding`, which can -be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is +Returns the Diffie-Hellman generator in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPrime([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman prime in the specified `encoding`, which can -be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is +Returns the Diffie-Hellman prime in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPrivateKey([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman private key in the specified `encoding`, -which can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a +Returns the Diffie-Hellman private key in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPublicKey([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman public key in the specified `encoding`, which -can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a +Returns the Diffie-Hellman public key in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.setPrivateKey(privateKey[, encoding]) @@ -605,10 +605,10 @@ string is returned; otherwise a [`Buffer`][] is returned. added: v0.5.0 --> * `privateKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `privateKey` string. -Sets the Diffie-Hellman private key. If the `encoding` argument is provided -and is either `'latin1'`, `'hex'`, or `'base64'`, `privateKey` is expected +Sets the Diffie-Hellman private key. If the `encoding` argument is provided, +`privateKey` is expected to be a string. If no `encoding` is provided, `privateKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -617,10 +617,10 @@ to be a [`Buffer`][], `TypedArray`, or `DataView`. added: v0.5.0 --> * `publicKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `publicKey` string. -Sets the Diffie-Hellman public key. If the `encoding` argument is provided -and is either `'latin1'`, `'hex'` or `'base64'`, `publicKey` is expected +Sets the Diffie-Hellman public key. If the `encoding` argument is provided, +`publicKey` is expected to be a string. If no `encoding` is provided, `publicKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -678,8 +678,8 @@ added: v10.0.0 * `key` {string | Buffer | TypedArray | DataView} * `curve` {string} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `key` string. +* `outputEncoding` {string} The [encoding][] of the return value. * `format` {string} **Default:** `'uncompressed'` * Returns: {Buffer | string} @@ -687,8 +687,7 @@ Converts the EC Diffie-Hellman public key specified by `key` and `curve` to the format specified by `format`. The `format` argument specifies point encoding and can be `'compressed'`, `'uncompressed'` or `'hybrid'`. The supplied key is interpreted using the specified `inputEncoding`, and the returned key is encoded -using the specified `outputEncoding`. Encodings can be `'latin1'`, `'hex'`, -or `'base64'`. +using the specified `outputEncoding`. Use [`crypto.getCurves()`][] to obtain a list of available curve names. On recent OpenSSL releases, `openssl ecparam -list_curves` will also display @@ -733,15 +732,15 @@ changes: error --> * `otherPublicKey` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `otherPublicKey` string. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Computes the shared secret using `otherPublicKey` as the other party's public key and returns the computed shared secret. The supplied key is interpreted using specified `inputEncoding`, and the returned secret -is encoded using the specified `outputEncoding`. Encodings can be -`'latin1'`, `'hex'`, or `'base64'`. If the `inputEncoding` is not +is encoded using the specified `outputEncoding`. +If the `inputEncoding` is not provided, `otherPublicKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -758,7 +757,7 @@ its recommended for developers to handle this exception accordingly. -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * `format` {string} **Default:** `'uncompressed'` * Returns: {Buffer | string} @@ -770,24 +769,24 @@ The `format` argument specifies point encoding and can be `'compressed'` or `'uncompressed'`. If `format` is not specified, the point will be returned in `'uncompressed'` format. -The `encoding` argument can be `'latin1'`, `'hex'`, or `'base64'`. If -`encoding` is provided a string is returned; otherwise a [`Buffer`][] +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### ecdh.getPrivateKey([encoding]) -* `encoding` {string} -* Returns: {Buffer | string} The EC Diffie-Hellman private key in the specified - `encoding`, which can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` - is provided a string is returned; otherwise a [`Buffer`][] is returned. +* `encoding` {string} The [encoding][] of the return value. +* Returns: {Buffer | string} The EC Diffie-Hellman in the specified `encoding`. + +If `encoding` is specified, a string is returned; otherwise a [`Buffer`][] is +returned. ### ecdh.getPublicKey([encoding][, format]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * `format` {string} **Default:** `'uncompressed'` * Returns: {Buffer | string} The EC Diffie-Hellman public key in the specified `encoding` and `format`. @@ -796,8 +795,7 @@ The `format` argument specifies point encoding and can be `'compressed'` or `'uncompressed'`. If `format` is not specified the point will be returned in `'uncompressed'` format. -The `encoding` argument can be `'latin1'`, `'hex'`, or `'base64'`. If -`encoding` is specified, a string is returned; otherwise a [`Buffer`][] is +If `encoding` is specified, a string is returned; otherwise a [`Buffer`][] is returned. ### ecdh.setPrivateKey(privateKey[, encoding]) @@ -805,10 +803,10 @@ returned. added: v0.11.14 --> * `privateKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `privateKey` string. -Sets the EC Diffie-Hellman private key. The `encoding` can be `'latin1'`, -`'hex'` or `'base64'`. If `encoding` is provided, `privateKey` is expected +Sets the EC Diffie-Hellman private key. +If `encoding` is provided, `privateKey` is expected to be a string; otherwise `privateKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -825,10 +823,10 @@ deprecated: v5.2.0 > Stability: 0 - Deprecated * `publicKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `publicKey` string. -Sets the EC Diffie-Hellman public key. Key encoding can be `'latin1'`, -`'hex'` or `'base64'`. If `encoding` is provided `publicKey` is expected to +Sets the EC Diffie-Hellman public key. +If `encoding` is provided `publicKey` is expected to be a string; otherwise a [`Buffer`][], `TypedArray`, or `DataView` is expected. Note that there is not normally a reason to call this method because `ECDH` @@ -925,12 +923,12 @@ console.log(hash.digest('hex')); -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Calculates the digest of all of the data passed to be hashed (using the -[`hash.update()`][] method). The `encoding` can be `'hex'`, `'latin1'` or -`'base64'`. If `encoding` is provided a string will be returned; otherwise +[`hash.update()`][] method). +If `encoding` is provided a string will be returned; otherwise a [`Buffer`][] is returned. The `Hash` object can not be used again after `hash.digest()` method has been @@ -945,11 +943,11 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the hash content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `encoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. @@ -1017,11 +1015,11 @@ console.log(hmac.digest('hex')); -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Calculates the HMAC digest of all of the data passed using [`hmac.update()`][]. -The `encoding` can be `'hex'`, `'latin1'` or `'base64'`. If `encoding` is +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned; The `Hmac` object can not be used again after `hmac.digest()` has been @@ -1036,11 +1034,11 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the `Hmac` content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `encoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. @@ -1110,7 +1108,7 @@ console.log(sign.sign(privateKey, 'hex')); // Prints: the calculated signature ``` -### sign.sign(privateKey[, outputFormat]) +### sign.sign(privateKey[, outputEncoding]) * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the `Sign` content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `encoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. @@ -1227,17 +1224,17 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the `Verify` content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `inputEncoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. This can be called many times with new data as it is streamed. -### verify.verify(object, signature[, signatureFormat]) +### verify.verify(object, signature[, signatureEncoding]) * `object` {string | Object} * `signature` {string | Buffer | TypedArray | DataView} -* `signatureFormat` {string} +* `signatureEncoding` {string} The [encoding][] of the `signature` string. * Returns: {boolean} `true` or `false` depending on the validity of the signature for the data and public key. @@ -1270,8 +1267,8 @@ or an object with one or more of the following properties: determined automatically. The `signature` argument is the previously calculated signature for the data, in -the `signatureFormat` which can be `'latin1'`, `'hex'` or `'base64'`. -If a `signatureFormat` is specified, the `signature` is expected to be a +the `signatureEncoding`. +If a `signatureEncoding` is specified, the `signature` is expected to be a string; otherwise `signature` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -1382,6 +1379,9 @@ Adversaries][] for details. * `prime` {string | Buffer | TypedArray | DataView} -* `primeEncoding` {string} +* `primeEncoding` {string} The [encoding][] of the `prime` string. * `generator` {number | string | Buffer | TypedArray | DataView} **Default:** `2` -* `generatorEncoding` {string} +* `generatorEncoding` {string} The [encoding][] of the `generator` string. +* Returns: {DiffieHellman} Creates a `DiffieHellman` key exchange object using the supplied `prime` and an optional specific `generator`. @@ -1540,9 +1544,6 @@ optional specific `generator`. The `generator` argument can be a number, string, or [`Buffer`][]. If `generator` is not specified, the value `2` is used. -The `primeEncoding` and `generatorEncoding` arguments can be `'latin1'`, -`'hex'`, or `'base64'`. - If `primeEncoding` is specified, `prime` is expected to be a string; otherwise a [`Buffer`][], `TypedArray`, or `DataView` is expected. @@ -1556,6 +1557,7 @@ added: v0.5.0 * `primeLength` {number} * `generator` {number | string | Buffer | TypedArray | DataView} **Default:** `2` +* Returns: {DiffieHellman} Creates a `DiffieHellman` key exchange object and generates a prime of `primeLength` bits using an optional specific numeric `generator`. @@ -1566,6 +1568,7 @@ If `generator` is not specified, the value `2` is used. added: v0.11.14 --> * `curveName` {string} +* Returns: {ECDH} Creates an Elliptic Curve Diffie-Hellman (`ECDH`) key exchange object using a predefined curve specified by the `curveName` string. Use @@ -1818,7 +1821,7 @@ console.log(curves); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...] added: v0.7.5 --> * `groupName` {string} -* Returns: {Object} +* Returns: {DiffieHellman} Creates a predefined `DiffieHellman` key exchange object. The supported groups are: `'modp1'`, `'modp2'`, `'modp5'` (defined in @@ -2885,13 +2888,13 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. [`hash.update()`]: #crypto_hash_update_data_inputencoding [`hmac.digest()`]: #crypto_hmac_digest_encoding [`hmac.update()`]: #crypto_hmac_update_data_inputencoding -[`sign.sign()`]: #crypto_sign_sign_privatekey_outputformat +[`sign.sign()`]: #crypto_sign_sign_privatekey_outputencoding [`sign.update()`]: #crypto_sign_update_data_inputencoding [`stream.transform` options]: stream.html#stream_new_stream_transform_options [`stream.Writable` options]: stream.html#stream_constructor_new_stream_writable_options [`util.promisify()`]: util.html#util_util_promisify_original [`verify.update()`]: #crypto_verify_update_data_inputencoding -[`verify.verify()`]: #crypto_verify_verify_object_signature_signatureformat +[`verify.verify()`]: #crypto_verify_verify_object_signature_signatureencoding [AEAD algorithms]: https://en.wikipedia.org/wiki/Authenticated_encryption [Caveats]: #crypto_support_for_weak_or_compromised_algorithms [CCM mode]: #crypto_ccm_mode @@ -2907,6 +2910,7 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. [RFC 3526]: https://www.rfc-editor.org/rfc/rfc3526.txt [RFC 3610]: https://www.rfc-editor.org/rfc/rfc3610.txt [RFC 4055]: https://www.rfc-editor.org/rfc/rfc4055.txt +[encoding]: buffer.html#buffer_buffers_and_character_encodings [initialization vector]: https://en.wikipedia.org/wiki/Initialization_vector [scrypt]: https://en.wikipedia.org/wiki/Scrypt [stream-writable-write]: stream.html#stream_writable_write_chunk_encoding_callback diff --git a/doc/api/errors.md b/doc/api/errors.md index bdabc48a7ddd72..500fb7801b61fd 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -260,7 +260,10 @@ not capture any frames. * {string} The `error.code` property is a string label that identifies the kind of error. -See [Node.js Error Codes][] for details about specific codes. +`error.code` is the most stable way to identify an error. It will only change +between major versions of Node.js. In contrast, `error.message` strings may +change between any versions of Node.js. See [Node.js Error Codes][] for details +about specific codes. ### error.message @@ -441,86 +444,94 @@ checks or `abort()` calls in the C++ layer. ## System Errors -System errors are generated when exceptions occur within the Node.js -runtime environment. Typically, these are operational errors that occur -when an application violates an operating system constraint such as attempting -to read a file that does not exist or when the user does not have sufficient -permissions. +Node.js generates system errors when exceptions occur within its runtime +environment. These usually occur when an application violates an operating +system constraint. For example, a system error will occur if an application +attempts to read a file that does not exist. -System errors are typically generated at the syscall level: an exhaustive list -of error codes and their meanings is available by running `man 2 intro` or -`man 3 errno` on most Unices; or [online][]. +System errors are usually generated at the syscall level. For a comprehensive +list, see the [`errno`(3) man page][]. -In Node.js, system errors are represented as augmented `Error` objects with -added properties. +In Node.js, system errors are `Error` objects with extra properties. ### Class: SystemError -#### error.info +* `address` {string} If present, the address to which a network connection + failed +* `code` {string} The string error code +* `dest` {string} If present, the file path destination when reporting a file + system error +* `errno` {number|string} The system-provided error number +* `info` {Object} If present, extra details about the error condition +* `message` {string} A system-provided human-readable description of the error +* `path` {string} If present, the file path when reporting a file system error +* `port` {number} If present, the network connection port that is not available +* `syscall` {string} The name of the system call that triggered the error -`SystemError` instances may have an additional `info` property whose -value is an object with additional details about the error conditions. +#### error.address -The following properties are provided: +* {string} -* `code` {string} The string error code -* `errno` {number} The system-provided error number -* `message` {string} A system-provided human readable description of the error -* `syscall` {string} The name of the system call that triggered the error -* `path` {Buffer} When reporting a file system error, the `path` will identify - the file path. -* `dest` {Buffer} When reporting a file system error, the `dest` will identify - the file path destination (if any). +If present, `error.address` is a string describing the address to which a +network connection failed. #### error.code * {string} -The `error.code` property is a string representing the error code, which is -typically `E` followed by a sequence of capital letters. +The `error.code` property is a string representing the error code. + +#### error.dest + +* {string} + +If present, `error.dest` is the file path destination when reporting a file +system error. #### error.errno * {string|number} -The `error.errno` property is a number or a string. -The number is a **negative** value which corresponds to the error code defined -in [`libuv Error handling`]. See `uv-errno.h` header file -(`deps/uv/include/uv-errno.h` in the Node.js source tree) for details. In case +The `error.errno` property is a number or a string. If it is a number, it is a +negative value which corresponds to the error code defined in +[`libuv Error handling`]. See the libuv `errno.h` header file +(`deps/uv/include/uv/errno.h` in the Node.js source tree) for details. In case of a string, it is the same as `error.code`. -#### error.syscall +#### error.info -* {string} +* {Object} -The `error.syscall` property is a string describing the [syscall][] that failed. +If present, `error.info` is an object with details about the error condition. -#### error.path +#### error.message * {string} -When present (e.g. in `fs` or `child_process`), the `error.path` property is a -string containing a relevant invalid pathname. +`error.message` is a system-provided human-readable description of the error. -#### error.address +#### error.path * {string} -When present (e.g. in `net` or `dgram`), the `error.address` property is a -string describing the address to which the connection failed. +If present, `error.path` is a string containing a relevant invalid pathname. #### error.port * {number} -When present (e.g. in `net` or `dgram`), the `error.port` property is a number -representing the connection's port that is not available. +If present, `error.port` is the network connection port that is not available. + +#### error.syscall + +* {string} + +The `error.syscall` property is a string describing the [syscall][] that failed. ### Common System Errors -This list is **not exhaustive**, but enumerates many of the common system -errors encountered when writing a Node.js program. An exhaustive list may be -found [here][online]. +This is a list of system errors commonly-encountered when writing a Node.js +program. For a comprehensive list, see the [`errno`(3) man page][]. - `EACCES` (Permission denied): An attempt was made to access a file in a way forbidden by its file access permissions. @@ -613,6 +624,19 @@ An attempt was made to register something that is not a function as an The type of an asynchronous resource was invalid. Note that users are also able to define their own types if using the public embedder API. + +### ERR_BUFFER_CONTEXT_NOT_AVAILABLE + +An attempt was made to create a Node.js `Buffer` instance from addon or embedder +code, while in a JS engine Context that is not associated with a Node.js +instance. The data passed to the `Buffer` method will have been released +by the time the method returns. + +When encountering this error, a possible alternative to creating a `Buffer` +instance is to create a normal `Uint8Array`, which only differs in the +prototype of the resulting object. `Uint8Array`s are generally accepted in all +Node.js core APIs where `Buffer`s are; they are available in all Contexts. + ### ERR_BUFFER_OUT_OF_BOUNDS @@ -2113,6 +2137,7 @@ such as `process.stdout.on('data')`. [`crypto.scryptSync()`]: crypto.html#crypto_crypto_scryptsync_password_salt_keylen_options [`crypto.timingSafeEqual()`]: crypto.html#crypto_crypto_timingsafeequal_a_b [`dgram.createSocket()`]: dgram.html#dgram_dgram_createsocket_options_callback +[`errno`(3) man page]: http://man7.org/linux/man-pages/man3/errno.3.html [`fs.readFileSync`]: fs.html#fs_fs_readfilesync_path_options [`fs.readdir`]: fs.html#fs_fs_readdir_path_options_callback [`fs.symlink()`]: fs.html#fs_fs_symlink_target_path_type_callback @@ -2134,7 +2159,7 @@ such as `process.stdout.on('data')`. [`require()`]: modules.html#modules_require [`server.close()`]: net.html#net_server_close_callback [`server.listen()`]: net.html#net_server_listen -[`sign.sign()`]: crypto.html#crypto_sign_sign_privatekey_outputformat +[`sign.sign()`]: crypto.html#crypto_sign_sign_privatekey_outputencoding [`stream.pipe()`]: stream.html#stream_readable_pipe_destination_options [`stream.push()`]: stream.html#stream_readable_push_chunk_encoding [`stream.unshift()`]: stream.html#stream_readable_unshift_chunk @@ -2152,7 +2177,6 @@ such as `process.stdout.on('data')`. [domains]: domain.html [event emitter-based]: events.html#events_class_eventemitter [file descriptors]: https://en.wikipedia.org/wiki/File_descriptor -[online]: http://man7.org/linux/man-pages/man3/errno.3.html [stream-based]: stream.html [syscall]: http://man7.org/linux/man-pages/man2/syscalls.2.html [try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch diff --git a/doc/api/fs.md b/doc/api/fs.md index 9de798c6ff7ca2..ce054230e6dba7 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -488,6 +488,16 @@ argument to `fs.createReadStream()`. If `path` is passed as a string, then `readStream.path` will be a string. If `path` is passed as a `Buffer`, then `readStream.path` will be a `Buffer`. +### readStream.pending + + +* {boolean} + +This property is `true` if the underlying file has not been opened yet, +i.e. before the `'ready'` event is emitted. + ## Class: fs.Stats + +* {boolean} + +This property is `true` if the underlying file has not been opened yet, +i.e. before the `'ready'` event is emitted. + ## fs.access(path[, mode], callback) * `path` {string|Buffer|URL} * `flags` {string|number} See [support of file system `flags`][]. + **Default:** `'r'`. * `mode` {integer} **Default:** `0o666` (readable and writable) * Returns: {Promise} diff --git a/doc/api/http.md b/doc/api/http.md index ff948cd9f5d6a6..1c6b5717e0049c 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -368,7 +368,7 @@ proxy.listen(1337, '127.0.0.1', () => { // make a request to a tunneling proxy const options = { port: 1337, - hostname: '127.0.0.1', + host: '127.0.0.1', method: 'CONNECT', path: 'www.google.com:80' }; @@ -415,7 +415,7 @@ event is emitted with a callback containing an object with a status code. const http = require('http'); const options = { - hostname: '127.0.0.1', + host: '127.0.0.1', port: 8080, path: '/length_request' }; @@ -502,7 +502,7 @@ srv.listen(1337, '127.0.0.1', () => { // make a request const options = { port: 1337, - hostname: '127.0.0.1', + host: '127.0.0.1', headers: { 'Connection': 'Upgrade', 'Upgrade': 'websocket' @@ -575,6 +575,17 @@ If `data` is specified, it is equivalent to calling If `callback` is specified, it will be called when the request stream is finished. +### request.finished + + +* {boolean} + +The `request.finished` property will be `true` if [`request.end()`][] +has been called. `request.end()` will automatically be called if the +request was initiated via [`http.get()`][]. + ### request.flushHeaders() +* {number} + +This property shows the number of characters currently buffered to be written. +See [`net.Socket.bufferSize`][] for details. + #### http2stream.close(code[, callback]) * `callback` {Function} +* Returns: {https.Server} See [`server.close()`][`http.close()`] from the HTTP module for details. @@ -49,6 +50,7 @@ added: v0.11.2 --> * `msecs` {number} **Default:** `120000` (2 minutes) * `callback` {Function} +* Returns: {https.Server} See [`http.Server#setTimeout()`][]. @@ -75,6 +77,7 @@ added: v0.3.4 * `options` {Object} Accepts `options` from [`tls.createServer()`][], [`tls.createSecureContext()`][] and [`http.createServer()`][]. * `requestListener` {Function} A listener to be added to the `'request'` event. +* Returns: {https.Server} ```js // curl -k https://localhost:8000/ diff --git a/doc/api/inspector.md b/doc/api/inspector.md index 02aa1ac1416acd..7406e36e73ce7e 100644 --- a/doc/api/inspector.md +++ b/doc/api/inspector.md @@ -43,6 +43,9 @@ started. If wait is `true`, will block until a client has connected to the inspect port and flow control has been passed to the debugger client. +See the [security warning](cli.html#inspector_security) regarding the `host` +parameter usage. + ## inspector.url() * Returns: {string|undefined} diff --git a/doc/api/net.md b/doc/api/net.md index eb48ab8d00c87f..b925245e7a338b 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -167,7 +167,7 @@ The number of concurrent connections on the server. This becomes `null` when sending a socket to a child with [`child_process.fork()`][]. To poll forks and get current number of active -connections use asynchronous [`server.getConnections()`][] instead. +connections, use asynchronous [`server.getConnections()`][] instead. ### server.getConnections(callback) -If `true` - +If `true`, [`socket.connect(options[, connectListener])`][`socket.connect(options)`] -was called and haven't yet finished. Will be set to `false` before emitting +was called and has not yet finished. Will be set to `true` before emitting `'connect'` event and/or calling [`socket.connect(options[, connectListener])`][`socket.connect(options)`]'s callback. @@ -724,6 +724,17 @@ The numeric representation of the local port. For example, `80` or `21`. Pauses the reading of data. That is, [`'data'`][] events will not be emitted. Useful to throttle back an upload. +### socket.pending + + +* {boolean} + +This is `true` if the socket is not connected yet, either because `.connect()` +has not yet been called or because it is still in the process of connecting +(see [`socket.connecting`][]). + ### socket.ref() * `options` {Object} * `connectListener` {Function} + Alias to [`net.createConnection(options[, connectListener])`][`net.createConnection(options)`]. @@ -1028,10 +1040,6 @@ then returns the `net.Socket` that starts the connection. -* `options` {Object} -* `connectionListener` {Function} - -Creates a new TCP or [IPC][] server. * `options` {Object} * `allowHalfOpen` {boolean} Indicates whether half-opened TCP @@ -1042,6 +1050,8 @@ Creates a new TCP or [IPC][] server. [`'connection'`][] event. * Returns: {net.Server} +Creates a new TCP or [IPC][] server. + If `allowHalfOpen` is set to `true`, when the other end of the socket sends a FIN packet, the server will only send a FIN packet back when [`socket.end()`][] is explicitly called, until then the connection is @@ -1168,6 +1178,7 @@ Returns `true` if input is a version 6 IP address, otherwise returns `false`. [`socket.connect(options)`]: #net_socket_connect_options_connectlistener [`socket.connect(path)`]: #net_socket_connect_path_connectlistener [`socket.connect(port, host)`]: #net_socket_connect_port_host_connectlistener +[`socket.connecting`]: #net_socket_connecting [`socket.destroy()`]: #net_socket_destroy_exception [`socket.end()`]: #net_socket_end_data_encoding_callback [`socket.pause()`]: #net_socket_pause diff --git a/doc/api/path.md b/doc/api/path.md index a5cd310690e5cc..4cfa4fa8ae37d5 100644 --- a/doc/api/path.md +++ b/doc/api/path.md @@ -288,7 +288,7 @@ added: v0.1.16 * Returns: {string} The `path.join()` method joins all given `path` segments together using the -platform specific separator as a delimiter, then normalizes the resulting path. +platform-specific separator as a delimiter, then normalizes the resulting path. Zero-length `path` segments are ignored. If the joined path string is a zero-length string then `'.'` will be returned, representing the current @@ -317,7 +317,7 @@ The `path.normalize()` method normalizes the given `path`, resolving `'..'` and When multiple, sequential path segment separation characters are found (e.g. `/` on POSIX and either `\` or `/` on Windows), they are replaced by a single -instance of the platform specific path segment separator (`/` on POSIX and +instance of the platform-specific path segment separator (`/` on POSIX and `\` on Windows). Trailing separators are preserved. If the `path` is a zero-length string, `'.'` is returned, representing the @@ -543,7 +543,7 @@ On Windows systems only, returns an equivalent [namespace-prefixed path][] for the given `path`. If `path` is not a string, `path` will be returned without modifications. -This method is meaningful only on Windows system. On posix systems, the +This method is meaningful only on Windows system. On POSIX systems, the method is non-operational and always returns `path` without modifications. ## path.win32 diff --git a/doc/api/process.md b/doc/api/process.md index 3907271bbfa26c..d555e54caeeac9 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -429,7 +429,7 @@ process.on('SIGTERM', handle); removed (Node.js will no longer exit). * `'SIGPIPE'` is ignored by default. It can have a listener installed. * `'SIGHUP'` is generated on Windows when the console window is closed, and on - other platforms under various similar conditions, see signal(7). It can have a + other platforms under various similar conditions. See signal(7). It can have a listener installed, however Node.js will be unconditionally terminated by Windows about 10 seconds later. On non-Windows platforms, the default behavior of `SIGHUP` is to terminate Node.js, but once a listener has been @@ -1382,7 +1382,7 @@ process.kill(process.pid, 'SIGHUP'); ``` When `SIGUSR1` is received by a Node.js process, Node.js will start the -debugger, see [Signal Events][]. +debugger. See [Signal Events][]. ## process.mainModule * `options` {Object} @@ -1521,6 +1526,8 @@ changes: [`stream._destroy()`][writable-_destroy] method. * `final` {Function} Implementation for the [`stream._final()`][stream-_final] method. + * `autoDestroy` {boolean} Whether this stream should automatically call + `.destroy()` on itself after ending. **Default:** `false`. ```js const { Writable } = require('stream'); @@ -1756,6 +1763,14 @@ Custom `Readable` streams *must* call the `new stream.Readable([options])` constructor and implement the `readable._read()` method. #### new stream.Readable([options]) + * `options` {Object} * `highWaterMark` {number} The maximum [number of bytes][hwm-gotcha] to store @@ -1770,6 +1785,8 @@ constructor and implement the `readable._read()` method. method. * `destroy` {Function} Implementation for the [`stream._destroy()`][readable-_destroy] method. + * `autoDestroy` {boolean} Whether this stream should automatically call + `.destroy()` on itself after ending. **Default:** `false`. ```js const { Readable } = require('stream'); @@ -1875,7 +1892,7 @@ changes: any JavaScript value. * `encoding` {string} Encoding of string chunks. Must be a valid `Buffer` encoding, such as `'utf8'` or `'ascii'`. -* Returns: {boolean} `true` if additional chunks of data may continued to be +* Returns: {boolean} `true` if additional chunks of data may continue to be pushed; `false` otherwise. When `chunk` is a `Buffer`, `Uint8Array` or `string`, the `chunk` of data will @@ -2288,7 +2305,7 @@ The `callback` function must be called only when the current chunk is completely consumed. The first argument passed to the `callback` must be an `Error` object if an error occurred while processing the input or `null` otherwise. If a second argument is passed to the `callback`, it will be forwarded on to the -`readable.push()` method. In other words the following are equivalent: +`readable.push()` method. In other words, the following are equivalent: ```js transform.prototype._transform = function(data, encoding, callback) { @@ -2335,7 +2352,7 @@ less powerful and less useful. guaranteed. This meant that it was still necessary to be prepared to receive [`'data'`][] events *even when the stream was in a paused state*. -In Node.js 0.10, the [`Readable`][] class was added. For backwards +In Node.js 0.10, the [`Readable`][] class was added. For backward compatibility with older Node.js programs, `Readable` streams switch into "flowing mode" when a [`'data'`][] event handler is added, or when the [`stream.resume()`][stream-resume] method is called. The effect is that, even diff --git a/doc/api/tls.md b/doc/api/tls.md index 8700839c400b38..392052986e3208 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -378,6 +378,7 @@ added: v0.3.2 * `callback` {Function} A listener callback that will be registered to listen for the server instance's `'close'` event. +* Returns: {tls.Server} The `server.close()` method stops the server from accepting new connections. @@ -565,6 +566,22 @@ added: v0.11.4 Always returns `true`. This may be used to distinguish TLS sockets from regular `net.Socket` instances. +### tlsSocket.getCertificate() + + +* Returns: {Object} + +Returns an object representing the local certificate. The returned object has +some properties corresponding to the fields of the certificate. + +See [`tls.TLSSocket.getPeerCertificate()`][] for an example of the certificate +structure. + +If there is no local certificate, an empty object will be returned. If the +socket has been destroyed, `null` will be returned. + ### tlsSocket.getCipher() -* `hostname` {string} The hostname to verify the certificate against +* `hostname` {string} The host name or IP address to verify the certificate + against. * `cert` {Object} An object representing the peer's certificate. The returned object has some properties corresponding to the fields of the certificate. * Returns: {Error|undefined} Verifies the certificate `cert` is issued to `hostname`. -Returns {Error} object, populating it with the reason, host, and cert on +Returns {Error} object, populating it with `reason`, `host`, and `cert` on failure. On success, returns {undefined}. This function can be overwritten by providing alternative function as part of @@ -901,11 +920,15 @@ changes: An array of strings, `Buffer`s or `TypedArray`s or `DataView`s, or a single `Buffer` or `TypedArray` or `DataView` containing the supported ALPN protocols. `Buffer`s should have the format `[len][name][len][name]...` - e.g. `0x05hello0x05world`, where the first byte is the length of the next - protocol name. Passing an array is usually much simpler, e.g. - `['hello', 'world']`. + e.g. `'\x08http/1.1\x08http/1.0'`, where the `len` byte is the length of the + next protocol name. Passing an array is usually much simpler, e.g. + `['http/1.1', 'http/1.0']`. Protocols earlier in the list have higher + preference than those later. * `servername`: {string} Server name for the SNI (Server Name Indication) TLS - extension. It must be a host name, and not an IP address. + extension. It is the name of the host being connected to, and must be a host + name, and not an IP address. It can be used by a multi-homed server to + choose the correct certificate to present to the client, see the + `SNICallback` option to [`tls.createServer()`][]. * `checkServerIdentity(servername, cert)` {Function} A callback function to be used (instead of the builtin `tls.checkServerIdentity()` function) when checking the server's hostname (or the provided `servername` when @@ -926,55 +949,31 @@ changes: * ...: [`tls.createSecureContext()`][] options that are used if the `secureContext` option is missing, otherwise they are ignored. * `callback` {Function} +* Returns: {tls.TLSSocket} The `callback` function, if specified, will be added as a listener for the [`'secureConnect'`][] event. `tls.connect()` returns a [`tls.TLSSocket`][] object. -Here is an example of a client of echo server as described in +The following illustrates a client for the echo server example from [`tls.createServer()`][]: ```js -// This example assumes that you have created an echo server that is -// listening on port 8000. +// Assumes an echo server that is listening on port 8000. const tls = require('tls'); const fs = require('fs'); const options = { - // Necessary only if using the client certificate authentication + // Necessary only if the server requires client certificate authentication. key: fs.readFileSync('client-key.pem'), cert: fs.readFileSync('client-cert.pem'), - // Necessary only if the server uses the self-signed certificate - ca: [ fs.readFileSync('server-cert.pem') ] -}; + // Necessary only if the server uses a self-signed certificate. + ca: [ fs.readFileSync('server-cert.pem') ], -const socket = tls.connect(8000, options, () => { - console.log('client connected', - socket.authorized ? 'authorized' : 'unauthorized'); - process.stdin.pipe(socket); - process.stdin.resume(); -}); -socket.setEncoding('utf8'); -socket.on('data', (data) => { - console.log(data); -}); -socket.on('end', () => { - console.log('client ends'); -}); -``` - -Or - -```js -// This example assumes that you have created an echo server that is -// listening on port 8000. -const tls = require('tls'); -const fs = require('fs'); - -const options = { - pfx: fs.readFileSync('client.pfx') + // Necessary only if the server's cert isn't for "localhost". + checkServerIdentity: () => { return null; }, }; const socket = tls.connect(8000, options, () => { @@ -988,7 +987,7 @@ socket.on('data', (data) => { console.log(data); }); socket.on('end', () => { - console.log('client ends'); + console.log('server ends connection'); }); ``` @@ -1000,6 +999,7 @@ added: v0.11.3 * `path` {string} Default value for `options.path`. * `options` {Object} See [`tls.connect()`][]. * `callback` {Function} See [`tls.connect()`][]. +* Returns: {tls.TLSSocket} Same as [`tls.connect()`][] except that `path` can be provided as an argument instead of an option. @@ -1015,6 +1015,7 @@ added: v0.11.3 * `host` {string} Default value for `options.host`. * `options` {Object} See [`tls.connect()`][]. * `callback` {Function} See [`tls.connect()`][]. +* Returns: {tls.TLSSocket} Same as [`tls.connect()`][] except that `port` and `host` can be provided as arguments instead of options. @@ -1191,6 +1192,7 @@ changes: * ...: Any [`tls.createSecureContext()`][] option can be provided. For servers, the identity options (`pfx` or `key`/`cert`) are usually required. * `secureConnectionListener` {Function} +* Returns: {tls.Server} Creates a new [`tls.Server`][]. The `secureConnectionListener`, if provided, is automatically set as a listener for the [`'secureConnection'`][] event. @@ -1208,10 +1210,10 @@ const options = { key: fs.readFileSync('server-key.pem'), cert: fs.readFileSync('server-cert.pem'), - // This is necessary only if using the client certificate authentication. + // This is necessary only if using client certificate authentication. requestCert: true, - // This is necessary only if the client uses the self-signed certificate. + // This is necessary only if the client uses a self-signed certificate. ca: [ fs.readFileSync('client-cert.pem') ] }; @@ -1227,36 +1229,8 @@ server.listen(8000, () => { }); ``` -Or - -```js -const tls = require('tls'); -const fs = require('fs'); - -const options = { - pfx: fs.readFileSync('server.pfx'), - - // This is necessary only if using the client certificate authentication. - requestCert: true, -}; - -const server = tls.createServer(options, (socket) => { - console.log('server connected', - socket.authorized ? 'authorized' : 'unauthorized'); - socket.write('welcome!\n'); - socket.setEncoding('utf8'); - socket.pipe(socket); -}); -server.listen(8000, () => { - console.log('server bound'); -}); -``` - -This server can be tested by connecting to it using `openssl s_client`: - -```sh -openssl s_client -connect 127.0.0.1:8000 -``` +The server can be tested by connecting to it using the example client from +[`tls.connect()`][]. ## tls.getCiphers() -* `buffer` {Buffer|Uint8Array} A buffer returned by [`serialize()`][]. +* `buffer` {Buffer|TypedArray|DataView} A buffer returned by [`serialize()`][]. Uses a [`DefaultDeserializer`][] with default options to read a JS value from a buffer. @@ -252,7 +252,7 @@ For use inside of a custom [`serializer._writeHostObject()`][]. #### serializer.writeRawBytes(buffer) -* `buffer` {Buffer|Uint8Array} +* `buffer` {Buffer|TypedArray|DataView} Write raw bytes into the serializer’s internal buffer. The deserializer will require a way to compute the length of the buffer. @@ -308,7 +308,7 @@ added: v8.0.0 #### new Deserializer(buffer) -* `buffer` {Buffer|Uint8Array} A buffer returned by +* `buffer` {Buffer|TypedArray|DataView} A buffer returned by [`serializer.releaseBuffer()`][]. Creates a new `Deserializer` object. diff --git a/doc/api/vm.md b/doc/api/vm.md index c4b7e3f9b381ed..1058e16d19dae7 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -246,9 +246,9 @@ in the ECMAScript specification. ### module.evaluate([options]) * `options` {Object} - * `timeout` {number} Specifies the number of milliseconds to evaluate + * `timeout` {integer} Specifies the number of milliseconds to evaluate before terminating execution. If execution is interrupted, an [`Error`][] - will be thrown. + will be thrown. This value must be a strictly positive integer. * `breakOnSigint` {boolean} If `true`, the execution will be terminated when `SIGINT` (Ctrl+C) is received. Existing handlers for the event that have been attached via `process.on('SIGINT')` will be disabled during script @@ -434,10 +434,10 @@ changes: in stack traces produced by this script. * `columnOffset` {number} Specifies the column number offset that is displayed in stack traces produced by this script. - * `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache - data for the supplied source. When supplied, the `cachedDataRejected` value - will be set to either `true` or `false` depending on acceptance of the data - by V8. + * `cachedData` {Buffer|TypedArray|DataView} Provides an optional `Buffer` or + `TypedArray`, or `DataView` with V8's code cache data for the supplied + source. When supplied, the `cachedDataRejected` value will be set to + either `true` or `false` depending on acceptance of the data by V8. * `produceCachedData` {boolean} When `true` and no `cachedData` is present, V8 will attempt to produce code cache data for `code`. Upon success, a `Buffer` with V8's code cache data will be produced and stored in the @@ -507,9 +507,9 @@ changes: * `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs while compiling the `code`, the line of code causing the error is attached to the stack trace. - * `timeout` {number} Specifies the number of milliseconds to execute `code` + * `timeout` {integer} Specifies the number of milliseconds to execute `code` before terminating execution. If execution is terminated, an [`Error`][] - will be thrown. + will be thrown. This value must be a strictly positive integer. * `breakOnSigint`: if `true`, the execution will be terminated when `SIGINT` (Ctrl+C) is received. Existing handlers for the event that have been attached via `process.on('SIGINT')` will be disabled @@ -570,9 +570,9 @@ changes: * `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs while compiling the `code`, the line of code causing the error is attached to the stack trace. - * `timeout` {number} Specifies the number of milliseconds to execute `code` + * `timeout` {integer} Specifies the number of milliseconds to execute `code` before terminating execution. If execution is terminated, an [`Error`][] - will be thrown. + will be thrown. This value must be a strictly positive integer. * `contextName` {string} Human-readable name of the newly created context. **Default:** `'VM Context i'`, where `i` is an ascending numerical index of the created context. @@ -628,9 +628,9 @@ added: v0.3.1 * `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs while compiling the `code`, the line of code causing the error is attached to the stack trace. - * `timeout` {number} Specifies the number of milliseconds to execute `code` + * `timeout` {integer} Specifies the number of milliseconds to execute `code` before terminating execution. If execution is terminated, an [`Error`][] - will be thrown. + will be thrown. This value must be a strictly positive integer. Runs the compiled code contained by the `vm.Script` within the context of the current `global` object. Running code does not have access to local scope, but @@ -669,8 +669,9 @@ added: v10.10.0 in stack traces produced by this script. **Default:** `0`. * `columnOffset` {number} Specifies the column number offset that is displayed in stack traces produced by this script. **Default:** `0`. - * `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache - data for the supplied source. + * `cachedData` {Buffer|TypedArray|DataView} Provides an optional `Buffer` or + `TypedArray`, or `DataView` with V8's code cache data for the supplied + source. * `produceCachedData` {boolean} Specifies whether to produce new cache data. **Default:** `false`. * `parsingContext` {Object} The [contextified][] sandbox in which the said @@ -775,9 +776,9 @@ Returns `true` if the given `sandbox` object has been [contextified][] using * `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs while compiling the `code`, the line of code causing the error is attached to the stack trace. - * `timeout` {number} Specifies the number of milliseconds to execute `code` + * `timeout` {integer} Specifies the number of milliseconds to execute `code` before terminating execution. If execution is terminated, an [`Error`][] - will be thrown. + will be thrown. This value must be a strictly positive integer. The `vm.runInContext()` method compiles `code`, runs it within the context of the `contextifiedSandbox`, then returns the result. Running code does not have @@ -822,9 +823,9 @@ added: v0.3.1 * `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs while compiling the `code`, the line of code causing the error is attached to the stack trace. - * `timeout` {number} Specifies the number of milliseconds to execute `code` + * `timeout` {integer} Specifies the number of milliseconds to execute `code` before terminating execution. If execution is terminated, an [`Error`][] - will be thrown. + will be thrown. This value must be a strictly positive integer. * `contextName` {string} Human-readable name of the newly created context. **Default:** `'VM Context i'`, where `i` is an ascending numerical index of the created context. @@ -876,9 +877,9 @@ added: v0.3.1 * `displayErrors` {boolean} When `true`, if an [`Error`][] error occurs while compiling the `code`, the line of code causing the error is attached to the stack trace. - * `timeout` {number} Specifies the number of milliseconds to execute `code` + * `timeout` {integer} Specifies the number of milliseconds to execute `code` before terminating execution. If execution is terminated, an [`Error`][] - will be thrown. + will be thrown. This value must be a strictly positive integer. `vm.runInThisContext()` compiles `code`, runs it within the context of the current `global` and returns the result. Running code does not have access to diff --git a/doc/changelogs/CHANGELOG_V11.md b/doc/changelogs/CHANGELOG_V11.md index e16ea1b0ad2543..afd930d13b476b 100644 --- a/doc/changelogs/CHANGELOG_V11.md +++ b/doc/changelogs/CHANGELOG_V11.md @@ -9,6 +9,7 @@
+11.2.0
11.1.0
11.0.0
adds tens of seconds of execution time for + // large test suites (tens of thousands of tests). + function escape_html(s) + { + return s.replace(/\&/g, "&") + .replace(/" + + "
ResultTest NameAssertionMessage
' + + escape_html(status_text[tests[i].status]) + + "" + + escape_html(tests[i].name) + + "" + + (assertions ? escape_html(get_assertion(tests[i])) + "" : "") + + escape_html(tests[i].message ? tests[i].message : " ") + + (tests[i].stack ? "
" +
+                 escape_html(tests[i].stack) +
+                 "
": "") + + "
"; + try { + log.lastChild.innerHTML = html; + } catch (e) { + log.appendChild(document.createElementNS(xhtml_ns, "p")) + .textContent = "Setting innerHTML for the log threw an exception."; + log.appendChild(document.createElementNS(xhtml_ns, "pre")) + .textContent = html; + } + }; + + /* + * Template code + * + * A template is just a JavaScript structure. An element is represented as: + * + * [tag_name, {attr_name:attr_value}, child1, child2] + * + * the children can either be strings (which act like text nodes), other templates or + * functions (see below) + * + * A text node is represented as + * + * ["{text}", value] + * + * String values have a simple substitution syntax; ${foo} represents a variable foo. + * + * It is possible to embed logic in templates by using a function in a place where a + * node would usually go. The function must either return part of a template or null. + * + * In cases where a set of nodes are required as output rather than a single node + * with children it is possible to just use a list + * [node1, node2, node3] + * + * Usage: + * + * render(template, substitutions) - take a template and an object mapping + * variable names to parameters and return either a DOM node or a list of DOM nodes + * + * substitute(template, substitutions) - take a template and variable mapping object, + * make the variable substitutions and return the substituted template + * + */ + + function is_single_node(template) + { + return typeof template[0] === "string"; + } + + function substitute(template, substitutions) + { + if (typeof template === "function") { + var replacement = template(substitutions); + if (!replacement) { + return null; + } + + return substitute(replacement, substitutions); + } + + if (is_single_node(template)) { + return substitute_single(template, substitutions); + } + + return filter(map(template, function(x) { + return substitute(x, substitutions); + }), function(x) {return x !== null;}); + } + + function substitute_single(template, substitutions) + { + var substitution_re = /\$\{([^ }]*)\}/g; + + function do_substitution(input) { + var components = input.split(substitution_re); + var rv = []; + for (var i = 0; i < components.length; i += 2) { + rv.push(components[i]); + if (components[i + 1]) { + rv.push(String(substitutions[components[i + 1]])); + } + } + return rv; + } + + function substitute_attrs(attrs, rv) + { + rv[1] = {}; + for (var name in template[1]) { + if (attrs.hasOwnProperty(name)) { + var new_name = do_substitution(name).join(""); + var new_value = do_substitution(attrs[name]).join(""); + rv[1][new_name] = new_value; + } + } + } + + function substitute_children(children, rv) + { + for (var i = 0; i < children.length; i++) { + if (children[i] instanceof Object) { + var replacement = substitute(children[i], substitutions); + if (replacement !== null) { + if (is_single_node(replacement)) { + rv.push(replacement); + } else { + extend(rv, replacement); + } + } + } else { + extend(rv, do_substitution(String(children[i]))); + } + } + return rv; + } + + var rv = []; + rv.push(do_substitution(String(template[0])).join("")); + + if (template[0] === "{text}") { + substitute_children(template.slice(1), rv); + } else { + substitute_attrs(template[1], rv); + substitute_children(template.slice(2), rv); + } + + return rv; + } + + function make_dom_single(template, doc) + { + var output_document = doc || document; + var element; + if (template[0] === "{text}") { + element = output_document.createTextNode(""); + for (var i = 1; i < template.length; i++) { + element.data += template[i]; + } + } else { + element = output_document.createElementNS(xhtml_ns, template[0]); + for (var name in template[1]) { + if (template[1].hasOwnProperty(name)) { + element.setAttribute(name, template[1][name]); + } + } + for (var i = 2; i < template.length; i++) { + if (template[i] instanceof Object) { + var sub_element = make_dom(template[i]); + element.appendChild(sub_element); + } else { + var text_node = output_document.createTextNode(template[i]); + element.appendChild(text_node); + } + } + } + + return element; + } + + function make_dom(template, substitutions, output_document) + { + if (is_single_node(template)) { + return make_dom_single(template, output_document); + } + + return map(template, function(x) { + return make_dom_single(x, output_document); + }); + } + + function render(template, substitutions, output_document) + { + return make_dom(substitute(template, substitutions), output_document); + } + + /* + * Utility functions + */ + function assert(expected_true, function_name, description, error, substitutions) + { + if (tests.tests.length === 0) { + tests.set_file_is_test(); + } + if (expected_true !== true) { + var msg = make_message(function_name, description, + error, substitutions); + throw new AssertionError(msg); + } + } + + function AssertionError(message) + { + this.message = message; + this.stack = this.get_stack(); + } + expose(AssertionError, "AssertionError"); + + AssertionError.prototype = Object.create(Error.prototype); + + AssertionError.prototype.get_stack = function() { + var stack = new Error().stack; + // IE11 does not initialize 'Error.stack' until the object is thrown. + if (!stack) { + try { + throw new Error(); + } catch (e) { + stack = e.stack; + } + } + + // 'Error.stack' is not supported in all browsers/versions + if (!stack) { + return "(Stack trace unavailable)"; + } + + var lines = stack.split("\n"); + + // Create a pattern to match stack frames originating within testharness.js. These include the + // script URL, followed by the line/col (e.g., '/resources/testharness.js:120:21'). + // Escape the URL per http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + // in case it contains RegExp characters. + var script_url = get_script_url(); + var re_text = script_url ? script_url.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') : "\\btestharness.js"; + var re = new RegExp(re_text + ":\\d+:\\d+"); + + // Some browsers include a preamble that specifies the type of the error object. Skip this by + // advancing until we find the first stack frame originating from testharness.js. + var i = 0; + while (!re.test(lines[i]) && i < lines.length) { + i++; + } + + // Then skip the top frames originating from testharness.js to begin the stack at the test code. + while (re.test(lines[i]) && i < lines.length) { + i++; + } + + // Paranoid check that we didn't skip all frames. If so, return the original stack unmodified. + if (i >= lines.length) { + return stack; + } + + return lines.slice(i).join("\n"); + } + + function make_message(function_name, description, error, substitutions) + { + for (var p in substitutions) { + if (substitutions.hasOwnProperty(p)) { + substitutions[p] = format_value(substitutions[p]); + } + } + var node_form = substitute(["{text}", "${function_name}: ${description}" + error], + merge({function_name:function_name, + description:(description?description + " ":"")}, + substitutions)); + return node_form.slice(1).join(""); + } + + function filter(array, callable, thisObj) { + var rv = []; + for (var i = 0; i < array.length; i++) { + if (array.hasOwnProperty(i)) { + var pass = callable.call(thisObj, array[i], i, array); + if (pass) { + rv.push(array[i]); + } + } + } + return rv; + } + + function map(array, callable, thisObj) + { + var rv = []; + rv.length = array.length; + for (var i = 0; i < array.length; i++) { + if (array.hasOwnProperty(i)) { + rv[i] = callable.call(thisObj, array[i], i, array); + } + } + return rv; + } + + function extend(array, items) + { + Array.prototype.push.apply(array, items); + } + + function forEach(array, callback, thisObj) + { + for (var i = 0; i < array.length; i++) { + if (array.hasOwnProperty(i)) { + callback.call(thisObj, array[i], i, array); + } + } + } + + /** + * Immediately invoke a "iteratee" function with a series of values in + * parallel and invoke a final "done" function when all of the "iteratee" + * invocations have signaled completion. + * + * If all callbacks complete synchronously (or if no callbacks are + * specified), the `done_callback` will be invoked synchronously. It is the + * responsibility of the caller to ensure asynchronicity in cases where + * that is desired. + * + * @param {array} value Zero or more values to use in the invocation of + * `iter_callback` + * @param {function} iter_callback A function that will be invoked once for + * each of the provided `values`. Two + * arguments will be available in each + * invocation: the value from `values` and + * a function that must be invoked to + * signal completion + * @param {function} done_callback A function that will be invoked after + * all operations initiated by the + * `iter_callback` function have signaled + * completion + */ + function all_async(values, iter_callback, done_callback) + { + var remaining = values.length; + + if (remaining === 0) { + done_callback(); + } + + forEach(values, + function(element) { + var invoked = false; + var elDone = function() { + if (invoked) { + return; + } + + invoked = true; + remaining -= 1; + + if (remaining === 0) { + done_callback(); + } + }; + + iter_callback(element, elDone); + }); + } + + function merge(a,b) + { + var rv = {}; + var p; + for (p in a) { + rv[p] = a[p]; + } + for (p in b) { + rv[p] = b[p]; + } + return rv; + } + + function expose(object, name) + { + var components = name.split("."); + var target = global_scope; + for (var i = 0; i < components.length - 1; i++) { + if (!(components[i] in target)) { + target[components[i]] = {}; + } + target = target[components[i]]; + } + target[components[components.length - 1]] = object; + } + + function is_same_origin(w) { + try { + 'random_prop' in w; + return true; + } catch (e) { + return false; + } + } + + /** Returns the 'src' URL of the first +``` + +## Documentation + +The API to WebIDL2 is trivial: you parse a string of WebIDL and it returns a syntax tree. + +### Parsing + +In Node, that happens with: + +```JS +var WebIDL2 = require("webidl2"); +var tree = WebIDL2.parse("string of WebIDL"); +``` + +In the browser: +```HTML + + +``` + +### Errors + +When there is a syntax error in the WebIDL, it throws an exception object with the following +properties: + +* `message`: the error message +* `line`: the line at which the error occurred. +* `input`: a short peek at the text at the point where the error happened +* `tokens`: the five tokens at the point of error, as understood by the tokeniser + (this is the same content as `input`, but seen from the tokeniser's point of view) + +The exception also has a `toString()` method that hopefully should produce a decent +error message. + +### AST (Abstract Syntax Tree) + +The `parse()` method returns a tree object representing the parse tree of the IDL. +Comment and white space are not represented in the AST. + +The root of this object is always an array of definitions (where definitions are +any of interfaces, dictionaries, callbacks, etc. — anything that can occur at the root +of the IDL). + +### IDL Type + +This structure is used in many other places (operation return types, argument types, etc.). +It captures a WebIDL type with a number of options. Types look like this and are typically +attached to a field called `idlType`: + +```JS +{ + "type": "attribute-type", + "generic": null, + "idlType": "unsigned short", + "nullable": false, + "union": false, + "extAttrs": [...] +} +``` + +Where the fields are as follows: + +* `type`: String indicating where this type is used. Can be `null` if not applicable. +* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null` + otherwise. +* `idlType`: Can be different things depending on context. In most cases, this will just + be a string with the type name. But the reason this field isn't called "typeName" is + because it can take more complex values. If the type is a union, then this contains an + array of the types it unites. If it is a generic type, it contains the IDL type + description for the type in the sequence, the eventual value of the promise, etc. +* `nullable`: Boolean indicating whether this is nullable or not. +* `union`: Boolean indicating whether this is a union type or not. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Interface + +Interfaces look like this: + +```JS +{ + "type": "interface", + "name": "Animal", + "partial": false, + "members": [...], + "inheritance": null, + "extAttrs": [...] +}, { + "type": "interface", + "name": "Human", + "partial": false, + "members": [...], + "inheritance": "Animal", + "extAttrs": [...] +} +``` + +The fields are as follows: + +* `type`: Always "interface". +* `name`: The name of the interface. +* `partial`: A boolean indicating whether it's a partial interface. +* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none. +* `inheritance`: A string giving the name of an interface this one inherits from, `null` otherwise. + **NOTE**: In v1 this was an array, but multiple inheritance is no longer supported so this didn't make + sense. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Interface mixins + +Interfaces mixins look like this: + +```JS +{ + "type": "interface mixin", + "name": "Animal", + "partial": false, + "members": [...], + "extAttrs": [...] +}, { + "type": "interface mixin", + "name": "Human", + "partial": false, + "members": [...], + "extAttrs": [...] +} +``` + +The fields are as follows: + +* `type`: Always "interface mixin". +* `name`: The name of the interface mixin. +* `partial`: A boolean indicating whether it's a partial interface mixin. +* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Namespace + +Namespaces look like this: + +```JS +{ + "type": "namespace", + "name": "Console", + "partial": false, + "members": [...], + "extAttrs": [...] +} +``` + +The fields are as follows: + +* `type`: Always "namespace". +* `name`: The name of the namespace. +* `partial`: A boolean indicating whether it's a partial namespace. +* `members`: An array of namespace members (attributes and operations). Empty if there are none. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Callback Interfaces + +These are captured by the same structure as [Interfaces](#interface) except that +their `type` field is "callback interface". + +### Callback + +A callback looks like this: + +```JS +{ + "type": "callback", + "name": "AsyncOperationCallback", + "idlType": { + "type": "return-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "void", + "extAttrs": [] + }, + "arguments": [...], + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "callback". +* `name`: The name of the callback. +* `idlType`: An [IDL Type](#idl-type) describing what the callback returns. +* `arguments`: A list of [arguments](#arguments), as in function paramters. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Dictionary + +A dictionary looks like this: + +```JS +{ + "type": "dictionary", + "name": "PaintOptions", + "partial": false, + "members": [{ + "type": "field", + "name": "fillPattern", + "required": false, + "idlType": { + "type": "dictionary-type", + "sequence": false, + "generic": null, + "nullable": true, + "union": false, + "idlType": "DOMString", + "extAttrs": [...] + }, + "extAttrs": [], + "default": { + "type": "string", + "value": "black" + } + }], + "inheritance": null, + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "dictionary". +* `name`: The dictionary name. +* `partial`: Boolean indicating whether it's a partial dictionary. +* `members`: An array of members (see below). +* `inheritance`: A string indicating which dictionary is being inherited from, `null` otherwise. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +All the members are fields as follows: + +* `type`: Always "field". +* `name`: The name of the field. +* `required`: Boolean indicating whether this is a [required](https://heycam.github.io/webidl/#required-dictionary-member) field. +* `idlType`: An [IDL Type](#idl-type) describing what field's type. +* `extAttrs`: A list of [extended attributes](#extended-attributes). +* `default`: A [default value](#default-and-const-values), absent if there is none. + +### Enum + +An enum looks like this: + +```JS +{ + "type": "enum", + "name": "MealType", + "values": [ + { "type": "string", "value": "rice" }, + { "type": "string", "value": "noodles" }, + { "type": "string", "value": "other" } + ], + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "enum". +* `name`: The enum's name. +* `values`: An array of values. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Typedef + +A typedef looks like this: + +```JS +{ + "type": "typedef", + "idlType": { + "type": "typedef-type", + "sequence": true, + "generic": "sequence", + "nullable": false, + "union": false, + "idlType": { + "type": "typedef-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "Point", + "extAttrs": [...] + }, + "extAttrs": [...] + }, + "name": "PointSequence", + "extAttrs": [] +} +``` + + +The fields are as follows: + +* `type`: Always "typedef". +* `name`: The typedef's name. +* `idlType`: An [IDL Type](#idl-type) describing what typedef's type. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Implements + +An implements definition looks like this: + +```JS +{ + "type": "implements", + "target": "Node", + "implements": "EventTarget", + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "implements". +* `target`: The interface that implements another. +* `implements`: The interface that is being implemented by the target. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Includes + +An includes definition looks like this: + +```JS +{ + "type": "includes", + "target": "Node", + "includes": "EventTarget", + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "includes". +* `target`: The interface that includes an interface mixin. +* `includes`: The interface mixin that is being included by the target. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Operation Member + +An operation looks like this: +```JS +{ + "type": "operation", + "getter": false, + "setter": false, + "deleter": false, + "static": false, + "stringifier": false, + "idlType": { + "type": "return-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "void", + "extAttrs": [] + }, + "name": "intersection", + "arguments": [{ + "optional": false, + "variadic": true, + "extAttrs": [], + "idlType": { + "type": "argument-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "long", + "extAttrs": [...] + }, + "name": "ints" + }], + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "operation". +* `getter`: True if a getter operation. +* `setter`: True if a setter operation. +* `deleter`: True if a deleter operation. +* `static`: True if a static operation. +* `stringifier`: True if a stringifier operation. +* `idlType`: An [IDL Type](#idl-type) of what the operation returns. If a stringifier, may be absent. +* `name`: The name of the operation. If a stringifier, may be `null`. +* `arguments`: An array of [arguments](#arguments) for the operation. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Attribute Member + +An attribute member looks like this: + +```JS +{ + "type": "attribute", + "static": false, + "stringifier": false, + "inherit": false, + "readonly": false, + "idlType": { + "type": "attribute-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "RegExp", + "extAttrs": [...] + }, + "name": "regexp", + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "attribute". +* `name`: The attribute's name. +* `static`: True if it's a static attribute. +* `stringifier`: True if it's a stringifier attribute. +* `inherit`: True if it's an inherit attribute. +* `readonly`: True if it's a read-only attribute. +* `idlType`: An [IDL Type](#idl-type) for the attribute. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Constant Member + +A constant member looks like this: + +```JS +{ + "type": "const", + "nullable": false, + "idlType": { + "type": "const-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "boolean" + "extAttrs": [] + }, + "name": "DEBUG", + "value": { + "type": "boolean", + "value": false + }, + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "const". +* `nullable`: Whether its type is nullable. +* `idlType`: An [IDL Type](#idl-type) of the constant that represents a simple type, the type name. +* `name`: The name of the constant. +* `value`: The constant value as described by [Const Values](#default-and-const-values) +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Arguments + +The arguments (e.g. for an operation) look like this: + +```JS +{ + "arguments": [{ + "optional": false, + "variadic": true, + "extAttrs": [], + "idlType": { + "type": "argument-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "long", + "extAttrs": [...] + }, + "name": "ints" + }] +} +``` + +The fields are as follows: + +* `optional`: True if the argument is optional. +* `variadic`: True if the argument is variadic. +* `idlType`: An [IDL Type](#idl-type) describing the type of the argument. +* `name`: The argument's name. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Extended Attributes + +Extended attributes are arrays of items that look like this: + +```JS +{ + "extAttrs": [{ + "name": "TreatNullAs", + "arguments": null, + "type": "extended-attribute", + "rhs": { + "type": "identifier", + "value": "EmptyString" + } + }] +} +``` + +The fields are as follows: + +* `name`: The extended attribute's name. +* `arguments`: If the extended attribute takes arguments (e.g. `[Foo()]`) or if + its right-hand side does (e.g. `[NamedConstructor=Name(DOMString blah)]`) they + are listed here. Note that an empty arguments list will produce an empty array, + whereas the lack thereof will yield a `null`. If there is an `rhs` field then + they are the right-hand side's arguments, otherwise they apply to the extended + attribute directly. +* `type`: Always `"extended-attribute"`. +* `rhs`: If there is a right-hand side, this will capture its `type` (which can be + "identifier" or "identifier-list") and its `value`. + +### Default and Const Values + +Dictionary fields and operation arguments can take default values, and constants take +values, all of which have the following fields: + +* `type`: One of string, number, boolean, null, Infinity, NaN, or sequence. + +For string, number, boolean, and sequence: + +* `value`: The value of the given type, as a string. For sequence, the only possible value is `[]`. + +For Infinity: + +* `negative`: Boolean indicating whether this is negative Infinity or not. + +### `iterable<>`, `legacyiterable<>`, `maplike<>`, `setlike<>` declarations + +These appear as members of interfaces that look like this: + +```JS +{ + "type": "maplike", // or "legacyiterable" / "iterable" / "setlike" + "idlType": /* One or two types */ , + "readonly": false, // only for maplike and setlike + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always one of "iterable", "legacyiterable", "maplike" or "setlike". +* `idlType`: An array with one or more [IDL Types](#idl-type) representing the declared type arguments. +* `readonly`: Whether the maplike or setlike is declared as read only. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + + +## Testing + +### Running + +The test runs with mocha and expect.js. Normally, running mocha in the root directory +should be enough once you're set up. + +### Coverage + +Current test coverage, as documented in `coverage.html`, is 95%. You can run your own +coverage analysis with: + +```Bash +jscoverage lib lib-cov +``` + +That will create the lib-cov directory with instrumented code; the test suite knows +to use that if needed. You can then run the tests with: + +```Bash +JSCOV=1 mocha --reporter html-cov > coverage.html +``` + +Note that I've been getting weirdly overescaped results from the html-cov reporter, +so you might wish to try this instead: + +```Bash +JSCOV=1 mocha --reporter html-cov | sed "s/<//g" | sed "s/"/\"/g" > coverage.html +``` +### Browser tests + +In order to test in the browser, get inside `test/web` and run `make-web-tests.js`. This +will generate a `browser-tests.html` file that you can open in a browser. As of this +writing tests pass in the latest Firefox, Chrome, Opera, and Safari. Testing on IE +and older versions will happen progressively. diff --git a/test/fixtures/wpt/resources/webidl2/checker/index.html b/test/fixtures/wpt/resources/webidl2/checker/index.html new file mode 100644 index 00000000000000..9897d8572f22a0 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/checker/index.html @@ -0,0 +1,55 @@ + + + +WebIDL 2 Checker + + + + + + +

WebIDL Checker

+

This is an online checker for WebIDL built on the webidl2.js project.

+

Enter your WebIDL to check below:

+ +
+ +

Validation results:

+ +

Parser output:

+ +
+Pretty Print + + diff --git a/test/fixtures/wpt/resources/webidl2/coverage.html b/test/fixtures/wpt/resources/webidl2/coverage.html new file mode 100644 index 00000000000000..46e7ed324ec2c8 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/coverage.html @@ -0,0 +1,341 @@ +Coverage +

Coverage

95%
572
548
24

webidl2.js

95%
572
548
24
LineHitsSource
1
2
31(function () {
41 var tokenise = function (str) {
547 var tokens = []
6 , re = {
7 "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/
8 , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/
9 , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/
10 , "string": /^"[^"]*"/
11 , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/
12 , "other": /^[^\t\n\r 0-9A-Z_a-z]/
13 }
14 , types = []
15 ;
16329 for (var k in re) types.push(k);
1747 while (str.length > 0) {
182914 var matched = false;
192914 for (var i = 0, n = types.length; i < n; i++) {
2013325 var type = types[i];
2113325 str = str.replace(re[type], function (tok) {
222914 tokens.push({ type: type, value: tok });
232914 matched = true;
242914 return "";
25 });
2616239 if (matched) break;
27 }
285828 if (matched) continue;
290 throw new Error("Token stream not progressing");
30 }
3147 return tokens;
32 };
33
341 var parse = function (tokens) {
3547 var line = 1;
3647 tokens = tokens.slice();
37
3847 var FLOAT = "float"
39 , INT = "integer"
40 , ID = "identifier"
41 , STR = "string"
42 , OTHER = "other"
43 ;
44
4547 var WebIDLParseError = function (str, line, input, tokens) {
460 this.message = str;
470 this.line = line;
480 this.input = input;
490 this.tokens = tokens;
50 };
5147 WebIDLParseError.prototype.toString = function () {
520 return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" +
53 JSON.stringify(this.tokens, null, 4);
54 };
55
5647 var error = function (str) {
570 var tok = "", numTokens = 0, maxTokens = 5;
580 while (numTokens < maxTokens && tokens.length > numTokens) {
590 tok += tokens[numTokens].value;
600 numTokens++;
61 }
620 throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5));
63 };
64
6547 var last_token = null;
66
6747 var consume = function (type, value) {
688778 if (!tokens.length || tokens[0].type !== type) return;
695470 if (typeof value === "undefined" || tokens[0].value === value) {
701738 last_token = tokens.shift();
711738 return last_token;
72 }
73 };
74
7547 var ws = function () {
766961 if (!tokens.length) return;
77 // console.log("tokens.length", tokens.length, tokens[0]);
786115 if (tokens[0].type === "whitespace") {
791172 var t = tokens.shift();
802294 t.value.replace(/\n/g, function (m) { line++; return m; });
811172 return t;
82 }
83 };
84
8547 var all_ws = function () {
865366 var t = { type: "whitespace", value: "" };
875366 while (true) {
886538 var w = ws();
8911904 if (!w) break;
901172 t.value += w.value;
91 }
926538 if (t.value.length > 0) return t;
93 };
94
9547 var integer_type = function () {
96273 var ret = "";
97273 all_ws();
98312 if (consume(ID, "unsigned")) ret = "unsigned ";
99273 all_ws();
100287 if (consume(ID, "short")) return ret + "short";
101259 if (consume(ID, "long")) {
10241 ret += "long";
10341 all_ws();
10443 if (consume(ID, "long")) return ret + " long";
10539 return ret;
106 }
107218 if (ret) error("Failed to parse integer type");
108 };
109
11047 var float_type = function () {
111218 var ret = "";
112218 all_ws();
113222 if (consume(ID, "unrestricted")) ret = "unrestricted ";
114218 all_ws();
115257 if (consume(ID, "float")) return ret + "float";
116182 if (consume(ID, "double")) return ret + "double";
117176 if (ret) error("Failed to parse float type");
118 };
119
12047 var primitive_type = function () {
121273 var num_type = integer_type() || float_type();
122370 if (num_type) return num_type;
123176 all_ws();
124186 if (consume(ID, "boolean")) return "boolean";
125167 if (consume(ID, "byte")) return "byte";
126168 if (consume(ID, "octet")) return "octet";
127 };
128
12947 var const_value = function () {
13017 if (consume(ID, "true")) return true;
13119 if (consume(ID, "false")) return false;
13217 if (consume(ID, "null")) return null;
13314 if (consume(ID, "Infinity")) return Infinity;
13413 if (consume(ID, "NaN")) return NaN;
13511 var ret = consume(FLOAT) || consume(INT);
13619 if (ret) return 1 * ret.value;
1373 var tok = consume(OTHER, "-");
1383 if (tok) {
1392 if (consume(ID, "Infinity")) return -Infinity;
1400 else tokens.unshift(tok);
141 }
142 };
143
14447 var type_suffix = function (obj) {
145249 while (true) {
146263 all_ws();
147263 if (consume(OTHER, "?")) {
14811 if (obj.nullable) error("Can't nullable more than once");
14911 obj.nullable = true;
150 }
151252 else if (consume(OTHER, "[")) {
1523 all_ws();
1533 consume(OTHER, "]") || error("Unterminated array type");
1545 if (!obj.array) obj.array = 1;
1551 else obj.array++;
156 }
157249 else return;
158 }
159 };
160
16147 var single_type = function () {
162261 var prim = primitive_type()
163 , ret = { sequence: false, nullable: false, array: false, union: false }
164 ;
165261 if (prim) {
16699 ret.idlType = prim;
167 }
168162 else if (consume(ID, "sequence")) {
1694 all_ws();
1704 if (!consume(OTHER, "<")) {
1710 ret.idlType = "sequence";
172 }
173 else {
1744 ret.sequence = true;
1754 ret.idlType = type() || error("Error parsing sequence type");
1764 all_ws();
1774 if (!consume(OTHER, ">")) error("Unterminated sequence");
1784 all_ws();
1795 if (consume(OTHER, "?")) ret.nullable = true;
1804 return ret;
181 }
182 }
183 else {
184158 var name = consume(ID);
185169 if (!name) return;
186147 ret.idlType = name.value;
187 }
188246 type_suffix(ret);
189246 if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable");
190246 return ret;
191 };
192
19347 var union_type = function () {
19411 all_ws();
19519 if (!consume(OTHER, "(")) return;
1963 var ret = { sequence: false, nullable: false, array: false, union: true, idlType: [] };
1973 var fst = type() || error("Union type with no content");
1983 ret.idlType.push(fst);
1993 while (true) {
2007 all_ws();
20110 if (!consume(ID, "or")) break;
2024 var typ = type() || error("No type after 'or' in union type");
2034 ret.idlType.push(typ);
204 }
2053 if (!consume(OTHER, ")")) error("Unterminated union type");
2063 type_suffix(ret);
2073 return ret;
208 };
209
21047 var type = function () {
211261 return single_type() || union_type();
212 };
213
21447 var argument = function () {
21579 var ret = { optional: false, variadic: false };
21679 ret.extAttrs = extended_attrs();
21779 all_ws();
21879 if (consume(ID, "optional")) {
2192 ret.optional = true;
2202 all_ws();
221 }
22279 ret.type = type();
22387 if (!ret.type) return;
22471 if (!ret.optional) {
22569 all_ws();
22669 if (tokens.length >= 3 &&
227 tokens[0].type === "other" && tokens[0].value === "." &&
228 tokens[1].type === "other" && tokens[1].value === "." &&
229 tokens[2].type === "other" && tokens[2].value === "."
230 ) {
2314 tokens.shift();
2324 tokens.shift();
2334 tokens.shift();
2344 ret.variadic = true;
235 }
236 }
23771 all_ws();
23871 var name = consume(ID) || error("No name in argument");
23971 ret.name = name.value;
24071 if (ret.optional) {
2412 all_ws();
2422 ret["default"] = default_();
243 }
24471 return ret;
245 };
246
24747 var argument_list = function () {
24859 var arg = argument(), ret = [];
24967 if (!arg) return ret;
25051 ret.push(arg);
25151 while (true) {
25271 all_ws();
253122 if (!consume(OTHER, ",")) return ret;
25420 all_ws();
25520 var nxt = argument() || error("Trailing comma in arguments list");
25620 ret.push(nxt);
257 }
258 };
259
26047 var simple_extended_attr = function () {
26117 all_ws();
26217 var name = consume(ID);
26317 if (!name) return;
26417 var ret = {
265 name: name.value
266 , "arguments": null
267 };
26817 all_ws();
26917 var eq = consume(OTHER, "=");
27017 if (eq) {
2715 all_ws();
2725 ret.rhs = consume(ID);
2735 if (!ret.rhs) return error("No right hand side to extended attribute assignment");
274 }
27517 all_ws();
27617 if (consume(OTHER, "(")) {
2772 ret["arguments"] = argument_list();
2782 all_ws();
2792 consume(OTHER, ")") || error("Unclosed argument in extended attribute");
280 }
28117 return ret;
282 };
283
284 // Note: we parse something simpler than the official syntax. It's all that ever
285 // seems to be used
28647 var extended_attrs = function () {
287415 var eas = [];
288415 all_ws();
289815 if (!consume(OTHER, "[")) return eas;
29015 eas[0] = simple_extended_attr() || error("Extended attribute with not content");
29115 all_ws();
29215 while (consume(OTHER, ",")) {
2932 all_ws();
2942 eas.push(simple_extended_attr() || error("Trailing comma in extended attribute"));
2952 all_ws();
296 }
29715 consume(OTHER, "]") || error("No end of extended attribute");
29815 return eas;
299 };
300
30147 var default_ = function () {
30211 all_ws();
30311 if (consume(OTHER, "=")) {
3045 all_ws();
3055 var def = const_value();
3065 if (typeof def !== "undefined") {
3073 return def;
308 }
309 else {
3102 var str = consume(STR) || error("No value for default");
3112 return str;
312 }
313 }
314 };
315
31647 var const_ = function () {
317180 all_ws();
318348 if (!consume(ID, "const")) return;
31912 var ret = { type: "const", nullable: false };
32012 all_ws();
32112 var typ = primitive_type();
32212 if (!typ) {
3230 typ = consume(ID) || error("No type for const");
3240 typ = typ.value;
325 }
32612 ret.idlType = typ;
32712 all_ws();
32812 if (consume(OTHER, "?")) {
3291 ret.nullable = true;
3301 all_ws();
331 }
33212 var name = consume(ID) || error("No name for const");
33312 ret.name = name.value;
33412 all_ws();
33512 consume(OTHER, "=") || error("No value assignment for const");
33612 all_ws();
33712 var cnt = const_value();
33824 if (typeof cnt !== "undefined") ret.value = cnt;
3390 else error("No value for const");
34012 all_ws();
34112 consume(OTHER, ";") || error("Unterminated const");
34212 return ret;
343 };
344
34547 var inheritance = function () {
34689 all_ws();
34789 if (consume(OTHER, ":")) {
3489 all_ws();
3499 var inh = consume(ID) || error ("No type in inheritance");
3509 return inh.value;
351 }
352 };
353
35447 var operation_rest = function (ret) {
35556 all_ws();
35657 if (!ret) ret = {};
35756 var name = consume(ID);
35856 ret.name = name ? name.value : null;
35956 all_ws();
36056 consume(OTHER, "(") || error("Invalid operation");
36156 ret["arguments"] = argument_list();
36256 all_ws();
36356 consume(OTHER, ")") || error("Unterminated operation");
36456 all_ws();
36556 consume(OTHER, ";") || error("Unterminated operation");
36656 return ret;
367 };
368
36947 var callback = function () {
370144 all_ws();
371144 var ret;
372286 if (!consume(ID, "callback")) return;
3732 all_ws();
3742 var tok = consume(ID, "interface");
3752 if (tok) {
3761 tokens.unshift(tok);
3771 ret = interface_();
3781 ret.type = "callback interface";
3791 return ret;
380 }
3811 var name = consume(ID) || error("No name for callback");
3821 ret = { type: "callback", name: name.value };
3831 all_ws();
3841 consume(OTHER, "=") || error("No assignment in callback");
3851 all_ws();
3861 ret.idlType = return_type();
3871 all_ws();
3881 consume(OTHER, "(") || error("No arguments in callback");
3891 ret["arguments"] = argument_list();
3901 all_ws();
3911 consume(OTHER, ")") || error("Unterminated callback");
3921 all_ws();
3931 consume(OTHER, ";") || error("Unterminated callback");
3941 return ret;
395 };
396
39747 var attribute = function () {
398154 all_ws();
399154 var grabbed = []
400 , ret = {
401 type: "attribute"
402 , "static": false
403 , stringifier: false
404 , inherit: false
405 , readonly: false
406 };
407154 if (consume(ID, "static")) {
4082 ret["static"] = true;
4092 grabbed.push(last_token);
410 }
411152 else if (consume(ID, "stringifier")) {
4124 ret.stringifier = true;
4134 grabbed.push(last_token);
414 }
415154 var w = all_ws();
416159 if (w) grabbed.push(w);
417154 if (consume(ID, "inherit")) {
4181 if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit");
4191 ret.inherit = true;
4201 grabbed.push(last_token);
4211 var w = all_ws();
4222 if (w) grabbed.push(w);
423 }
424154 if (consume(ID, "readonly")) {
42532 ret.readonly = true;
42632 grabbed.push(last_token);
42732 var w = all_ws();
42864 if (w) grabbed.push(w);
429 }
430154 if (!consume(ID, "attribute")) {
43160 tokens = grabbed.concat(tokens);
43260 return;
433 }
43494 all_ws();
43594 ret.idlType = type() || error("No type in attribute");
43694 if (ret.idlType.sequence) error("Attributes cannot accept sequence types");
43794 all_ws();
43894 var name = consume(ID) || error("No name in attribute");
43994 ret.name = name.value;
44094 all_ws();
44194 consume(OTHER, ";") || error("Unterminated attribute");
44294 return ret;
443 };
444
44547 var return_type = function () {
44661 var typ = type();
44761 if (!typ) {
4480 if (consume(ID, "void")) {
4490 return "void";
450 }
4510 else error("No return type");
452 }
45361 return typ;
454 };
455
45647 var operation = function () {
45760 all_ws();
45860 var ret = {
459 type: "operation"
460 , getter: false
461 , setter: false
462 , creator: false
463 , deleter: false
464 , legacycaller: false
465 , "static": false
466 , stringifier: false
467 };
46860 while (true) {
46978 all_ws();
47087 if (consume(ID, "getter")) ret.getter = true;
47174 else if (consume(ID, "setter")) ret.setter = true;
47265 else if (consume(ID, "creator")) ret.creator = true;
47365 else if (consume(ID, "deleter")) ret.deleter = true;
47462 else if (consume(ID, "legacycaller")) ret.legacycaller = true;
47560 else break;
476 }
47760 if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
47817 all_ws();
47917 ret.idlType = return_type();
48017 operation_rest(ret);
48117 return ret;
482 }
48343 if (consume(ID, "static")) {
4841 ret["static"] = true;
4851 ret.idlType = return_type();
4861 operation_rest(ret);
4871 return ret;
488 }
48942 else if (consume(ID, "stringifier")) {
4903 ret.stringifier = true;
4913 all_ws();
4924 if (consume(OTHER, ";")) return ret;
4932 ret.idlType = return_type();
4942 operation_rest(ret);
4952 return ret;
496 }
49739 ret.idlType = return_type();
49839 all_ws();
49939 if (consume(ID, "iterator")) {
5004 all_ws();
5014 ret.type = "iterator";
5024 if (consume(ID, "object")) {
5031 ret.iteratorObject = "object";
504 }
5053 else if (consume(OTHER, "=")) {
5062 all_ws();
5072 var name = consume(ID) || error("No right hand side in iterator");
5082 ret.iteratorObject = name.value;
509 }
5104 all_ws();
5114 consume(OTHER, ";") || error("Unterminated iterator");
5124 return ret;
513 }
514 else {
51535 operation_rest(ret);
51635 return ret;
517 }
518 };
519
52047 var identifiers = function (arr) {
5215 while (true) {
52211 all_ws();
52311 if (consume(OTHER, ",")) {
5246 all_ws();
5256 var name = consume(ID) || error("Trailing comma in identifiers list");
5266 arr.push(name.value);
527 }
5285 else break;
529 }
530 };
531
53247 var serialiser = function () {
533164 all_ws();
534318 if (!consume(ID, "serializer")) return;
53510 var ret = { type: "serializer" };
53610 all_ws();
53710 if (consume(OTHER, "=")) {
5388 all_ws();
5398 if (consume(OTHER, "{")) {
5405 ret.patternMap = true;
5415 all_ws();
5425 var id = consume(ID);
5435 if (id && id.value === "getter") {
5441 ret.names = ["getter"];
545 }
5464 else if (id && id.value === "inherit") {
5472 ret.names = ["inherit"];
5482 identifiers(ret.names);
549 }
5502 else if (id) {
5512 ret.names = [id.value];
5522 identifiers(ret.names);
553 }
554 else {
5550 ret.names = [];
556 }
5575 all_ws();
5585 consume(OTHER, "}") || error("Unterminated serializer pattern map");
559 }
5603 else if (consume(OTHER, "[")) {
5612 ret.patternList = true;
5622 all_ws();
5632 var id = consume(ID);
5642 if (id && id.value === "getter") {
5651 ret.names = ["getter"];
566 }
5671 else if (id) {
5681 ret.names = [id.value];
5691 identifiers(ret.names);
570 }
571 else {
5720 ret.names = [];
573 }
5742 all_ws();
5752 consume(OTHER, "]") || error("Unterminated serializer pattern list");
576 }
577 else {
5781 var name = consume(ID) || error("Invalid serializer");
5791 ret.name = name.value;
580 }
5818 all_ws();
5828 consume(OTHER, ";") || error("Unterminated serializer");
5838 return ret;
584 }
5852 else if (consume(OTHER, ";")) {
586 // noop, just parsing
587 }
588 else {
5891 ret.idlType = return_type();
5901 all_ws();
5911 ret.operation = operation_rest();
592 }
5932 return ret;
594 };
595
59647 var interface_ = function (isPartial) {
597144 all_ws();
598210 if (!consume(ID, "interface")) return;
59978 all_ws();
60078 var name = consume(ID) || error("No name for interface");
60178 var ret = {
602 type: "interface"
603 , name: name.value
604 , partial: false
605 , members: []
606 };
607155 if (!isPartial) ret.inheritance = inheritance() || null;
60878 all_ws();
60978 consume(OTHER, "{") || error("Bodyless interface");
61078 while (true) {
611251 all_ws();
612251 if (consume(OTHER, "}")) {
61378 all_ws();
61478 consume(OTHER, ";") || error("Missing semicolon after interface");
61578 return ret;
616 }
617173 var ea = extended_attrs();
618173 all_ws();
619173 var cnt = const_();
620173 if (cnt) {
6219 cnt.extAttrs = ea;
6229 ret.members.push(cnt);
6239 continue;
624 }
625164 var mem = serialiser() || attribute() || operation() || error("Unknown member");
626164 mem.extAttrs = ea;
627164 ret.members.push(mem);
628 }
629 };
630
63147 var partial = function () {
63266 all_ws();
633130 if (!consume(ID, "partial")) return;
6342 var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything");
6352 thing.partial = true;
6362 return thing;
637 };
638
63947 var dictionary = function (isPartial) {
64066 all_ws();
641128 if (!consume(ID, "dictionary")) return;
6424 all_ws();
6434 var name = consume(ID) || error("No name for dictionary");
6444 var ret = {
645 type: "dictionary"
646 , name: name.value
647 , partial: false
648 , members: []
649 };
6507 if (!isPartial) ret.inheritance = inheritance() || null;
6514 all_ws();
6524 consume(OTHER, "{") || error("Bodyless dictionary");
6534 while (true) {
65413 all_ws();
65513 if (consume(OTHER, "}")) {
6564 all_ws();
6574 consume(OTHER, ";") || error("Missing semicolon after dictionary");
6584 return ret;
659 }
6609 var ea = extended_attrs();
6619 all_ws();
6629 var typ = type() || error("No type for dictionary member");
6639 all_ws();
6649 var name = consume(ID) || error("No name for dictionary member");
6659 ret.members.push({
666 type: "field"
667 , name: name.value
668 , idlType: typ
669 , extAttrs: ea
670 , "default": default_()
671 });
6729 all_ws();
6739 consume(OTHER, ";") || error("Unterminated dictionary member");
674 }
675 };
676
67747 var exception = function () {
67861 all_ws();
679113 if (!consume(ID, "exception")) return;
6809 all_ws();
6819 var name = consume(ID) || error("No name for exception");
6829 var ret = {
683 type: "exception"
684 , name: name.value
685 , members: []
686 };
6879 ret.inheritance = inheritance() || null;
6889 all_ws();
6899 consume(OTHER, "{") || error("Bodyless exception");
6909 while (true) {
69116 all_ws();
69216 if (consume(OTHER, "}")) {
6939 all_ws();
6949 consume(OTHER, ";") || error("Missing semicolon after exception");
6959 return ret;
696 }
6977 var ea = extended_attrs();
6987 all_ws();
6997 var cnt = const_();
7007 if (cnt) {
7013 cnt.extAttrs = ea;
7023 ret.members.push(cnt);
703 }
704 else {
7054 var typ = type();
7064 all_ws();
7074 var name = consume(ID);
7084 all_ws();
7094 if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body");
7104 ret.members.push({
711 type: "field"
712 , name: name.value
713 , idlType: typ
714 , extAttrs: ea
715 });
716 }
717 }
718 };
719
72047 var enum_ = function () {
72152 all_ws();
722103 if (!consume(ID, "enum")) return;
7231 all_ws();
7241 var name = consume(ID) || error("No name for enum");
7251 var ret = {
726 type: "enum"
727 , name: name.value
728 , values: []
729 };
7301 all_ws();
7311 consume(OTHER, "{") || error("No curly for enum");
7321 var saw_comma = false;
7331 while (true) {
7344 all_ws();
7354 if (consume(OTHER, "}")) {
7361 all_ws();
7371 if (saw_comma) error("Trailing comma in enum");
7381 consume(OTHER, ";") || error("No semicolon after enum");
7391 return ret;
740 }
7413 var val = consume(STR) || error("Unexpected value in enum");
7423 ret.values.push(val.value.replace(/"/g, ""));
7433 all_ws();
7443 if (consume(OTHER, ",")) {
7452 all_ws();
7462 saw_comma = true;
747 }
748 else {
7491 saw_comma = false;
750 }
751 }
752 };
753
75447 var typedef = function () {
75551 all_ws();
75699 if (!consume(ID, "typedef")) return;
7573 var ret = {
758 type: "typedef"
759 };
7603 all_ws();
7613 ret.extAttrs = extended_attrs();
7623 all_ws();
7633 ret.idlType = type() || error("No type in typedef");
7643 all_ws();
7653 var name = consume(ID) || error("No name in typedef");
7663 ret.name = name.value;
7673 all_ws();
7683 consume(OTHER, ";") || error("Unterminated typedef");
7693 return ret;
770 };
771
77247 var implements_ = function () {
77348 all_ws();
77448 var target = consume(ID);
77595 if (!target) return;
7761 var w = all_ws();
7771 if (consume(ID, "implements")) {
7781 var ret = {
779 type: "implements"
780 , target: target.value
781 };
7821 all_ws();
7831 var imp = consume(ID) || error("Incomplete implements statement");
7841 ret["implements"] = imp.value;
7851 all_ws();
7861 consume(OTHER, ";") || error("No terminating ; for implements statement");
7871 return ret;
788 }
789 else {
790 // rollback
7910 tokens.unshift(w);
7920 tokens.unshift(target);
793 }
794 };
795
79647 var definition = function () {
797144 return callback() ||
798 interface_() ||
799 partial() ||
800 dictionary() ||
801 exception() ||
802 enum_() ||
803 typedef() ||
804 implements_()
805 ;
806 };
807
80847 var definitions = function () {
80947 if (!tokens.length) return [];
81047 var defs = [];
81147 while (true) {
812144 var ea = extended_attrs()
813 , def = definition();
814144 if (!def) {
81547 if (ea.length) error("Stray extended attributes");
81647 break;
817 }
81897 def.extAttrs = ea;
81997 defs.push(def);
820 }
82147 return defs;
822 };
82347 var res = definitions();
82447 if (tokens.length) error("Unrecognised tokens");
82547 return res;
826 };
827
8281 var obj = {
829 parse: function (str) {
83047 var tokens = tokenise(str);
831 // console.log(tokens);
83247 return parse(tokens);
833 }
834 };
8351 if (typeof module !== "undefined" && module.exports) {
8361 module.exports = obj;
837 }
838 else {
8390 window.WebIDL2 = obj;
840 }
841}());
diff --git a/test/fixtures/wpt/resources/webidl2/index.js b/test/fixtures/wpt/resources/webidl2/index.js new file mode 100644 index 00000000000000..09f9eb46aa78f4 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/index.js @@ -0,0 +1 @@ +module.exports = require("./lib/webidl2.js"); diff --git a/test/fixtures/wpt/resources/webidl2/lib/webidl2.js b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js new file mode 100644 index 00000000000000..ef519c09df6d6d --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js @@ -0,0 +1,970 @@ +"use strict"; + +(() => { + // These regular expressions use the sticky flag so they will only match at + // the current location (ie. the offset of lastIndex). + const tokenRe = { + // This expression uses a lookahead assertion to catch false matches + // against integers early. + "float": /-?(?=[0-9]*\.|[0-9]+[eE])(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/y, + "integer": /-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/y, + "identifier": /_?[A-Za-z][0-9A-Z_a-z-]*/y, + "string": /"[^"]*"/y, + "whitespace": /[\t\n\r ]+/y, + "comment": /((\/(\/.*|\*([^*]|\*[^\/])*\*\/)[\t\n\r ]*)+)/y, + "other": /[^\t\n\r 0-9A-Za-z]/y + }; + + const stringTypes = [ + "ByteString", + "DOMString", + "USVString" + ]; + + const argumentNameKeywords = [ + "attribute", + "callback", + "const", + "deleter", + "dictionary", + "enum", + "getter", + "includes", + "inherit", + "interface", + "iterable", + "maplike", + "namespace", + "partial", + "required", + "setlike", + "setter", + "static", + "stringifier", + "typedef", + "unrestricted" + ]; + + const nonRegexTerminals = [ + "FrozenArray", + "Infinity", + "NaN", + "Promise", + "boolean", + "byte", + "double", + "false", + "float", + "implements", + "legacyiterable", + "long", + "mixin", + "null", + "octet", + "optional", + "or", + "readonly", + "record", + "sequence", + "short", + "true", + "unsigned", + "void" + ].concat(argumentNameKeywords, stringTypes); + + const punctuations = [ + "(", + ")", + ",", + "-Infinity", + "...", + ":", + ";", + "<", + "=", + ">", + "?", + "[", + "]", + "{", + "}" + ]; + + function tokenise(str) { + const tokens = []; + let lastIndex = 0; + let trivia = ""; + while (lastIndex < str.length) { + const nextChar = str.charAt(lastIndex); + let result = -1; + + if (/[\t\n\r ]/.test(nextChar)) { + result = attemptTokenMatch("whitespace", { noFlushTrivia: true }); + } else if (nextChar === '/') { + result = attemptTokenMatch("comment", { noFlushTrivia: true }); + } + + if (result !== -1) { + trivia += tokens.pop().value; + } else if (/[-0-9.]/.test(nextChar)) { + result = attemptTokenMatch("float"); + if (result === -1) { + result = attemptTokenMatch("integer"); + } + } else if (/[A-Z_a-z]/.test(nextChar)) { + result = attemptTokenMatch("identifier"); + const token = tokens[tokens.length - 1]; + if (result !== -1 && nonRegexTerminals.includes(token.value)) { + token.type = token.value; + } + } else if (nextChar === '"') { + result = attemptTokenMatch("string"); + } + + for (const punctuation of punctuations) { + if (str.startsWith(punctuation, lastIndex)) { + tokens.push({ type: punctuation, value: punctuation, trivia }); + trivia = ""; + lastIndex += punctuation.length; + result = lastIndex; + break; + } + } + + // other as the last try + if (result === -1) { + result = attemptTokenMatch("other"); + } + if (result === -1) { + throw new Error("Token stream not progressing"); + } + lastIndex = result; + } + return tokens; + + function attemptTokenMatch(type, { noFlushTrivia } = {}) { + const re = tokenRe[type]; + re.lastIndex = lastIndex; + const result = re.exec(str); + if (result) { + tokens.push({ type, value: result[0], trivia }); + if (!noFlushTrivia) { + trivia = ""; + } + return re.lastIndex; + } + return -1; + } + } + + class WebIDLParseError { + constructor(str, line, input, tokens) { + this.message = str; + this.line = line; + this.input = input; + this.tokens = tokens; + } + + toString() { + const escapedInput = JSON.stringify(this.input); + const tokens = JSON.stringify(this.tokens, null, 4); + return `${this.message}, line ${this.line} (tokens: ${escapedInput})\n${tokens}`; + } + } + + function parse(tokens) { + let line = 1; + tokens = tokens.slice(); + const names = new Map(); + let current = null; + + const FLOAT = "float"; + const INT = "integer"; + const ID = "identifier"; + const STR = "string"; + const OTHER = "other"; + + const EMPTY_OPERATION = Object.freeze({ + type: "operation", + getter: false, + setter: false, + deleter: false, + static: false, + stringifier: false + }); + + const EMPTY_IDLTYPE = Object.freeze({ + generic: null, + nullable: false, + union: false, + idlType: null, + extAttrs: [] + }); + + function error(str) { + const maxTokens = 5; + const tok = tokens + .slice(consume_position, consume_position + maxTokens) + .map(t => t.trivia + t.value).join(""); + // Count newlines preceding the actual erroneous token + if (tokens.length) { + line += count(tokens[consume_position].trivia, "\n"); + } + + let message; + if (current) { + message = `Got an error during or right after parsing \`${current.partial ? "partial " : ""}${current.type} ${current.name}\`: ${str}` + } + else { + // throwing before any valid definition + message = `Got an error before parsing any named definition: ${str}`; + } + + throw new WebIDLParseError(message, line, tok, tokens.slice(0, maxTokens)); + } + + function sanitize_name(name, type) { + if (names.has(name)) { + error(`The name "${name}" of type "${names.get(name)}" is already seen`); + } + names.set(name, type); + return name; + } + + let consume_position = 0; + + function probe(type) { + return tokens.length > consume_position && tokens[consume_position].type === type; + } + + function consume(...candidates) { + // TODO: use const when Servo updates its JS engine + for (let type of candidates) { + if (!probe(type)) continue; + const token = tokens[consume_position]; + consume_position++; + line += count(token.trivia, "\n"); + return token; + } + } + + function unescape(identifier) { + return identifier.startsWith('_') ? identifier.slice(1) : identifier; + } + + function unconsume(position) { + while (consume_position > position) { + consume_position--; + line -= count(tokens[consume_position].trivia, "\n"); + } + } + + function count(str, char) { + let total = 0; + for (let i = str.indexOf(char); i !== -1; i = str.indexOf(char, i + 1)) { + ++total; + } + return total; + } + + function integer_type() { + let ret = ""; + if (consume("unsigned")) ret = "unsigned "; + if (consume("short")) return ret + "short"; + if (consume("long")) { + ret += "long"; + if (consume("long")) return ret + " long"; + return ret; + } + if (ret) error("Failed to parse integer type"); + } + + function float_type() { + let ret = ""; + if (consume("unrestricted")) ret = "unrestricted "; + if (consume("float")) return ret + "float"; + if (consume("double")) return ret + "double"; + if (ret) error("Failed to parse float type"); + } + + function primitive_type() { + const num_type = integer_type() || float_type(); + if (num_type) return num_type; + if (consume("boolean")) return "boolean"; + if (consume("byte")) return "byte"; + if (consume("octet")) return "octet"; + } + + function const_value() { + if (consume("true")) return { type: "boolean", value: true }; + if (consume("false")) return { type: "boolean", value: false }; + if (consume("null")) return { type: "null" }; + if (consume("Infinity")) return { type: "Infinity", negative: false }; + if (consume("-Infinity")) return { type: "Infinity", negative: true }; + if (consume("NaN")) return { type: "NaN" }; + const ret = consume(FLOAT, INT); + if (ret) return { type: "number", value: ret.value }; + } + + function type_suffix(obj) { + obj.nullable = !!consume("?"); + if (probe("?")) error("Can't nullable more than once"); + } + + function generic_type(typeName) { + const name = consume("FrozenArray", "Promise", "sequence", "record"); + if (!name) { + return; + } + const ret = { generic: name.type }; + consume("<") || error(`No opening bracket after ${name.type}`); + switch (name.type) { + case "Promise": + if (probe("[")) error("Promise type cannot have extended attribute"); + ret.idlType = return_type(typeName); + break; + case "sequence": + case "FrozenArray": + ret.idlType = type_with_extended_attributes(typeName); + break; + case "record": + if (probe("[")) error("Record key cannot have extended attribute"); + ret.idlType = []; + const keyType = consume(...stringTypes); + if (!keyType) error(`Record key must be a string type`); + ret.idlType.push(Object.assign({ type: typeName }, EMPTY_IDLTYPE, { idlType: keyType.value })); + consume(",") || error("Missing comma after record key type"); + const valueType = type_with_extended_attributes(typeName) || error("Error parsing generic type record"); + ret.idlType.push(valueType); + break; + } + if (!ret.idlType) error(`Error parsing generic type ${name.type}`); + consume(">") || error(`Missing closing bracket after ${name.type}`); + if (name.type === "Promise" && probe("?")) { + error("Promise type cannot be nullable"); + } + type_suffix(ret); + return ret; + } + + function single_type(typeName) { + const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE); + const generic = generic_type(typeName); + if (generic) { + return Object.assign(ret, generic); + } + const prim = primitive_type(); + let name; + if (prim) { + ret.idlType = prim; + } else if (name = consume(ID, ...stringTypes)) { + ret.idlType = name.value; + if (probe("<")) error(`Unsupported generic type ${name.value}`); + } else { + return; + } + type_suffix(ret); + if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable"); + return ret; + } + + function union_type(typeName) { + if (!consume("(")) return; + const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE, { union: true, idlType: [] }); + do { + const typ = type_with_extended_attributes() || error("No type after open parenthesis or 'or' in union type"); + ret.idlType.push(typ); + } while (consume("or")); + if (ret.idlType.length < 2) { + error("At least two types are expected in a union type but found less"); + } + if (!consume(")")) error("Unterminated union type"); + type_suffix(ret); + return ret; + } + + function type(typeName) { + return single_type(typeName) || union_type(typeName); + } + + function type_with_extended_attributes(typeName) { + const extAttrs = extended_attrs(); + const ret = single_type(typeName) || union_type(typeName); + if (extAttrs.length && ret) ret.extAttrs = extAttrs; + return ret; + } + + function argument() { + const start_position = consume_position; + const ret = { optional: false, variadic: false, default: null }; + ret.extAttrs = extended_attrs(); + const opt_token = consume("optional"); + if (opt_token) { + ret.optional = true; + } + ret.idlType = type_with_extended_attributes("argument-type"); + if (!ret.idlType) { + unconsume(start_position); + return; + } + if (!ret.optional && consume("...")) { + ret.variadic = true; + } + const name = consume(ID, ...argumentNameKeywords); + if (!name) { + unconsume(start_position); + return; + } + ret.name = unescape(name.value); + ret.escapedName = name.value; + if (ret.optional) { + ret.default = default_() || null; + } + return ret; + } + + function argument_list() { + const ret = []; + const arg = argument(); + if (!arg) return ret; + ret.push(arg); + while (true) { + if (!consume(",")) return ret; + const nxt = argument() || error("Trailing comma in arguments list"); + ret.push(nxt); + } + } + + function simple_extended_attr() { + const name = consume(ID); + if (!name) return; + const ret = { + name: name.value, + arguments: null, + type: "extended-attribute", + rhs: null + }; + const eq = consume("="); + if (eq) { + ret.rhs = consume(ID, FLOAT, INT, STR); + if (ret.rhs) { + // No trivia exposure yet + ret.rhs.trivia = undefined; + } + } + if (consume("(")) { + if (eq && !ret.rhs) { + // [Exposed=(Window,Worker)] + ret.rhs = { + type: "identifier-list", + value: identifiers() + }; + } + else { + // [NamedConstructor=Audio(DOMString src)] or [Constructor(DOMString str)] + ret.arguments = argument_list(); + } + consume(")") || error("Unexpected token in extended attribute argument list"); + } + if (eq && !ret.rhs) error("No right hand side to extended attribute assignment"); + return ret; + } + + // Note: we parse something simpler than the official syntax. It's all that ever + // seems to be used + function extended_attrs() { + const eas = []; + if (!consume("[")) return eas; + eas[0] = simple_extended_attr() || error("Extended attribute with not content"); + while (consume(",")) { + eas.push(simple_extended_attr() || error("Trailing comma in extended attribute")); + } + consume("]") || error("No end of extended attribute"); + return eas; + } + + function default_() { + if (consume("=")) { + const def = const_value(); + if (def) { + return def; + } else if (consume("[")) { + if (!consume("]")) error("Default sequence value must be empty"); + return { type: "sequence", value: [] }; + } else { + const str = consume(STR) || error("No value for default"); + str.value = str.value.slice(1, -1); + // No trivia exposure yet + str.trivia = undefined; + return str; + } + } + } + + function const_() { + if (!consume("const")) return; + const ret = { type: "const", nullable: false }; + let typ = primitive_type(); + if (!typ) { + typ = consume(ID) || error("No type for const"); + typ = typ.value; + } + ret.idlType = Object.assign({ type: "const-type" }, EMPTY_IDLTYPE, { idlType: typ }); + type_suffix(ret); + const name = consume(ID) || error("No name for const"); + ret.name = name.value; + consume("=") || error("No value assignment for const"); + const cnt = const_value(); + if (cnt) ret.value = cnt; + else error("No value for const"); + consume(";") || error("Unterminated const"); + return ret; + } + + function inheritance() { + if (consume(":")) { + const inh = consume(ID) || error("No type in inheritance"); + return inh.value; + } + } + + function operation_rest(ret) { + if (!ret) ret = {}; + const name = consume(ID); + ret.name = name ? unescape(name.value) : null; + ret.escapedName = name ? name.value : null; + consume("(") || error("Invalid operation"); + ret.arguments = argument_list(); + consume(")") || error("Unterminated operation"); + consume(";") || error("Unterminated operation"); + return ret; + } + + function callback() { + let ret; + if (!consume("callback")) return; + const tok = consume("interface"); + if (tok) { + ret = interface_rest(false, "callback interface"); + return ret; + } + const name = consume(ID) || error("No name for callback"); + ret = current = { type: "callback", name: sanitize_name(name.value, "callback") }; + consume("=") || error("No assignment in callback"); + ret.idlType = return_type() || error("Missing return type"); + consume("(") || error("No arguments in callback"); + ret.arguments = argument_list(); + consume(")") || error("Unterminated callback"); + consume(";") || error("Unterminated callback"); + return ret; + } + + function attribute({ noInherit = false, readonly = false } = {}) { + const start_position = consume_position; + const ret = { + type: "attribute", + static: false, + stringifier: false, + inherit: false, + readonly: false + }; + if (!noInherit && consume("inherit")) { + ret.inherit = true; + } + if (consume("readonly")) { + ret.readonly = true; + } else if (readonly && probe("attribute")) { + error("Attributes must be readonly in this context"); + } + const rest = attribute_rest(ret); + if (!rest) { + unconsume(start_position); + } + return rest; + } + + function attribute_rest(ret) { + if (!consume("attribute")) { + return; + } + ret.idlType = type_with_extended_attributes("attribute-type") || error("No type in attribute"); + if (ret.idlType.generic === "sequence") error("Attributes cannot accept sequence types"); + if (ret.idlType.generic === "record") error("Attributes cannot accept record types"); + const name = consume(ID, "required") || error("No name in attribute"); + ret.name = unescape(name.value); + ret.escapedName = name.value; + consume(";") || error("Unterminated attribute"); + return ret; + } + + function return_type(typeName) { + const typ = type(typeName || "return-type"); + if (typ) { + return typ; + } + if (consume("void")) { + return Object.assign({ type: "return-type" }, EMPTY_IDLTYPE, { idlType: "void" }); + } + } + + function operation({ regular = false } = {}) { + const ret = Object.assign({}, EMPTY_OPERATION); + while (!regular) { + if (consume("getter")) ret.getter = true; + else if (consume("setter")) ret.setter = true; + else if (consume("deleter")) ret.deleter = true; + else break; + } + ret.idlType = return_type() || error("Missing return type"); + operation_rest(ret); + return ret; + } + + function static_member() { + if (!consume("static")) return; + const member = attribute({ noInherit: true }) || + operation({ regular: true }) || + error("No body in static member"); + member.static = true; + return member; + } + + function stringifier() { + if (!consume("stringifier")) return; + if (consume(";")) { + return Object.assign({}, EMPTY_OPERATION, { stringifier: true }); + } + const member = attribute({ noInherit: true }) || + operation({ regular: true }) || + error("Unterminated stringifier"); + member.stringifier = true; + return member; + } + + function identifiers() { + const arr = []; + const id = consume(ID); + if (id) { + arr.push(id.value); + } + else error("Expected identifiers but not found"); + while (true) { + if (consume(",")) { + const name = consume(ID) || error("Trailing comma in identifiers list"); + arr.push(name.value); + } else break; + } + return arr; + } + + function iterable_type() { + if (consume("iterable")) return "iterable"; + else if (consume("legacyiterable")) return "legacyiterable"; + else if (consume("maplike")) return "maplike"; + else if (consume("setlike")) return "setlike"; + else return; + } + + function readonly_iterable_type() { + if (consume("maplike")) return "maplike"; + else if (consume("setlike")) return "setlike"; + else return; + } + + function iterable() { + const start_position = consume_position; + const ret = { type: null, idlType: null, readonly: false }; + if (consume("readonly")) { + ret.readonly = true; + } + const consumeItType = ret.readonly ? readonly_iterable_type : iterable_type; + + const ittype = consumeItType(); + if (!ittype) { + unconsume(start_position); + return; + } + + const secondTypeRequired = ittype === "maplike"; + const secondTypeAllowed = secondTypeRequired || ittype === "iterable"; + ret.type = ittype; + if (ret.type !== 'maplike' && ret.type !== 'setlike') + delete ret.readonly; + if (consume("<")) { + ret.idlType = [type_with_extended_attributes()] || error(`Error parsing ${ittype} declaration`); + if (secondTypeAllowed) { + if (consume(",")) { + ret.idlType.push(type_with_extended_attributes()); + } + else if (secondTypeRequired) + error(`Missing second type argument in ${ittype} declaration`); + } + if (!consume(">")) error(`Unterminated ${ittype} declaration`); + if (!consume(";")) error(`Missing semicolon after ${ittype} declaration`); + } else + error(`Error parsing ${ittype} declaration`); + + return ret; + } + + function interface_rest(isPartial, typeName = "interface") { + const name = consume(ID) || error("No name for interface"); + const mems = []; + const ret = current = { + type: typeName, + name: isPartial ? name.value : sanitize_name(name.value, "interface"), + partial: isPartial, + members: mems + }; + if (!isPartial) ret.inheritance = inheritance() || null; + consume("{") || error("Bodyless interface"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after interface"); + return ret; + } + const ea = extended_attrs(); + const mem = const_() || + static_member() || + stringifier() || + iterable() || + attribute() || + operation() || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + } + + function mixin_rest(isPartial) { + if (!consume("mixin")) return; + const name = consume(ID) || error("No name for interface mixin"); + const mems = []; + const ret = current = { + type: "interface mixin", + name: isPartial ? name.value : sanitize_name(name.value, "interface mixin"), + partial: isPartial, + members: mems + }; + consume("{") || error("Bodyless interface mixin"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after interface mixin"); + return ret; + } + const ea = extended_attrs(); + const mem = const_() || + stringifier() || + attribute({ noInherit: true }) || + operation({ regular: true }) || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + } + + function interface_(isPartial) { + if (!consume("interface")) return; + return mixin_rest(isPartial) || + interface_rest(isPartial) || + error("Interface has no proper body"); + } + + function namespace(isPartial) { + if (!consume("namespace")) return; + const name = consume(ID) || error("No name for namespace"); + const mems = []; + const ret = current = { + type: "namespace", + name: isPartial ? name.value : sanitize_name(name.value, "namespace"), + partial: isPartial, + members: mems + }; + consume("{") || error("Bodyless namespace"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after namespace"); + return ret; + } + const ea = extended_attrs(); + const mem = attribute({ noInherit: true, readonly: true }) || + operation({ regular: true }) || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + } + + function partial() { + if (!consume("partial")) return; + const thing = dictionary(true) || + interface_(true) || + namespace(true) || + error("Partial doesn't apply to anything"); + return thing; + } + + function dictionary(isPartial) { + if (!consume("dictionary")) return; + const name = consume(ID) || error("No name for dictionary"); + const mems = []; + const ret = current = { + type: "dictionary", + name: isPartial ? name.value : sanitize_name(name.value, "dictionary"), + partial: isPartial, + members: mems + }; + if (!isPartial) ret.inheritance = inheritance() || null; + consume("{") || error("Bodyless dictionary"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after dictionary"); + return ret; + } + const ea = extended_attrs(); + const required = consume("required"); + const typ = type_with_extended_attributes("dictionary-type") || error("No type for dictionary member"); + const name = consume(ID) || error("No name for dictionary member"); + const dflt = default_() || null; + if (required && dflt) error("Required member must not have a default"); + const member = { + type: "field", + name: unescape(name.value), + escapedName: name.value, + required: !!required, + idlType: typ, + extAttrs: ea, + default: dflt + }; + ret.members.push(member); + consume(";") || error("Unterminated dictionary member"); + } + } + + function enum_() { + if (!consume("enum")) return; + const name = consume(ID) || error("No name for enum"); + const vals = []; + const ret = current = { + type: "enum", + name: sanitize_name(name.value, "enum"), + values: vals + }; + consume("{") || error("No curly for enum"); + let value_expected = true; + while (true) { + if (consume("}")) { + if (!ret.values.length) error("No value in enum"); + consume(";") || error("No semicolon after enum"); + return ret; + } + else if (!value_expected) { + error("No comma between enum values"); + } + const val = consume(STR) || error("Unexpected value in enum"); + val.value = val.value.slice(1, -1); + // No trivia exposure yet + val.trivia = undefined; + ret.values.push(val); + value_expected = !!consume(","); + } + } + + function typedef() { + if (!consume("typedef")) return; + const ret = { + type: "typedef" + }; + ret.idlType = type_with_extended_attributes("typedef-type") || error("No type in typedef"); + const name = consume(ID) || error("No name in typedef"); + ret.name = sanitize_name(name.value, "typedef"); + current = ret; + consume(";") || error("Unterminated typedef"); + return ret; + } + + function implements_() { + const start_position = consume_position; + const target = consume(ID); + if (!target) return; + if (consume("implements")) { + const ret = { + type: "implements", + target: target.value + }; + const imp = consume(ID) || error("Incomplete implements statement"); + ret.implements = imp.value; + consume(";") || error("No terminating ; for implements statement"); + return ret; + } else { + // rollback + unconsume(start_position); + } + } + + function includes() { + const start_position = consume_position; + const target = consume(ID); + if (!target) return; + if (consume("includes")) { + const ret = { + type: "includes", + target: target.value + }; + const imp = consume(ID) || error("Incomplete includes statement"); + ret.includes = imp.value; + consume(";") || error("No terminating ; for includes statement"); + return ret; + } else { + // rollback + unconsume(start_position); + } + } + + function definition() { + return callback() || + interface_(false) || + partial() || + dictionary(false) || + enum_() || + typedef() || + implements_() || + includes() || + namespace(false); + } + + function definitions() { + if (!tokens.length) return []; + const defs = []; + while (true) { + const ea = extended_attrs(); + const def = definition(); + if (!def) { + if (ea.length) error("Stray extended attributes"); + break; + } + def.extAttrs = ea; + defs.push(def); + } + return defs; + } + const res = definitions(); + if (consume_position < tokens.length) error("Unrecognised tokens"); + return res; + } + + const obj = { + parse(str) { + const tokens = tokenise(str); + return parse(tokens); + } + }; + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = obj; + } else if (typeof define === 'function' && define.amd) { + define([], () => obj); + } else { + (self || window).WebIDL2 = obj; + } +})(); diff --git a/test/fixtures/wpt/resources/webidl2/lib/webidl2.js.headers b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js.headers new file mode 100644 index 00000000000000..6805c323df5a97 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js.headers @@ -0,0 +1 @@ +Content-Type: text/javascript; charset=utf-8 diff --git a/test/fixtures/wpt/resources/webidl2/lib/writer.js b/test/fixtures/wpt/resources/webidl2/lib/writer.js new file mode 100644 index 00000000000000..b3097a6f8a74e4 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/lib/writer.js @@ -0,0 +1,221 @@ +"use strict"; + +(() => { + function write(ast, opt = {}) { + const noop = str => str; + const optNames = "type".split(" "); + const context = []; + for (const o of optNames) { + if (!opt[o]) opt[o] = noop; + } + + function literal(it) { + return it.value; + }; + function type(it) { + if (typeof it === "string") return opt.type(it); // XXX should maintain some context + let ret = extended_attributes(it.extAttrs); + if (it.union) ret += `(${it.idlType.map(type).join(" or ")})`; + else { + if (it.generic) ret += `${it.generic}<`; + if (Array.isArray(it.idlType)) ret += it.idlType.map(type).join(", "); + else ret += type(it.idlType); + if (it.generic) ret += ">"; + } + if (it.nullable) ret += "?"; + + return ret; + }; + function const_value(it) { + const tp = it.type; + if (tp === "boolean") return it.value ? "true" : "false"; + else if (tp === "null") return "null"; + else if (tp === "Infinity") return (it.negative ? "-" : "") + "Infinity"; + else if (tp === "NaN") return "NaN"; + else if (tp === "number") return it.value; + else if (tp === "sequence") return "[]"; + else return `"${it.value}"`; + }; + function argument(arg) { + let ret = extended_attributes(arg.extAttrs); + if (arg.optional) ret += "optional "; + ret += type(arg.idlType); + if (arg.variadic) ret += "..."; + ret += ` ${arg.escapedName}`; + if (arg.default) ret += ` = ${const_value(arg.default)}`; + return ret; + }; + function make_ext_at(it) { + context.unshift(it); + let ret = it.name; + if (it.rhs) { + if (it.rhs.type === "identifier-list") ret += `=(${it.rhs.value.join(",")})`; + else ret += `=${it.rhs.value}`; + } + if (it.arguments) ret += `(${it.arguments.length ? it.arguments.map(argument).join(",") : ""})`; + context.shift(); // XXX need to add more contexts, but not more than needed for ReSpec + return ret; + }; + function extended_attributes(eats) { + if (!eats || !eats.length) return ""; + return `[${eats.map(make_ext_at).join(", ")}]`; + }; + + const modifiers = "getter setter deleter stringifier static".split(" "); + function operation(it) { + let ret = extended_attributes(it.extAttrs); + if (it.stringifier && !it.idlType) return "stringifier;"; + for (const mod of modifiers) { + if (it[mod]) ret += mod + " "; + } + ret += type(it.idlType) + " "; + if (it.name) ret += it.escapedName; + ret += `(${it.arguments.map(argument).join(",")});`; + return ret; + }; + + function attribute(it) { + let ret = extended_attributes(it.extAttrs); + if (it.static) ret += "static "; + if (it.stringifier) ret += "stringifier "; + if (it.inherit) ret += "inherit "; + if (it.readonly) ret += "readonly "; + ret += `attribute ${type(it.idlType)} ${it.escapedName};`; + return ret; + }; + + function interface_(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `interface ${it.name} `; + if (it.inheritance) ret += `: ${it.inheritance} `; + ret += `{${iterate(it.members)}};`; + return ret; + }; + + function interface_mixin(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `interface mixin ${it.name} `; + ret += `{${iterate(it.members)}};`; + return ret; + } + + function namespace(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `namespace ${it.name} `; + ret += `{${iterate(it.members)}};`; + return ret; + } + + function dictionary(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `dictionary ${it.name} `; + if (it.inheritance) ret += `: ${it.inheritance} `; + ret += `{${iterate(it.members)}};`; + return ret; + }; + function field(it) { + let ret = extended_attributes(it.extAttrs); + if (it.required) ret += "required "; + ret += `${type(it.idlType)} ${it.escapedName}`; + if (it.default) ret += ` = ${const_value(it.default)}`; + ret += ";"; + return ret; + }; + function const_(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}const ${type(it.idlType)}${it.nullable ? "?" : ""} ${it.name} = ${const_value(it.value)};`; + }; + function typedef(it) { + let ret = extended_attributes(it.extAttrs); + ret += `typedef ${extended_attributes(it.typeExtAttrs)}`; + return `${ret}${type(it.idlType)} ${it.name};`; + }; + function implements_(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}${it.target} implements ${it.implements};`; + }; + function includes(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}${it.target} includes ${it.includes};`; + }; + function callback(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}callback ${it.name} = ${type(it.idlType)}(${it.arguments.map(argument).join(",")});`; + }; + function enum_(it) { + let ret = extended_attributes(it.extAttrs); + ret += `enum ${it.name} {`; + for (const v of it.values) { + ret += `"${v.value}",`; + } + return ret + "};"; + }; + function iterable(it) { + return `iterable<${Array.isArray(it.idlType) ? it.idlType.map(type).join(", ") : type(it.idlType)}>;`; + }; + function legacyiterable(it) { + return `legacyiterable<${Array.isArray(it.idlType) ? it.idlType.map(type).join(", ") : type(it.idlType)}>;`; + }; + function maplike(it) { + return `${it.readonly ? "readonly " : ""}maplike<${it.idlType.map(type).join(", ")}>;`; + }; + function setlike(it) { + return `${it.readonly ? "readonly " : ""}setlike<${type(it.idlType[0])}>;`; + }; + function callbackInterface(it) { + return `callback ${interface_(it)}`; + }; + + const table = { + interface: interface_, + "interface mixin": interface_mixin, + namespace, + operation, + attribute, + dictionary, + field, + const: const_, + typedef, + implements: implements_, + includes, + callback, + enum: enum_, + iterable, + legacyiterable, + maplike, + setlike, + "callback interface": callbackInterface + }; + function dispatch(it) { + const dispatcher = table[it.type]; + if (!dispatcher) { + throw new Error(`Type "${it.type}" is unsupported`) + } + return table[it.type](it); + }; + function iterate(things) { + if (!things) return; + let ret = ""; + for (const thing of things) ret += dispatch(thing); + return ret; + }; + return iterate(ast); + }; + + + const obj = { + write + }; + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = obj; + } else if (typeof define === 'function' && define.amd) { + define([], () => obj); + } else { + (self || window).WebIDL2Writer = obj; + } +})(); diff --git a/test/fixtures/wpt/resources/webidl2/package-lock.json b/test/fixtures/wpt/resources/webidl2/package-lock.json new file mode 100644 index 00000000000000..b0581037fe9434 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/package-lock.json @@ -0,0 +1,700 @@ +{ + "name": "webidl2", + "version": "13.0.3", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz", + "integrity": "sha512-eVXQSbu/RimU6OKcK2/gDJVTFcxXJI4sHbIqw2mhwMZeQ2as/8AhS9DGkEDoHMBBNJZ5B0US63lF56x+KDcxiA==", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0-beta.40" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.40.tgz", + "integrity": "sha512-mOhhTrzieV6VO7odgzFGFapiwRK0ei8RZRhfzHhb6cpX3QM8XXuCLXWjN8qBB7JReDdUR80V3LFfFrGUYevhNg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-match-patch": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.0.tgz", + "integrity": "sha1-HMPIOkkNZ/ldkeOfatHy4Ia2MEg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + } + }, + "expect": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-22.4.0.tgz", + "integrity": "sha512-Fiy862jT3qc70hwIHwwCBNISmaqBrfWKKrtqyMJ6iwZr+6KXtcnHojZFtd63TPRvRl8EQTJ+YXYy2lK6/6u+Hw==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "jest-diff": "^22.4.0", + "jest-get-type": "^22.1.0", + "jest-matcher-utils": "^22.4.0", + "jest-message-util": "^22.4.0", + "jest-regex-util": "^22.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "jest-diff": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.4.0.tgz", + "integrity": "sha512-+/t20WmnkOkB8MOaGaPziI8zWKxquMvYw4Ub+wOzi7AUhmpFXz43buWSxVoZo4J5RnCozpGbX3/FssjJ5KV9Nw==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff": "^3.2.0", + "jest-get-type": "^22.1.0", + "pretty-format": "^22.4.0" + } + }, + "jest-get-type": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.1.0.tgz", + "integrity": "sha512-nD97IVOlNP6fjIN5i7j5XRH+hFsHL7VlauBbzRvueaaUe70uohrkz7pL/N8lx/IAwZRTJ//wOdVgh85OgM7g3w==", + "dev": true + }, + "jest-matcher-utils": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.4.0.tgz", + "integrity": "sha512-03m3issxUXpWMwDYTfmL8hRNewUB0yCRTeXPm+eq058rZxLHD9f5NtSSO98CWHqe4UyISIxd9Ao9iDVjHWd2qg==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-get-type": "^22.1.0", + "pretty-format": "^22.4.0" + } + }, + "jest-message-util": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.0.tgz", + "integrity": "sha512-eyCJB0T3hrlpFF2FqQoIB093OulP+1qvATQmD3IOgJgMGqPL6eYw8TbC5P/VCWPqKhGL51xvjIIhow5eZ2wHFw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0-beta.35", + "chalk": "^2.0.1", + "micromatch": "^2.3.11", + "slash": "^1.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-regex-util": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.1.0.tgz", + "integrity": "sha512-on0LqVS6Xeh69sw3d1RukVnur+lVOl3zkmb0Q54FHj9wHoq6dbtWqb3TSlnVUyx36hqjJhjgs/QLqs07Bzu72Q==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "jsondiffpatch": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.3.5.tgz", + "integrity": "sha512-v7eaGLDMCHXH+fsIaZhptEUJmS8EJpunq7IM4cc4vIT/kSRAkaZ6ZF4ebiNcyUelL0znbvj6o2B5Gh9v7Og0BQ==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "diff-match-patch": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.4.tgz", + "integrity": "sha512-nMOpAPFosU1B4Ix1jdhx5e3q7XO55ic5a8cgYvW27CequcEY+BabS0kUVL1Cw1V5PuVHZWeNRWFLmEPexo79VA==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-format": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.0.tgz", + "integrity": "sha512-pvCxP2iODIIk9adXlo4S3GRj0BrJiil68kByAa1PrgG97c1tClh9dLMgp3Z6cHFZrclaABt0UH8PIhwHuFLqYA==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "randomatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", + "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/test/fixtures/wpt/resources/webidl2/package.json b/test/fixtures/wpt/resources/webidl2/package.json new file mode 100644 index 00000000000000..92faccafa813fb --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/package.json @@ -0,0 +1,27 @@ +{ + "name": "webidl2", + "description": "A WebIDL Parser", + "version": "13.0.3", + "contributors": [ + "Robin Berjon (https://berjon.com)", + "Marcos Caceres (https://marcosc.com)", + "Kagami Sascha Rosylight ", + "Timothy Gu " + ], + "license": "W3C", + "dependencies": {}, + "devDependencies": { + "expect": "22.4.0", + "jsondiffpatch": "0.3.5", + "mocha": "5.0.4" + }, + "scripts": { + "test": "mocha", + "acquire": "node test/util/acquire.js" + }, + "repository": "git://github.com/w3c/webidl2.js", + "main": "index.js", + "files": [ + "lib/*" + ] +} diff --git a/test/fixtures/wpt/url/META.yml b/test/fixtures/wpt/url/META.yml new file mode 100644 index 00000000000000..3a789a0d513f0a --- /dev/null +++ b/test/fixtures/wpt/url/META.yml @@ -0,0 +1,8 @@ +spec: https://url.spec.whatwg.org/ +suggested_reviewers: + - mikewest + - domenic + - Sebmaster + - annevk + - GPHemsley + - TimothyGu diff --git a/test/fixtures/wpt/url/README.md b/test/fixtures/wpt/url/README.md new file mode 100644 index 00000000000000..823a8eec022282 --- /dev/null +++ b/test/fixtures/wpt/url/README.md @@ -0,0 +1,53 @@ +## urltestdata.json + +These tests are for browsers, but the data for +`a-element.html`, `url-constructor.html`, `a-element-xhtml.xhtml`, and `failure.html` +is in `resources/urltestdata.json` and can be re-used by non-browser implementations. +This file contains a JSON array of comments as strings and test cases as objects. +The keys for each test case are: + +* `base`: an absolute URL as a string whose [parsing] without a base of its own must succeed. + This key is always present, + and may have a value like `"about:blank"` when `input` is an absolute URL. +* `input`: an URL as a string to be [parsed][parsing] with `base` as its base URL. +* Either: + * `failure` with the value `true`, indicating that parsing `input` should return failure, + * or `href`, `origin`, `protocol`, `username`, `password`, `host`, `hostname`, `port`, + `pathname`, `search`, and `hash` with string values; + indicating that parsing `input` should return an URL record + and that the getters of each corresponding attribute in that URL’s [API] + should return the corresponding value. + + The `origin` key may be missing. + In that case, the API’s `origin` attribute is not tested. + +In addition to testing that parsing `input` against `base` gives the result, a test harness for the +`URL` constructor (or similar APIs) should additionally test the following pattern: if `failure` is +true, parsing `about:blank` against `input` must give failure. This tests that the logic for +converting base URLs into strings properly fails the whole parsing algorithm if the base URL cannot +be parsed. + +## setters_tests.json + +`resources/setters_tests.json` is self-documented. + +## toascii.json + +`resources/toascii.json` is a JSON resource containing an array where each item is an object +consisting of an optional `comment` field and mandatory `input` and `output` fields. `input` is the +domain to be parsed according to the rules of UTS #46 (as stipulated by the URL Standard). `output` +gives the expected output of the parser after serialization. An `output` of `null` means parsing is +expected to fail. + +## URL parser's encoding argument + +Tests in `/encoding` and `/html/infrastructure/urls/resolving-urls/query-encoding/` cover the +encoding argument to the URL parser. + +## Specification + +The tests in this directory assert conformance with [the URL Standard][URL]. + +[parsing]: https://url.spec.whatwg.org/#concept-basic-url-parser +[API]: https://url.spec.whatwg.org/#api +[URL]: https://url.spec.whatwg.org/ diff --git a/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml b/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml new file mode 100644 index 00000000000000..effcf04bee3fb0 --- /dev/null +++ b/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml @@ -0,0 +1,15 @@ + + + + + URL Test + + + + + +
+ + + + diff --git a/test/fixtures/wpt/url/a-element-origin.html b/test/fixtures/wpt/url/a-element-origin.html new file mode 100644 index 00000000000000..9cc8e94cbed060 --- /dev/null +++ b/test/fixtures/wpt/url/a-element-origin.html @@ -0,0 +1,8 @@ + + + + + +
+ + diff --git a/test/fixtures/wpt/url/a-element-xhtml.xhtml b/test/fixtures/wpt/url/a-element-xhtml.xhtml new file mode 100644 index 00000000000000..c6c67cf3ce619b --- /dev/null +++ b/test/fixtures/wpt/url/a-element-xhtml.xhtml @@ -0,0 +1,15 @@ + + + + + URL Test + + + + + +
+ + + + diff --git a/test/fixtures/wpt/url/a-element.html b/test/fixtures/wpt/url/a-element.html new file mode 100644 index 00000000000000..05c37f30b71e12 --- /dev/null +++ b/test/fixtures/wpt/url/a-element.html @@ -0,0 +1,8 @@ + + + + + +
+ + diff --git a/test/fixtures/wpt/url/data-uri-fragment.html b/test/fixtures/wpt/url/data-uri-fragment.html new file mode 100644 index 00000000000000..e77d96f03d821d --- /dev/null +++ b/test/fixtures/wpt/url/data-uri-fragment.html @@ -0,0 +1,34 @@ + + +Data URI parsing of fragments + + + + + + + + + diff --git a/test/fixtures/wpt/url/failure.html b/test/fixtures/wpt/url/failure.html new file mode 100644 index 00000000000000..13a90cc8d097c1 --- /dev/null +++ b/test/fixtures/wpt/url/failure.html @@ -0,0 +1,48 @@ + + +Test URL parser failure consistency + + +
+ + diff --git a/test/fixtures/wpt/url/historical.any.js b/test/fixtures/wpt/url/historical.any.js new file mode 100644 index 00000000000000..c3797ad263850c --- /dev/null +++ b/test/fixtures/wpt/url/historical.any.js @@ -0,0 +1,29 @@ +test(function() { + assert_false("searchParams" in self.location, + "location object should not have a searchParams attribute"); +}, "searchParams on location object"); + +if(self.GLOBAL.isWindow()) { + test(() => { + assert_false("searchParams" in document.createElement("a")) + assert_false("searchParams" in document.createElement("area")) + }, " and .searchParams should be undefined"); +} + +test(function() { + var url = new URL("./foo", "http://www.example.org"); + assert_equals(url.href, "http://www.example.org/foo"); + assert_throws(new TypeError(), function() { + url.href = "./bar"; + }); +}, "Setting URL's href attribute and base URLs"); + +test(function() { + assert_equals(URL.domainToASCII, undefined); +}, "URL.domainToASCII should be undefined"); + +test(function() { + assert_equals(URL.domainToUnicode, undefined); +}, "URL.domainToUnicode should be undefined"); + +done(); diff --git a/test/fixtures/wpt/url/idlharness.any.js b/test/fixtures/wpt/url/idlharness.any.js new file mode 100644 index 00000000000000..4a0e52f12b3c32 --- /dev/null +++ b/test/fixtures/wpt/url/idlharness.any.js @@ -0,0 +1,13 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +idl_test( + ['url'], + [], // no deps + idl_array => { + idl_array.add_objects({ + URL: ['new URL("http://foo")'], + URLSearchParams: ['new URLSearchParams("hi=there&thank=you")'] + }); + } +); diff --git a/test/fixtures/wpt/url/resources/a-element-origin.js b/test/fixtures/wpt/url/resources/a-element-origin.js new file mode 100644 index 00000000000000..3b8cb1cbbe7c75 --- /dev/null +++ b/test/fixtures/wpt/url/resources/a-element-origin.js @@ -0,0 +1,25 @@ +promise_test(() => fetch("resources/urltestdata.json").then(res => res.json()).then(runURLTests), "Loading data…"); + +function setBase(base) { + document.getElementById("base").href = base +} + +function bURL(url, base) { + base = base || "about:blank" + setBase(base) + var a = document.createElement("a") + a.setAttribute("href", url) + return a +} + +function runURLTests(urltests) { + for(var i = 0, l = urltests.length; i < l; i++) { + var expected = urltests[i] + if (typeof expected === "string" || !("origin" in expected)) continue + + test(function() { + var url = bURL(expected.input, expected.base) + assert_equals(url.origin, expected.origin, "origin") + }, "Parsing origin: <" + expected.input + "> against <" + expected.base + ">") + } +} diff --git a/test/fixtures/wpt/url/resources/a-element.js b/test/fixtures/wpt/url/resources/a-element.js new file mode 100644 index 00000000000000..f64531bc8bd528 --- /dev/null +++ b/test/fixtures/wpt/url/resources/a-element.js @@ -0,0 +1,42 @@ +promise_test(() => fetch("resources/urltestdata.json").then(res => res.json()).then(runURLTests), "Loading data…"); + +function setBase(base) { + document.getElementById("base").href = base +} + +function bURL(url, base) { + base = base || "about:blank" + setBase(base) + var a = document.createElement("a") + a.setAttribute("href", url) + return a +} + +function runURLTests(urltests) { + for(var i = 0, l = urltests.length; i < l; i++) { + var expected = urltests[i] + if (typeof expected === "string") continue // skip comments + + test(function() { + var url = bURL(expected.input, expected.base) + if(expected.failure) { + if(url.protocol !== ':') { + assert_unreached("Expected URL to fail parsing") + } + assert_equals(url.href, expected.input, "failure should set href to input") + return + } + + assert_equals(url.href, expected.href, "href") + assert_equals(url.protocol, expected.protocol, "protocol") + assert_equals(url.username, expected.username, "username") + assert_equals(url.password, expected.password, "password") + assert_equals(url.host, expected.host, "host") + assert_equals(url.hostname, expected.hostname, "hostname") + assert_equals(url.port, expected.port, "port") + assert_equals(url.pathname, expected.pathname, "pathname") + assert_equals(url.search, expected.search, "search") + assert_equals(url.hash, expected.hash, "hash") + }, "Parsing: <" + expected.input + "> against <" + expected.base + ">") + } +} diff --git a/test/fixtures/url-setter-tests.js b/test/fixtures/wpt/url/resources/setters_tests.json similarity index 99% rename from test/fixtures/url-setter-tests.js rename to test/fixtures/wpt/url/resources/setters_tests.json index 1e460ff2d8dd7c..db23d924732800 100644 --- a/test/fixtures/url-setter-tests.js +++ b/test/fixtures/wpt/url/resources/setters_tests.json @@ -1,11 +1,3 @@ -'use strict'; - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/f0fe479/url/setters_tests.json - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -module.exports = { "comment": [ "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members", diff --git a/test/fixtures/url-toascii.js b/test/fixtures/wpt/url/resources/toascii.json similarity index 94% rename from test/fixtures/url-toascii.js rename to test/fixtures/wpt/url/resources/toascii.json index 59b76330f867f2..814f06e794866d 100644 --- a/test/fixtures/url-toascii.js +++ b/test/fixtures/wpt/url/resources/toascii.json @@ -1,11 +1,3 @@ -'use strict'; - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/4839a0a804/url/toascii.json - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -module.exports = [ "This resource is focused on highlighting issues with UTS #46 ToASCII", { diff --git a/test/fixtures/url-tests.js b/test/fixtures/wpt/url/resources/urltestdata.json similarity index 99% rename from test/fixtures/url-tests.js rename to test/fixtures/wpt/url/resources/urltestdata.json index be0365edae7c72..26b8ea2e0bc9a1 100644 --- a/test/fixtures/url-tests.js +++ b/test/fixtures/wpt/url/resources/urltestdata.json @@ -1,11 +1,3 @@ -'use strict'; - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/web-platform-tests/wpt/blob/ba4921d054/url/resources/urltestdata.json - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -module.exports = [ "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js", { @@ -1441,6 +1433,22 @@ module.exports = "search": "", "hash": "" }, + "# Based on https://felixfbecker.github.io/whatwg-url-custom-host-repro/", + { + "input": "ssh://example.com/foo/bar.git", + "base": "http://example.org/", + "href": "ssh://example.com/foo/bar.git", + "origin": "null", + "protocol": "ssh:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/bar.git", + "search": "", + "hash": "" + }, "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html", { "input": "file:c:\\foo\\bar.html", diff --git a/test/fixtures/wpt/url/toascii.window.js b/test/fixtures/wpt/url/toascii.window.js new file mode 100644 index 00000000000000..b28c664479a26a --- /dev/null +++ b/test/fixtures/wpt/url/toascii.window.js @@ -0,0 +1,54 @@ +promise_test(() => fetch("resources/toascii.json").then(res => res.json()).then(runTests), "Loading data…"); + +function makeURL(type, input) { + input = "https://" + input + "/x" + if(type === "url") { + return new URL(input) + } else { + const url = document.createElement(type) + url.href = input + return url + } +} + +function runTests(tests) { + for(var i = 0, l = tests.length; i < l; i++) { + let hostTest = tests[i] + if (typeof hostTest === "string") { + continue // skip comments + } + const typeName = { "url": "URL", "a": "", "area": "" } + ;["url", "a", "area"].forEach((type) => { + test(() => { + if(hostTest.output !== null) { + const url = makeURL("url", hostTest.input) + assert_equals(url.host, hostTest.output) + assert_equals(url.hostname, hostTest.output) + assert_equals(url.pathname, "/x") + assert_equals(url.href, "https://" + hostTest.output + "/x") + } else { + if(type === "url") { + assert_throws(new TypeError, () => makeURL("url", hostTest.input)) + } else { + const url = makeURL(type, hostTest.input) + assert_equals(url.host, "") + assert_equals(url.hostname, "") + assert_equals(url.pathname, "") + assert_equals(url.href, "https://" + hostTest.input + "/x") + } + } + }, hostTest.input + " (using " + typeName[type] + ")") + ;["host", "hostname"].forEach((val) => { + test(() => { + const url = makeURL(type, "x") + url[val] = hostTest.input + if(hostTest.output !== null) { + assert_equals(url[val], hostTest.output) + } else { + assert_equals(url[val], "x") + } + }, hostTest.input + " (using " + typeName[type] + "." + val + ")") + }) + }) + } +} diff --git a/test/fixtures/wpt/url/url-constructor.html b/test/fixtures/wpt/url/url-constructor.html new file mode 100644 index 00000000000000..cb4c0db3571d2f --- /dev/null +++ b/test/fixtures/wpt/url/url-constructor.html @@ -0,0 +1,44 @@ + + + + +
+ diff --git a/test/fixtures/wpt/url/url-origin.html b/test/fixtures/wpt/url/url-origin.html new file mode 100644 index 00000000000000..fccb643ed6c806 --- /dev/null +++ b/test/fixtures/wpt/url/url-origin.html @@ -0,0 +1,24 @@ + + + + +
+ diff --git a/test/fixtures/wpt/url/url-searchparams.any.js b/test/fixtures/wpt/url/url-searchparams.any.js new file mode 100644 index 00000000000000..c55ae58d3b1e5b --- /dev/null +++ b/test/fixtures/wpt/url/url-searchparams.any.js @@ -0,0 +1,72 @@ +function bURL(url, base) { + return new URL(url, base || "about:blank") +} + +function runURLSearchParamTests() { + test(function() { + var url = bURL('http://example.org/?a=b') + assert_true("searchParams" in url) + var searchParams = url.searchParams + assert_true(url.searchParams === searchParams, 'Object identity should hold.') + }, 'URL.searchParams getter') + + test(function() { + var url = bURL('http://example.org/?a=b') + assert_true("searchParams" in url) + var searchParams = url.searchParams + assert_equals(searchParams.toString(), 'a=b') + + searchParams.set('a', 'b') + assert_equals(url.searchParams.toString(), 'a=b') + assert_equals(url.search, '?a=b') + url.search = '' + assert_equals(url.searchParams.toString(), '') + assert_equals(url.search, '') + assert_equals(searchParams.toString(), '') + }, 'URL.searchParams updating, clearing') + + test(function() { + 'use strict' + var urlString = 'http://example.org' + var url = bURL(urlString) + assert_throws(TypeError(), function() { url.searchParams = new URLSearchParams(urlString) }) + }, 'URL.searchParams setter, invalid values') + + test(function() { + var url = bURL('http://example.org/file?a=b&c=d') + assert_true("searchParams" in url) + var searchParams = url.searchParams + assert_equals(url.search, '?a=b&c=d') + assert_equals(searchParams.toString(), 'a=b&c=d') + + // Test that setting 'search' propagates to the URL object's query object. + url.search = 'e=f&g=h' + assert_equals(url.search, '?e=f&g=h') + assert_equals(searchParams.toString(), 'e=f&g=h') + + // ..and same but with a leading '?'. + url.search = '?e=f&g=h' + assert_equals(url.search, '?e=f&g=h') + assert_equals(searchParams.toString(), 'e=f&g=h') + + // And in the other direction, altering searchParams propagates + // back to 'search'. + searchParams.append('i', ' j ') + assert_equals(url.search, '?e=f&g=h&i=+j+') + assert_equals(url.searchParams.toString(), 'e=f&g=h&i=+j+') + assert_equals(searchParams.get('i'), ' j ') + + searchParams.set('e', 'updated') + assert_equals(url.search, '?e=updated&g=h&i=+j+') + assert_equals(searchParams.get('e'), 'updated') + + var url2 = bURL('http://example.org/file??a=b&c=d') + assert_equals(url2.search, '??a=b&c=d') + assert_equals(url2.searchParams.toString(), '%3Fa=b&c=d') + + url2.href = 'http://example.org/file??a=b' + assert_equals(url2.search, '??a=b') + assert_equals(url2.searchParams.toString(), '%3Fa=b') + }, 'URL.searchParams and URL.search setters, update propagation') +} +runURLSearchParamTests() diff --git a/test/fixtures/wpt/url/url-setters.html b/test/fixtures/wpt/url/url-setters.html new file mode 100644 index 00000000000000..db30cf0774da44 --- /dev/null +++ b/test/fixtures/wpt/url/url-setters.html @@ -0,0 +1,48 @@ + + + + +
+ diff --git a/test/fixtures/wpt/url/url-tojson.any.js b/test/fixtures/wpt/url/url-tojson.any.js new file mode 100644 index 00000000000000..65165f96c572d9 --- /dev/null +++ b/test/fixtures/wpt/url/url-tojson.any.js @@ -0,0 +1,4 @@ +test(() => { + const a = new URL("https://example.com/") + assert_equals(JSON.stringify(a), "\"https://example.com/\"") +}) diff --git a/test/fixtures/wpt/url/urlencoded-parser.any.js b/test/fixtures/wpt/url/urlencoded-parser.any.js new file mode 100644 index 00000000000000..65e894b94c26b0 --- /dev/null +++ b/test/fixtures/wpt/url/urlencoded-parser.any.js @@ -0,0 +1,63 @@ +[ + { "input": "test", "output": [["test", ""]] }, + { "input": "\uFEFFtest=\uFEFF", "output": [["\uFEFFtest", "\uFEFF"]] }, + { "input": "%EF%BB%BFtest=%EF%BB%BF", "output": [["\uFEFFtest", "\uFEFF"]] }, + { "input": "%FE%FF", "output": [["\uFFFD\uFFFD", ""]] }, + { "input": "%FF%FE", "output": [["\uFFFD\uFFFD", ""]] }, + { "input": "†&†=x", "output": [["†", ""], ["†", "x"]] }, + { "input": "%C2", "output": [["\uFFFD", ""]] }, + { "input": "%C2x", "output": [["\uFFFDx", ""]] }, + { "input": "_charset_=windows-1252&test=%C2x", "output": [["_charset_", "windows-1252"], ["test", "\uFFFDx"]] }, + { "input": '', "output": [] }, + { "input": 'a', "output": [['a', '']] }, + { "input": 'a=b', "output": [['a', 'b']] }, + { "input": 'a=', "output": [['a', '']] }, + { "input": '=b', "output": [['', 'b']] }, + { "input": '&', "output": [] }, + { "input": '&a', "output": [['a', '']] }, + { "input": 'a&', "output": [['a', '']] }, + { "input": 'a&a', "output": [['a', ''], ['a', '']] }, + { "input": 'a&b&c', "output": [['a', ''], ['b', ''], ['c', '']] }, + { "input": 'a=b&c=d', "output": [['a', 'b'], ['c', 'd']] }, + { "input": 'a=b&c=d&', "output": [['a', 'b'], ['c', 'd']] }, + { "input": '&&&a=b&&&&c=d&', "output": [['a', 'b'], ['c', 'd']] }, + { "input": 'a=a&a=b&a=c', "output": [['a', 'a'], ['a', 'b'], ['a', 'c']] }, + { "input": 'a==a', "output": [['a', '=a']] }, + { "input": 'a=a+b+c+d', "output": [['a', 'a b c d']] }, + { "input": '%=a', "output": [['%', 'a']] }, + { "input": '%a=a', "output": [['%a', 'a']] }, + { "input": '%a_=a', "output": [['%a_', 'a']] }, + { "input": '%61=a', "output": [['a', 'a']] }, + { "input": '%61+%4d%4D=', "output": [['a MM', '']] } +].forEach((val) => { + test(() => { + let sp = new URLSearchParams(val.input), + i = 0 + for (let item of sp) { + assert_array_equals(item, val.output[i]) + i++ + } + }, "URLSearchParams constructed with: " + val.input) + + promise_test(() => { + let init = new Request("about:blank", { body: val.input, method: "LADIDA", headers: {"Content-Type": "application/x-www-form-urlencoded;charset=windows-1252"} }).formData() + return init.then((fd) => { + let i = 0 + for (let item of fd) { + assert_array_equals(item, val.output[i]) + i++ + } + }) + }, "request.formData() with input: " + val.input) + + promise_test(() => { + let init = new Response(val.input, { headers: {"Content-Type": "application/x-www-form-urlencoded;charset=shift_jis"} }).formData() + return init.then((fd) => { + let i = 0 + for (let item of fd) { + assert_array_equals(item, val.output[i]) + i++ + } + }) + }, "response.formData() with input: " + val.input) +}); diff --git a/test/parallel/test-whatwg-url-searchparams-append.js b/test/fixtures/wpt/url/urlsearchparams-append.any.js similarity index 75% rename from test/parallel/test-whatwg-url-searchparams-append.js rename to test/fixtures/wpt/url/urlsearchparams-append.any.js index 342cbd53357986..5a7376144d0637 100644 --- a/test/parallel/test-whatwg-url-searchparams-append.js +++ b/test/fixtures/wpt/url/urlsearchparams-append.any.js @@ -1,15 +1,3 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-append.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ test(function() { var params = new URLSearchParams(); params.append('a', 'b'); @@ -19,6 +7,7 @@ test(function() { params.append('a', 'c'); assert_equals(params + '', 'a=b&a=b&a=c'); }, 'Append same name'); + test(function() { var params = new URLSearchParams(); params.append('', ''); @@ -26,6 +15,7 @@ test(function() { params.append('', ''); assert_equals(params + '', '=&='); }, 'Append empty strings'); + test(function() { var params = new URLSearchParams(); params.append(null, null); @@ -33,6 +23,7 @@ test(function() { params.append(null, null); assert_equals(params + '', 'null=null&null=null'); }, 'Append null'); + test(function() { var params = new URLSearchParams(); params.append('first', 1); @@ -46,4 +37,3 @@ test(function() { params.append('first', 10); assert_equals(params.get('first'), '1', 'Search params object has name "first" with value "1"'); }, 'Append multiple'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-constructor.js b/test/fixtures/wpt/url/urlsearchparams-constructor.any.js similarity index 81% rename from test/parallel/test-whatwg-url-searchparams-constructor.js rename to test/fixtures/wpt/url/urlsearchparams-constructor.any.js index 882072ba445fcb..6fff03f00fdddd 100644 --- a/test/parallel/test-whatwg-url-searchparams-constructor.js +++ b/test/fixtures/wpt/url/urlsearchparams-constructor.any.js @@ -1,19 +1,3 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { - test, assert_equals, assert_true, - assert_false, assert_throws, assert_array_equals -} = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/54c3502d7b/url/urlsearchparams-constructor.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -var params; // Strict mode fix for WPT. test(function() { var params = new URLSearchParams(); assert_equals(params + '', ''); @@ -30,19 +14,21 @@ test(function() { assert_equals(params.toString(), "") }, "URLSearchParams constructor, no arguments") -// test(() => { -// params = new URLSearchParams(DOMException.prototype); -// assert_equals(params.toString(), "INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21"A_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25") -// }, "URLSearchParams constructor, DOMException.prototype as argument") +test(() => { + var params = new URLSearchParams(DOMException); + assert_equals(params.toString(), "INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21"A_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25") + assert_throws(new TypeError(), () => new URLSearchParams(DOMException.prototype), + "Constructing a URLSearchParams from DOMException.prototype should throw due to branding checks"); +}, "URLSearchParams constructor, DOMException as argument") test(() => { - params = new URLSearchParams(''); + var params = new URLSearchParams(''); assert_true(params != null, 'constructor returned non-null value.'); assert_equals(params.__proto__, URLSearchParams.prototype, 'expected URLSearchParams.prototype as prototype.'); }, "URLSearchParams constructor, empty string as argument") test(() => { - params = new URLSearchParams({}); + var params = new URLSearchParams({}); assert_equals(params + '', ""); }, 'URLSearchParams constructor, {} as argument'); @@ -51,11 +37,13 @@ test(function() { assert_true(params != null, 'constructor returned non-null value.'); assert_true(params.has('a'), 'Search params object has name "a"'); assert_false(params.has('b'), 'Search params object has not got name "b"'); - var params = new URLSearchParams('a=b&c'); + + params = new URLSearchParams('a=b&c'); assert_true(params != null, 'constructor returned non-null value.'); assert_true(params.has('a'), 'Search params object has name "a"'); assert_true(params.has('c'), 'Search params object has name "c"'); - var params = new URLSearchParams('&a&&& &&&&&a+b=& c&m%c3%b8%c3%b8'); + + params = new URLSearchParams('&a&&& &&&&&a+b=& c&m%c3%b8%c3%b8'); assert_true(params != null, 'constructor returned non-null value.'); assert_true(params.has('a'), 'Search params object has name "a"'); assert_true(params.has('a b'), 'Search params object has name "a b"'); @@ -181,11 +169,10 @@ test(function() { }) test(() => { - params = new URLSearchParams() + var params = new URLSearchParams() params[Symbol.iterator] = function *() { yield ["a", "b"] } let params2 = new URLSearchParams(params) assert_equals(params2.get("a"), "b") }, "Custom [Symbol.iterator]") -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-delete.js b/test/fixtures/wpt/url/urlsearchparams-delete.any.js similarity index 79% rename from test/parallel/test-whatwg-url-searchparams-delete.js rename to test/fixtures/wpt/url/urlsearchparams-delete.any.js index cdf3332efc7807..1aa9b313736de2 100644 --- a/test/parallel/test-whatwg-url-searchparams-delete.js +++ b/test/fixtures/wpt/url/urlsearchparams-delete.any.js @@ -1,16 +1,3 @@ -'use strict'; - -require('../common'); -const { URL, URLSearchParams } = require('url'); -const { test, assert_equals, assert_true, assert_false } = - require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/70a0898763/url/urlsearchparams-delete.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ test(function() { var params = new URLSearchParams('a=b&c=d'); params.delete('a'); @@ -56,4 +43,3 @@ test(function() { assert_equals(url.href, 'http://example.com/', 'url.href does not have ?'); assert_equals(url.search, '', 'url.search does not have ?'); }, 'Removing non-existent param removes ? from URL'); -/* eslint-enable */ diff --git a/test/fixtures/wpt/url/urlsearchparams-foreach.any.js b/test/fixtures/wpt/url/urlsearchparams-foreach.any.js new file mode 100644 index 00000000000000..7969a0cb11a271 --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-foreach.any.js @@ -0,0 +1,76 @@ +test(function() { + var params = new URLSearchParams('a=1&b=2&c=3'); + var keys = []; + var values = []; + params.forEach(function(value, key) { + keys.push(key); + values.push(value); + }); + assert_array_equals(keys, ['a', 'b', 'c']); + assert_array_equals(values, ['1', '2', '3']); +}, "ForEach Check"); + +test(function() { + let a = new URL("http://a.b/c?a=1&b=2&c=3&d=4"); + let b = a.searchParams; + var c = []; + for (i of b) { + a.search = "x=1&y=2&z=3"; + c.push(i); + } + assert_array_equals(c[0], ["a","1"]); + assert_array_equals(c[1], ["y","2"]); + assert_array_equals(c[2], ["z","3"]); +}, "For-of Check"); + +test(function() { + let a = new URL("http://a.b/c"); + let b = a.searchParams; + for (i of b) { + assert_unreached(i); + } +}, "empty"); + +test(function() { + const url = new URL("http://localhost/query?param0=0¶m1=1¶m2=2"); + const searchParams = url.searchParams; + const seen = []; + for (param of searchParams) { + if (param[0] === 'param0') { + searchParams.delete('param1'); + } + seen.push(param); + } + + assert_array_equals(seen[0], ["param0", "0"]); + assert_array_equals(seen[1], ["param2", "2"]); +}, "delete next param during iteration"); + +test(function() { + const url = new URL("http://localhost/query?param0=0¶m1=1¶m2=2"); + const searchParams = url.searchParams; + const seen = []; + for (param of searchParams) { + if (param[0] === 'param0') { + searchParams.delete('param0'); + // 'param1=1' is now in the first slot, so the next iteration will see 'param2=2'. + } else { + seen.push(param); + } + } + + assert_array_equals(seen[0], ["param2", "2"]); +}, "delete current param during iteration"); + +test(function() { + const url = new URL("http://localhost/query?param0=0¶m1=1¶m2=2"); + const searchParams = url.searchParams; + const seen = []; + for (param of searchParams) { + seen.push(param[0]); + searchParams.delete(param[0]); + } + + assert_array_equals(seen, ["param0", "param2"], "param1 should not have been seen by the loop"); + assert_equals(String(searchParams), "param1=1", "param1 should remain"); +}, "delete every param seen during iteration"); diff --git a/test/parallel/test-whatwg-url-searchparams-get.js b/test/fixtures/wpt/url/urlsearchparams-get.any.js similarity index 68% rename from test/parallel/test-whatwg-url-searchparams-get.js rename to test/fixtures/wpt/url/urlsearchparams-get.any.js index 94e92c18e4b218..a2610fc933a772 100644 --- a/test/parallel/test-whatwg-url-searchparams-get.js +++ b/test/fixtures/wpt/url/urlsearchparams-get.any.js @@ -1,15 +1,3 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-get.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ test(function() { var params = new URLSearchParams('a=b&c=d'); assert_equals(params.get('a'), 'b'); @@ -31,4 +19,3 @@ test(function() { assert_equals(params.get('third'), '', 'Search params object has name "third" with the empty value.'); assert_equals(params.get('fourth'), null, 'Search params object has no "fourth" name and value.'); }, 'More get() basics'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-getall.js b/test/fixtures/wpt/url/urlsearchparams-getall.any.js similarity index 72% rename from test/parallel/test-whatwg-url-searchparams-getall.js rename to test/fixtures/wpt/url/urlsearchparams-getall.any.js index 06827f37d95bfe..5d1a35352acf2c 100644 --- a/test/parallel/test-whatwg-url-searchparams-getall.js +++ b/test/fixtures/wpt/url/urlsearchparams-getall.any.js @@ -1,16 +1,3 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true, assert_array_equals } = - require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-getall.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ test(function() { var params = new URLSearchParams('a=b&c=d'); assert_array_equals(params.getAll('a'), ['b']); @@ -36,4 +23,3 @@ test(function() { assert_true(matches && matches.length == 1, 'Search params object has values for name "a"'); assert_array_equals(matches, ['one'], 'Search params object has expected name "a" values'); }, 'getAll() multiples'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-has.js b/test/fixtures/wpt/url/urlsearchparams-has.any.js similarity index 67% rename from test/parallel/test-whatwg-url-searchparams-has.js rename to test/fixtures/wpt/url/urlsearchparams-has.any.js index 95e69beb4d26ec..673dce77dc44ab 100644 --- a/test/parallel/test-whatwg-url-searchparams-has.js +++ b/test/fixtures/wpt/url/urlsearchparams-has.any.js @@ -1,15 +1,3 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_false, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-has.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ test(function() { var params = new URLSearchParams('a=b&c=d'); assert_true(params.has('a')); @@ -34,4 +22,3 @@ test(function() { params.delete('first'); assert_false(params.has('first'), 'Search params object has no name "first"'); }, 'has() following delete()'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-set.js b/test/fixtures/wpt/url/urlsearchparams-set.any.js similarity index 67% rename from test/parallel/test-whatwg-url-searchparams-set.js rename to test/fixtures/wpt/url/urlsearchparams-set.any.js index 0d43678427c23f..eb24cac87b6dca 100644 --- a/test/parallel/test-whatwg-url-searchparams-set.js +++ b/test/fixtures/wpt/url/urlsearchparams-set.any.js @@ -1,15 +1,3 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-set.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ test(function() { var params = new URLSearchParams('a=b&c=d'); params.set('a', 'B'); @@ -32,4 +20,3 @@ test(function() { assert_true(params.has('a'), 'Search params object has name "a"'); assert_equals(params.get('a'), '4', 'Search params object has name "a" with value "4"'); }, 'URLSearchParams.set'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-sort.js b/test/fixtures/wpt/url/urlsearchparams-sort.any.js similarity index 68% rename from test/parallel/test-whatwg-url-searchparams-sort.js rename to test/fixtures/wpt/url/urlsearchparams-sort.any.js index 65dd23a6daba57..4fd8cef69239d2 100644 --- a/test/parallel/test-whatwg-url-searchparams-sort.js +++ b/test/fixtures/wpt/url/urlsearchparams-sort.any.js @@ -1,15 +1,3 @@ -'use strict'; - -require('../common'); -const { URL, URLSearchParams } = require('url'); -const { test, assert_equals, assert_array_equals } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/70a0898763/url/urlsearchparams-sort.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ [ { "input": "z=b&a=b&z=a&a=a", @@ -30,6 +18,18 @@ const { test, assert_equals, assert_array_equals } = require('../common/wpt'); { "input": "z=z&a=a&z=y&a=b&z=x&a=c&z=w&a=d&z=v&a=e&z=u&a=f&z=t&a=g", "output": [["a", "a"], ["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"], ["a", "g"], ["z", "z"], ["z", "y"], ["z", "x"], ["z", "w"], ["z", "v"], ["z", "u"], ["z", "t"]] + }, + { + "input": "bbb&bb&aaa&aa=x&aa=y", + "output": [["aa", "x"], ["aa", "y"], ["aaa", ""], ["bb", ""], ["bbb", ""]] + }, + { + "input": "z=z&=f&=t&=x", + "output": [["", "f"], ["", "t"], ["", "x"], ["z", "z"]] + }, + { + "input": "a🌈&a💩", + "output": [["a🌈", ""], ["a💩", ""]] } ].forEach((val) => { test(() => { @@ -40,10 +40,10 @@ const { test, assert_equals, assert_array_equals } = require('../common/wpt'); assert_array_equals(param, val.output[i]) i++ } - }, `Parse and sort: ${val.input}`) + }, "Parse and sort: " + val.input) test(() => { - let url = new URL(`?${val.input}`, "https://example/") + let url = new URL("?" + val.input, "https://example/") url.searchParams.sort() let params = new URLSearchParams(url.search), i = 0 @@ -51,7 +51,7 @@ const { test, assert_equals, assert_array_equals } = require('../common/wpt'); assert_array_equals(param, val.output[i]) i++ } - }, `URL parse and sort: ${val.input}`) + }, "URL parse and sort: " + val.input) }) test(function() { @@ -60,4 +60,3 @@ test(function() { assert_equals(url.href, "http://example.com/") assert_equals(url.search, "") }, "Sorting non-existent params removes ? from URL") -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-stringifier.js b/test/fixtures/wpt/url/urlsearchparams-stringifier.any.js similarity index 87% rename from test/parallel/test-whatwg-url-searchparams-stringifier.js rename to test/fixtures/wpt/url/urlsearchparams-stringifier.any.js index e2b6faaabe85fc..ef95c1434c7964 100644 --- a/test/parallel/test-whatwg-url-searchparams-stringifier.js +++ b/test/fixtures/wpt/url/urlsearchparams-stringifier.any.js @@ -1,15 +1,3 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-stringifier.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ test(function() { var params = new URLSearchParams(); params.append('a', 'b c'); @@ -120,4 +108,16 @@ test(function() { params = new URLSearchParams('a=&a=b'); assert_equals(params.toString(), 'a=&a=b'); }, 'URLSearchParams.toString'); -/* eslint-enable */ + +test(() => { + const url = new URL('http://www.example.com/?a=b,c'); + const params = url.searchParams; + + assert_equals(url.toString(), 'http://www.example.com/?a=b,c'); + assert_equals(params.toString(), 'a=b%2Cc'); + + params.append('x', 'y'); + + assert_equals(url.toString(), 'http://www.example.com/?a=b%2Cc&x=y'); + assert_equals(params.toString(), 'a=b%2Cc&x=y'); +}, 'URLSearchParams connected to URL'); diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json new file mode 100644 index 00000000000000..9ce98bcbb8d7ba --- /dev/null +++ b/test/fixtures/wpt/versions.json @@ -0,0 +1,18 @@ +{ + "resources": { + "commit": "679a364421ce3704289df21e1ff985c14b360981", + "path": "resources" + }, + "interfaces": { + "commit": "db7f86289e47f0d124593cd27926529a6265ddb3", + "path": "interfaces" + }, + "console": { + "commit": "9786a4b1317c03b89ea3bf2e997f2e2b6a3690ae", + "path": "console" + }, + "url": { + "commit": "75b0f336c50105c6fea47ad253d57219dfa744d3", + "path": "url" + } +} \ No newline at end of file diff --git a/test/internet/test-dgram-broadcast-multi-process.js b/test/internet/test-dgram-broadcast-multi-process.js index c30059e739b687..a8d97869703e58 100644 --- a/test/internet/test-dgram-broadcast-multi-process.js +++ b/test/internet/test-dgram-broadcast-multi-process.js @@ -182,7 +182,7 @@ if (process.argv[2] !== 'child') { const buf = messages[i++]; if (!buf) { - try { sendSocket.close(); } catch (e) {} + try { sendSocket.close(); } catch {} return; } diff --git a/test/internet/test-dgram-multicast-multi-process.js b/test/internet/test-dgram-multicast-multi-process.js index e6e7a44fcd4de2..9d2e2c9f3ffd84 100644 --- a/test/internet/test-dgram-multicast-multi-process.js +++ b/test/internet/test-dgram-multicast-multi-process.js @@ -170,7 +170,7 @@ if (process.argv[2] !== 'child') { const buf = messages[i++]; if (!buf) { - try { sendSocket.close(); } catch (e) {} + try { sendSocket.close(); } catch {} return; } diff --git a/test/known_issues/known_issues.status b/test/known_issues/known_issues.status index 5a1ab289280d23..a1f66fc6d96fc2 100644 --- a/test/known_issues/known_issues.status +++ b/test/known_issues/known_issues.status @@ -9,9 +9,7 @@ prefix known_issues [$system==win32] [$system==linux] -test-vm-timeout-escape-nexttick: PASS,FLAKY test-vm-timeout-escape-promise: PASS,FLAKY -test-vm-timeout-escape-queuemicrotask: PASS,FLAKY [$system==macos] diff --git a/test/known_issues/test-module-deleted-extensions.js b/test/known_issues/test-module-deleted-extensions.js deleted file mode 100644 index 3a51e8725eec60..00000000000000 --- a/test/known_issues/test-module-deleted-extensions.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; -// Refs: https://github.com/nodejs/node/issues/4778 -const common = require('../common'); -const assert = require('assert'); -const fs = require('fs'); -const path = require('path'); -const tmpdir = require('../common/tmpdir'); -const file = path.join(tmpdir.path, 'test-extensions.foo.bar'); - -tmpdir.refresh(); -fs.writeFileSync(file, '', 'utf8'); -require.extensions['.foo.bar'] = (module, path) => {}; -delete require.extensions['.foo.bar']; -require.extensions['.bar'] = common.mustCall((module, path) => { - assert.strictEqual(module.id, file); - assert.strictEqual(path, file); -}); -require(path.join(tmpdir.path, 'test-extensions')); diff --git a/test/known_issues/test-url-parse-conformance.js b/test/known_issues/test-url-parse-conformance.js index 022a613a226549..7be8c16099df59 100644 --- a/test/known_issues/test-url-parse-conformance.js +++ b/test/known_issues/test-url-parse-conformance.js @@ -5,7 +5,9 @@ require('../common'); const url = require('url'); const assert = require('assert'); const fixtures = require('../common/fixtures'); -const tests = require(fixtures.path('url-tests')); +const tests = require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') +); let failed = 0; let attempted = 0; @@ -40,12 +42,12 @@ tests.forEach((test) => { assert.strictEqual(test.pathname, parsed.pathname || '/'); assert.strictEqual(test.search, parsed.search || ''); assert.strictEqual(test.hash, parsed.hash || ''); - } catch (err) { + } catch { // For now, we're just interested in the number of failures. failed++; } } - } catch (err) { + } catch { // If Parse failed and it wasn't supposed to, treat it as a failure. if (!test.failure) failed++; diff --git a/test/known_issues/test-vm-timeout-escape-nexttick.js b/test/known_issues/test-vm-timeout-escape-nexttick.js index 8afe2fb8cebb15..40937c96d91a69 100644 --- a/test/known_issues/test-vm-timeout-escape-nexttick.js +++ b/test/known_issues/test-vm-timeout-escape-nexttick.js @@ -4,7 +4,7 @@ // Promises, nextTick, and queueMicrotask allow code to escape the timeout // set for runInContext, runInNewContext, and runInThisContext -require('../common'); +const common = require('../common'); const assert = require('assert'); const vm = require('vm'); @@ -13,12 +13,14 @@ const NS_PER_MS = 1000000n; const hrtime = process.hrtime.bigint; const nextTick = process.nextTick; +const waitDuration = common.platformTimeout(100n); + function loop() { const start = hrtime(); while (1) { const current = hrtime(); const span = (current - start) / NS_PER_MS; - if (span >= 100n) { + if (span >= waitDuration) { throw new Error( `escaped timeout at ${span} milliseconds!`); } @@ -33,9 +35,8 @@ assert.throws(() => { nextTick, loop }, - { timeout: 5 } + { timeout: common.platformTimeout(10) } ); }, { - code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', - message: 'Script execution timed out after 5ms' + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT' }); diff --git a/test/known_issues/test-vm-timeout-escape-queuemicrotask.js b/test/known_issues/test-vm-timeout-escape-queuemicrotask.js index 8de33bc24ddcdc..1ed327f7793e7c 100644 --- a/test/known_issues/test-vm-timeout-escape-queuemicrotask.js +++ b/test/known_issues/test-vm-timeout-escape-queuemicrotask.js @@ -4,7 +4,7 @@ // Promises, nextTick, and queueMicrotask allow code to escape the timeout // set for runInContext, runInNewContext, and runInThisContext -require('../common'); +const common = require('../common'); const assert = require('assert'); const vm = require('vm'); @@ -32,7 +32,7 @@ assert.throws(() => { queueMicrotask, loop }, - { timeout: 5 } + { timeout: common.platformTimeout(5) } ); }, { code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', diff --git a/test/message/vm_dont_display_runtime_error.js b/test/message/vm_dont_display_runtime_error.js index e7c77081a597c6..72568a21c7c339 100644 --- a/test/message/vm_dont_display_runtime_error.js +++ b/test/message/vm_dont_display_runtime_error.js @@ -30,7 +30,7 @@ try { filename: 'test.vm', displayErrors: false }); -} catch (e) {} +} catch {} console.error('middle'); diff --git a/test/message/vm_dont_display_syntax_error.js b/test/message/vm_dont_display_syntax_error.js index f3965b33430e78..7e588c5095741a 100644 --- a/test/message/vm_dont_display_syntax_error.js +++ b/test/message/vm_dont_display_syntax_error.js @@ -30,7 +30,7 @@ try { filename: 'test.vm', displayErrors: false }); -} catch (e) {} +} catch {} console.error('middle'); diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index 3a5fca74d4c287..ddbc5e78eafcaf 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -915,6 +915,27 @@ assert.deepStrictEqual(obj1, obj2); ); } +// Strict equal with identical objects that are not identical +// by reference and longer than 30 elements +// E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) +{ + const a = {}; + const b = {}; + for (let i = 0; i < 35; i++) { + a[`symbol${i}`] = Symbol(); + b[`symbol${i}`] = Symbol(); + } + + assert.throws( + () => assert.deepStrictEqual(a, b), + { + code: 'ERR_ASSERTION', + name: 'AssertionError [ERR_ASSERTION]', + message: /\.\.\./g + } + ); +} + // Basic valueOf check. { const a = new String(1); diff --git a/test/parallel/test-assert-typedarray-deepequal.js b/test/parallel/test-assert-typedarray-deepequal.js index 78394bb91facde..1e9c8c8d1c247d 100644 --- a/test/parallel/test-assert-typedarray-deepequal.js +++ b/test/parallel/test-assert-typedarray-deepequal.js @@ -47,6 +47,7 @@ const notEqualArrayPairs = [ [new Int16Array([-256]), new Uint16Array([0xff00])], // same bits [new Int32Array([-256]), new Uint32Array([0xffffff00])], // ditto [new Float32Array([0.1]), new Float32Array([0.0])], + [new Float32Array([0.1]), new Float32Array([0.1, 0.2])], [new Float64Array([0.1]), new Float64Array([0.0])], [new Uint8Array([1, 2, 3]).buffer, new Uint8Array([4, 5, 6]).buffer], [ diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 8e6c2e52b5be55..695d890f4c5f6f 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -168,7 +168,7 @@ assert.throws( }, Array ); - } catch (e) { + } catch { threw = true; } assert.ok(threw, 'wrong constructor validation'); @@ -862,6 +862,14 @@ common.expectsError( }); { + + assert.throws(() => { + assert.ok((() => Boolean('' === false))()); + }, { + message: 'The expression evaluated to a falsy value:\n\n' + + " assert.ok((() => Boolean('\\u0001' === false))())\n" + }); + const errFn = () => { const err = new TypeError('Wrong value'); err.code = 404; diff --git a/test/parallel/test-async-wrap-pop-id-during-load.js b/test/parallel/test-async-wrap-pop-id-during-load.js index 31d2113eabc163..cff7e85fdffef4 100644 --- a/test/parallel/test-async-wrap-pop-id-during-load.js +++ b/test/parallel/test-async-wrap-pop-id-during-load.js @@ -16,7 +16,7 @@ const { spawnSync } = require('child_process'); const ret = spawnSync( process.execPath, - ['--stack_size=75', __filename, 'async'] + ['--stack_size=150', __filename, 'async'] ); assert.strictEqual(ret.status, 0, `EXIT CODE: ${ret.status}, STDERR:\n${ret.stderr}`); diff --git a/test/parallel/test-bash-completion.js b/test/parallel/test-bash-completion.js new file mode 100644 index 00000000000000..50378a7b0f8028 --- /dev/null +++ b/test/parallel/test-bash-completion.js @@ -0,0 +1,23 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const child_process = require('child_process'); + +const p = child_process.spawnSync( + process.execPath, [ '--completion-bash' ]); +assert.ifError(p.error); +assert.ok(p.stdout.toString().includes( + `_node_complete() { + local cur_word options + cur_word="\${COMP_WORDS[COMP_CWORD]}" + if [[ "\${cur_word}" == -* ]] ; then + COMPREPLY=( $(compgen -W '`)); +assert.ok(p.stdout.toString().includes( + `' -- "\${cur_word}") ) + return 0 + else + COMPREPLY=( $(compgen -f "\${cur_word}") ) + return 0 + fi +} +complete -F _node_complete node node_g`)); diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 885a58ff9f86fc..70011637e08af4 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -11,4 +11,4 @@ const list = process.moduleLoadList.slice(); const assert = require('assert'); -assert(list.length <= 77, list); +assert(list.length <= 78, list); diff --git a/test/parallel/test-buffer-copy.js b/test/parallel/test-buffer-copy.js index 8ede5101463b05..6fb6a4ec707ef0 100644 --- a/test/parallel/test-buffer-copy.js +++ b/test/parallel/test-buffer-copy.js @@ -1,10 +1,17 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const b = Buffer.allocUnsafe(1024); const c = Buffer.allocUnsafe(512); + +const errorProperty = { + code: 'ERR_OUT_OF_RANGE', + type: RangeError, + message: 'Index out of range' +}; + let cntr = 0; { @@ -96,9 +103,9 @@ bb.fill('hello crazy world'); b.copy(c, 0, 100, 10); // copy throws at negative sourceStart -assert.throws(function() { - Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1); -}, RangeError); +common.expectsError( + () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1), + errorProperty); { // check sourceEnd resets to targetEnd if former is greater than the latter @@ -111,7 +118,8 @@ assert.throws(function() { } // throw with negative sourceEnd -assert.throws(() => b.copy(c, 0, 0, -1), RangeError); +common.expectsError( + () => b.copy(c, 0, -1), errorProperty); // when sourceStart is greater than sourceEnd, zero copied assert.strictEqual(b.copy(c, 0, 100, 10), 0); diff --git a/test/parallel/test-buffer-fill.js b/test/parallel/test-buffer-fill.js index 6a0a8adb7ae2b9..61ff6bbb501f4d 100644 --- a/test/parallel/test-buffer-fill.js +++ b/test/parallel/test-buffer-fill.js @@ -303,19 +303,19 @@ Buffer.alloc(8, ''); buf.fill(0); for (let i = 0; i < buf.length; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); buf.fill(null); for (let i = 0; i < buf.length; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); buf.fill(1, 16, 32); for (let i = 0; i < 16; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); for (let i = 16; i < 32; i++) - assert.strictEqual(1, buf[i]); + assert.strictEqual(buf[i], 1); for (let i = 32; i < buf.length; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); } { diff --git a/test/parallel/test-buffer-indexof.js b/test/parallel/test-buffer-indexof.js index 357558c74d2edc..3647d115b0dc5b 100644 --- a/test/parallel/test-buffer-indexof.js +++ b/test/parallel/test-buffer-indexof.js @@ -183,24 +183,24 @@ assert.strictEqual(Buffer.from('aaaa00a').indexOf('3030', 'hex'), 4); // test usc2 encoding const twoByteString = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2'); - assert.strictEqual(8, twoByteString.indexOf('\u0395', 4, 'ucs2')); - assert.strictEqual(6, twoByteString.indexOf('\u03a3', -4, 'ucs2')); - assert.strictEqual(4, twoByteString.indexOf('\u03a3', -6, 'ucs2')); - assert.strictEqual(4, twoByteString.indexOf( - Buffer.from('\u03a3', 'ucs2'), -6, 'ucs2')); + assert.strictEqual(twoByteString.indexOf('\u0395', 4, 'ucs2'), 8); + assert.strictEqual(twoByteString.indexOf('\u03a3', -4, 'ucs2'), 6); + assert.strictEqual(twoByteString.indexOf('\u03a3', -6, 'ucs2'), 4); + assert.strictEqual(twoByteString.indexOf( + Buffer.from('\u03a3', 'ucs2'), -6, 'ucs2'), 4); assert.strictEqual(-1, twoByteString.indexOf('\u03a3', -2, 'ucs2')); } const mixedByteStringUcs2 = Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395', 'ucs2'); -assert.strictEqual(6, mixedByteStringUcs2.indexOf('bc', 0, 'ucs2')); -assert.strictEqual(10, mixedByteStringUcs2.indexOf('\u03a3', 0, 'ucs2')); +assert.strictEqual(mixedByteStringUcs2.indexOf('bc', 0, 'ucs2'), 6); +assert.strictEqual(mixedByteStringUcs2.indexOf('\u03a3', 0, 'ucs2'), 10); assert.strictEqual(-1, mixedByteStringUcs2.indexOf('\u0396', 0, 'ucs2')); assert.strictEqual( - 6, mixedByteStringUcs2.indexOf(Buffer.from('bc', 'ucs2'), 0, 'ucs2')); + mixedByteStringUcs2.indexOf(Buffer.from('bc', 'ucs2'), 0, 'ucs2'), 6); assert.strictEqual( - 10, mixedByteStringUcs2.indexOf(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2')); + mixedByteStringUcs2.indexOf(Buffer.from('\u03a3', 'ucs2'), 0, 'ucs2'), 10); assert.strictEqual( -1, mixedByteStringUcs2.indexOf(Buffer.from('\u0396', 'ucs2'), 0, 'ucs2')); @@ -208,34 +208,34 @@ assert.strictEqual( const twoByteString = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2'); // Test single char pattern - assert.strictEqual(0, twoByteString.indexOf('\u039a', 0, 'ucs2')); + assert.strictEqual(twoByteString.indexOf('\u039a', 0, 'ucs2'), 0); let index = twoByteString.indexOf('\u0391', 0, 'ucs2'); - assert.strictEqual(2, index, `Alpha - at index ${index}`); + assert.strictEqual(index, 2, `Alpha - at index ${index}`); index = twoByteString.indexOf('\u03a3', 0, 'ucs2'); - assert.strictEqual(4, index, `First Sigma - at index ${index}`); + assert.strictEqual(index, 4, `First Sigma - at index ${index}`); index = twoByteString.indexOf('\u03a3', 6, 'ucs2'); - assert.strictEqual(6, index, `Second Sigma - at index ${index}`); + assert.strictEqual(index, 6, `Second Sigma - at index ${index}`); index = twoByteString.indexOf('\u0395', 0, 'ucs2'); - assert.strictEqual(8, index, `Epsilon - at index ${index}`); + assert.strictEqual(index, 8, `Epsilon - at index ${index}`); index = twoByteString.indexOf('\u0392', 0, 'ucs2'); assert.strictEqual(-1, index, `Not beta - at index ${index}`); // Test multi-char pattern index = twoByteString.indexOf('\u039a\u0391', 0, 'ucs2'); - assert.strictEqual(0, index, `Lambda Alpha - at index ${index}`); + assert.strictEqual(index, 0, `Lambda Alpha - at index ${index}`); index = twoByteString.indexOf('\u0391\u03a3', 0, 'ucs2'); - assert.strictEqual(2, index, `Alpha Sigma - at index ${index}`); + assert.strictEqual(index, 2, `Alpha Sigma - at index ${index}`); index = twoByteString.indexOf('\u03a3\u03a3', 0, 'ucs2'); - assert.strictEqual(4, index, `Sigma Sigma - at index ${index}`); + assert.strictEqual(index, 4, `Sigma Sigma - at index ${index}`); index = twoByteString.indexOf('\u03a3\u0395', 0, 'ucs2'); - assert.strictEqual(6, index, `Sigma Epsilon - at index ${index}`); + assert.strictEqual(index, 6, `Sigma Epsilon - at index ${index}`); } const mixedByteStringUtf8 = Buffer.from('\u039a\u0391abc\u03a3\u03a3\u0395'); -assert.strictEqual(5, mixedByteStringUtf8.indexOf('bc')); -assert.strictEqual(5, mixedByteStringUtf8.indexOf('bc', 5)); -assert.strictEqual(5, mixedByteStringUtf8.indexOf('bc', -8)); -assert.strictEqual(7, mixedByteStringUtf8.indexOf('\u03a3')); +assert.strictEqual(mixedByteStringUtf8.indexOf('bc'), 5); +assert.strictEqual(mixedByteStringUtf8.indexOf('bc', 5), 5); +assert.strictEqual(mixedByteStringUtf8.indexOf('bc', -8), 5); +assert.strictEqual(mixedByteStringUtf8.indexOf('\u03a3'), 7); assert.strictEqual(-1, mixedByteStringUtf8.indexOf('\u0396')); @@ -257,22 +257,22 @@ for (let i = 0; i < longBufferString.length - pattern.length; i += 7) { } let index = longBufferString.indexOf('AJABACA'); -assert.strictEqual(510, index, `Long AJABACA, First J - at index ${index}`); +assert.strictEqual(index, 510, `Long AJABACA, First J - at index ${index}`); index = longBufferString.indexOf('AJABACA', 511); -assert.strictEqual(1534, index, `Long AJABACA, Second J - at index ${index}`); +assert.strictEqual(index, 1534, `Long AJABACA, Second J - at index ${index}`); pattern = 'JABACABADABACABA'; index = longBufferString.indexOf(pattern); -assert.strictEqual(511, index, `Long JABACABA..., First J - at index ${index}`); +assert.strictEqual(index, 511, `Long JABACABA..., First J - at index ${index}`); index = longBufferString.indexOf(pattern, 512); assert.strictEqual( - 1535, index, `Long JABACABA..., Second J - at index ${index}`); + index, 1535, `Long JABACABA..., Second J - at index ${index}`); // Search for a non-ASCII string in a pure ASCII string. const asciiString = Buffer.from( 'arglebargleglopglyfarglebargleglopglyfarglebargleglopglyf'); assert.strictEqual(-1, asciiString.indexOf('\x2061')); -assert.strictEqual(3, asciiString.indexOf('leb', 0)); +assert.strictEqual(asciiString.indexOf('leb', 0), 3); // Search in string containing many non-ASCII chars. const allCodePoints = []; @@ -505,20 +505,20 @@ assert.strictEqual(buf_bc.lastIndexOf(Buffer.from('你好'), 7), -1); // Test lastIndexOf on a longer buffer: const bufferString = Buffer.from('a man a plan a canal panama'); -assert.strictEqual(15, bufferString.lastIndexOf('canal')); -assert.strictEqual(21, bufferString.lastIndexOf('panama')); -assert.strictEqual(0, bufferString.lastIndexOf('a man a plan a canal panama')); +assert.strictEqual(bufferString.lastIndexOf('canal'), 15); +assert.strictEqual(bufferString.lastIndexOf('panama'), 21); +assert.strictEqual(bufferString.lastIndexOf('a man a plan a canal panama'), 0); assert.strictEqual(-1, bufferString.lastIndexOf('a man a plan a canal mexico')); assert.strictEqual(-1, bufferString .lastIndexOf('a man a plan a canal mexico city')); assert.strictEqual(-1, bufferString.lastIndexOf(Buffer.from('a'.repeat(1000)))); -assert.strictEqual(0, bufferString.lastIndexOf('a man a plan', 4)); -assert.strictEqual(13, bufferString.lastIndexOf('a ')); -assert.strictEqual(13, bufferString.lastIndexOf('a ', 13)); -assert.strictEqual(6, bufferString.lastIndexOf('a ', 12)); -assert.strictEqual(0, bufferString.lastIndexOf('a ', 5)); -assert.strictEqual(13, bufferString.lastIndexOf('a ', -1)); -assert.strictEqual(0, bufferString.lastIndexOf('a ', -27)); +assert.strictEqual(bufferString.lastIndexOf('a man a plan', 4), 0); +assert.strictEqual(bufferString.lastIndexOf('a '), 13); +assert.strictEqual(bufferString.lastIndexOf('a ', 13), 13); +assert.strictEqual(bufferString.lastIndexOf('a ', 12), 6); +assert.strictEqual(bufferString.lastIndexOf('a ', 5), 0); +assert.strictEqual(bufferString.lastIndexOf('a ', -1), 13); +assert.strictEqual(bufferString.lastIndexOf('a ', -27), 0); assert.strictEqual(-1, bufferString.lastIndexOf('a ', -28)); // Test lastIndexOf for the case that the first character can be found, @@ -534,18 +534,18 @@ assert.strictEqual(-1, Buffer.from('bc').lastIndexOf(Buffer.from('ab'))); assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf('ab', 'ucs2')); assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf(abInUCS2)); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab')); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 1)); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 2)); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 3)); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab'), 0); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 1), 0); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 2), 0); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 3), 0); // The above tests test the LINEAR and SINGLE-CHAR strategies. // Now, we test the BOYER-MOORE-HORSPOOL strategy. // Test lastIndexOf on a long buffer w multiple matches: pattern = 'JABACABADABACABA'; -assert.strictEqual(1535, longBufferString.lastIndexOf(pattern)); -assert.strictEqual(1535, longBufferString.lastIndexOf(pattern, 1535)); -assert.strictEqual(511, longBufferString.lastIndexOf(pattern, 1534)); +assert.strictEqual(longBufferString.lastIndexOf(pattern), 1535); +assert.strictEqual(longBufferString.lastIndexOf(pattern, 1535), 1535); +assert.strictEqual(longBufferString.lastIndexOf(pattern, 1534), 511); // Finally, give it a really long input to trigger fallback from BMH to // regular BOYER-MOORE (which has better worst-case complexity). @@ -567,19 +567,19 @@ for (let i = 0; i < 1000000; i++) { parts.push((countBits(i) % 2 === 0) ? 'yolo' : 'swag'); } const reallyLong = Buffer.from(parts.join(' ')); -assert.strictEqual('yolo swag swag yolo', reallyLong.slice(0, 19).toString()); +assert.strictEqual(reallyLong.slice(0, 19).toString(), 'yolo swag swag yolo'); // Expensive reverse searches. Stress test lastIndexOf: pattern = reallyLong.slice(0, 100000); // First 1/50th of the pattern. -assert.strictEqual(4751360, reallyLong.lastIndexOf(pattern)); -assert.strictEqual(3932160, reallyLong.lastIndexOf(pattern, 4000000)); -assert.strictEqual(2949120, reallyLong.lastIndexOf(pattern, 3000000)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 4751360); +assert.strictEqual(reallyLong.lastIndexOf(pattern, 4000000), 3932160); +assert.strictEqual(reallyLong.lastIndexOf(pattern, 3000000), 2949120); pattern = reallyLong.slice(100000, 200000); // Second 1/50th. -assert.strictEqual(4728480, reallyLong.lastIndexOf(pattern)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 4728480); pattern = reallyLong.slice(0, 1000000); // First 1/5th. -assert.strictEqual(3932160, reallyLong.lastIndexOf(pattern)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 3932160); pattern = reallyLong.slice(0, 2000000); // first 2/5ths. -assert.strictEqual(0, reallyLong.lastIndexOf(pattern)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 0); // test truncation of Number arguments to uint8 { diff --git a/test/parallel/test-buffer-slice.js b/test/parallel/test-buffer-slice.js index 6175370a9bccee..f40a495b206079 100644 --- a/test/parallel/test-buffer-slice.js +++ b/test/parallel/test-buffer-slice.js @@ -24,8 +24,8 @@ require('../common'); const assert = require('assert'); -assert.strictEqual(0, Buffer.from('hello', 'utf8').slice(0, 0).length); -assert.strictEqual(0, Buffer('hello', 'utf8').slice(0, 0).length); +assert.strictEqual(Buffer.from('hello', 'utf8').slice(0, 0).length, 0); +assert.strictEqual(Buffer('hello', 'utf8').slice(0, 0).length, 0); const buf = Buffer.from('0123456789', 'utf8'); const expectedSameBufs = [ @@ -72,7 +72,7 @@ for (let i = 0, s = buf.toString(); i < buf.length; ++i) { } expectedSameBufs.forEach(([buf1, buf2]) => { - assert.strictEqual(0, Buffer.compare(buf1, buf2)); + assert.strictEqual(Buffer.compare(buf1, buf2), 0); }); const utf16Buf = Buffer.from('0123456789', 'utf16le'); @@ -83,12 +83,12 @@ assert.strictEqual(Buffer.alloc(0).slice(0, 1).length, 0); { // Single argument slice - assert.strictEqual('bcde', - Buffer.from('abcde', 'utf8').slice(1).toString('utf8')); + assert.strictEqual(Buffer.from('abcde', 'utf8').slice(1).toString('utf8'), + 'bcde'); } // slice(0,0).length === 0 -assert.strictEqual(0, Buffer.from('hello', 'utf8').slice(0, 0).length); +assert.strictEqual(Buffer.from('hello', 'utf8').slice(0, 0).length, 0); { // Regression tests for https://github.com/nodejs/node/issues/9096 diff --git a/test/parallel/test-buffer-writeuint.js b/test/parallel/test-buffer-writeuint.js index 999440114c74f4..387aafd3354a35 100644 --- a/test/parallel/test-buffer-writeuint.js +++ b/test/parallel/test-buffer-writeuint.js @@ -84,6 +84,18 @@ const assert = require('assert'); data.writeUInt16BE(value, 0); assert.ok(data.equals(new Uint8Array([0xff, 0x80, 0x43, 0x23]))); + + value = 0xfffff; + ['writeUInt16BE', 'writeUInt16LE'].forEach((fn) => { + assert.throws( + () => data[fn](value, 0), + { + code: 'ERR_OUT_OF_RANGE', + message: 'The value of "value" is out of range. ' + + `It must be >= 0 and <= 65535. Received ${value}` + } + ); + }); } // Test 32 bit diff --git a/test/parallel/test-child-process-fork-options.js b/test/parallel/test-child-process-fork-options.js new file mode 100644 index 00000000000000..5efb9bdbb49735 --- /dev/null +++ b/test/parallel/test-child-process-fork-options.js @@ -0,0 +1,37 @@ +'use strict'; +const common = require('../common'); +const fixtures = require('../common/fixtures'); + +// This test ensures that fork should parse options +// correctly if args is undefined or null + +const assert = require('assert'); +const { fork } = require('child_process'); + +const expectedEnv = { foo: 'bar' }; + +{ + const cp = fork(fixtures.path('child-process-echo-options.js'), undefined, + { env: Object.assign({}, process.env, expectedEnv) }); + + cp.on('message', common.mustCall(({ env }) => { + assert.strictEqual(env.foo, expectedEnv.foo); + })); + + cp.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); +} + +{ + const cp = fork(fixtures.path('child-process-echo-options.js'), null, + { env: Object.assign({}, process.env, expectedEnv) }); + + cp.on('message', common.mustCall(({ env }) => { + assert.strictEqual(env.foo, expectedEnv.foo); + })); + + cp.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); +} diff --git a/test/parallel/test-child-process-no-deprecation.js b/test/parallel/test-child-process-no-deprecation.js new file mode 100644 index 00000000000000..d12e5b882f6375 --- /dev/null +++ b/test/parallel/test-child-process-no-deprecation.js @@ -0,0 +1,15 @@ +'use strict'; +const common = require('../common'); +process.noDeprecation = true; + +if (process.argv[2] === 'child') { + process.emitWarning('Something else is deprecated.', 'DeprecationWarning'); +} else { + // parent process + const spawn = require('child_process').spawn; + + // spawn self as child + const child = spawn(process.execPath, [process.argv[1], 'child']); + + child.stderr.on('data', common.mustNotCall()); +} diff --git a/test/parallel/test-child-process-spawn-typeerror.js b/test/parallel/test-child-process-spawn-typeerror.js index 31a1867df945f7..82acaf8e088038 100644 --- a/test/parallel/test-child-process-spawn-typeerror.js +++ b/test/parallel/test-child-process-spawn-typeerror.js @@ -33,12 +33,11 @@ const invalidArgValueError = common.expectsError({ code: 'ERR_INVALID_ARG_VALUE', type: TypeError }, 14); const invalidArgTypeError = - common.expectsError({ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 12); + common.expectsError({ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 13); assert.throws(function() { - const child = spawn(invalidcmd, 'this is not an array'); - child.on('error', common.mustNotCall()); -}, TypeError); + spawn(invalidcmd, 'this is not an array'); +}, invalidArgTypeError); // Verify that valid argument combinations do not throw. spawn(cmd); diff --git a/test/parallel/test-child-process-spawnsync-shell.js b/test/parallel/test-child-process-spawnsync-shell.js index 6f7c0ec0f14a26..01c5aef9e8d919 100644 --- a/test/parallel/test-child-process-spawnsync-shell.js +++ b/test/parallel/test-child-process-spawnsync-shell.js @@ -67,7 +67,7 @@ assert.strictEqual(env.stdout.toString().trim(), 'buzz'); assert.strictEqual(opts.options.shell, shell); assert.strictEqual(opts.options.file, opts.file); assert.deepStrictEqual(opts.options.args, opts.args); - assert.strictEqual(opts.options.windowsHide, true); + assert.strictEqual(opts.options.windowsHide, undefined); assert.strictEqual(opts.options.windowsVerbatimArguments, windowsVerbatim); }); diff --git a/test/parallel/test-child-process-stdin.js b/test/parallel/test-child-process-stdin.js index 7f49d90f3a3fb6..29f78df7d0ae88 100644 --- a/test/parallel/test-child-process-stdin.js +++ b/test/parallel/test-child-process-stdin.js @@ -30,8 +30,8 @@ cat.stdin.write('hello'); cat.stdin.write(' '); cat.stdin.write('world'); -assert.strictEqual(true, cat.stdin.writable); -assert.strictEqual(false, cat.stdin.readable); +assert.strictEqual(cat.stdin.writable, true); +assert.strictEqual(cat.stdin.readable, false); cat.stdin.end(); @@ -50,9 +50,9 @@ cat.stderr.on('data', common.mustNotCall()); cat.stderr.on('end', common.mustCall()); cat.on('exit', common.mustCall(function(status) { - assert.strictEqual(0, status); + assert.strictEqual(status, 0); })); cat.on('close', common.mustCall(function() { - assert.strictEqual('hello world', response); + assert.strictEqual(response, 'hello world'); })); diff --git a/test/parallel/test-child-process-stdio.js b/test/parallel/test-child-process-stdio.js index 5ca3875f5600f6..a5e5f952259cee 100644 --- a/test/parallel/test-child-process-stdio.js +++ b/test/parallel/test-child-process-stdio.js @@ -60,8 +60,8 @@ const { spawn } = require('child_process'); })); child.on('close', common.mustCall(function() { - assert.strictEqual(true, output.length > 1); - assert.strictEqual('\n', output[output.length - 1]); + assert.strictEqual(output.length > 1, true); + assert.strictEqual(output[output.length - 1], '\n'); })); } diff --git a/test/parallel/test-console-instance.js b/test/parallel/test-console-instance.js index 0b69212948dd2c..91d130f260184b 100644 --- a/test/parallel/test-console-instance.js +++ b/test/parallel/test-console-instance.js @@ -33,7 +33,7 @@ const err = new Stream(); process.stdout.write = process.stderr.write = common.mustNotCall(); // Make sure that the "Console" function exists. -assert.strictEqual('function', typeof Console); +assert.strictEqual(typeof Console, 'function'); // Make sure that the Console constructor throws // when not given a writable stream instance. diff --git a/test/parallel/test-console-table.js b/test/parallel/test-console-table.js index e5b56ced8435ea..3a4d6fefbbc8f1 100644 --- a/test/parallel/test-console-table.js +++ b/test/parallel/test-console-table.js @@ -168,6 +168,14 @@ test({ a: { a: 1, b: 2, c: 3 } }, ` └─────────┴───┴───┴───┘ `); +test({ a: { a: { a: 1, b: 2, c: 3 } } }, ` +┌─────────┬──────────┐ +│ (index) │ a │ +├─────────┼──────────┤ +│ a │ [Object] │ +└─────────┴──────────┘ +`); + test({ a: [1, 2] }, ` ┌─────────┬───┬───┐ │ (index) │ 0 │ 1 │ diff --git a/test/parallel/test-console.js b/test/parallel/test-console.js index 5ecc0bd834bde4..92e66596d76ca7 100644 --- a/test/parallel/test-console.js +++ b/test/parallel/test-console.js @@ -45,6 +45,10 @@ common.expectWarning( ['Count for \'noLabel\' does not exist', common.noWarnCode], ['No such label \'noLabel\' for console.timeLog()', common.noWarnCode], ['No such label \'noLabel\' for console.timeEnd()', common.noWarnCode], + ['Count for \'default\' does not exist', common.noWarnCode], + ['No such label \'default\' for console.timeLog()', common.noWarnCode], + ['No such label \'default\' for console.timeEnd()', common.noWarnCode], + ['Label \'default\' already exists for console.time()', common.noWarnCode], ['Label \'test\' already exists for console.time()', common.noWarnCode] ] ); @@ -56,6 +60,17 @@ console.timeEnd('noLabel'); console.time('label'); console.timeEnd('label'); +// Test using the default label +// on console.time(), console.countReset(), console.timeLog(), console.timeEnd() +console.countReset(); +console.timeLog(); +console.timeEnd(); + +console.time(); +console.time(); +console.timeLog(); +console.timeEnd(); + // Check that the `Error` is a `TypeError` but do not check the message as it // will be different in different JavaScript engines. assert.throws(() => console.time(Symbol('test')), @@ -180,6 +195,8 @@ assert.strictEqual(errStrings[errStrings.length - 1], console.assert(true, 'this should not throw'); +console.assert(true); + assert.strictEqual(strings.length, process.stdout.writeTimes); assert.strictEqual(errStrings.length, process.stderr.writeTimes); restoreStdout(); diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index ec5c05cb120da7..01ce1d9996863e 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -94,9 +94,10 @@ for (const test of TEST_CASES) { const isCCM = /^aes-(128|192|256)-ccm$/.test(test.algo); const isOCB = /^aes-(128|192|256)-ocb$/.test(test.algo); + const isChacha20Poly1305 = test.algo === 'chacha20-poly1305'; let options; - if (isCCM || isOCB) + if (isCCM || isOCB || isChacha20Poly1305) options = { authTagLength: test.tag.length / 2 }; const inputEncoding = test.plainIsHex ? 'hex' : 'ascii'; diff --git a/test/parallel/test-crypto-cipher-decipher.js b/test/parallel/test-crypto-cipher-decipher.js index 3c0658762f478b..ed387c3c999026 100644 --- a/test/parallel/test-crypto-cipher-decipher.js +++ b/test/parallel/test-crypto-cipher-decipher.js @@ -168,13 +168,13 @@ testCipher2(Buffer.from('0123456789abcdef')); // not assert. See https://github.com/nodejs/node-v0.x-archive/issues/4886. { const c = crypto.createCipher('aes-256-cbc', 'secret'); - try { c.final('xxx'); } catch (e) { /* Ignore. */ } - try { c.final('xxx'); } catch (e) { /* Ignore. */ } - try { c.final('xxx'); } catch (e) { /* Ignore. */ } + try { c.final('xxx'); } catch { /* Ignore. */ } + try { c.final('xxx'); } catch { /* Ignore. */ } + try { c.final('xxx'); } catch { /* Ignore. */ } const d = crypto.createDecipher('aes-256-cbc', 'secret'); - try { d.final('xxx'); } catch (e) { /* Ignore. */ } - try { d.final('xxx'); } catch (e) { /* Ignore. */ } - try { d.final('xxx'); } catch (e) { /* Ignore. */ } + try { d.final('xxx'); } catch { /* Ignore. */ } + try { d.final('xxx'); } catch { /* Ignore. */ } + try { d.final('xxx'); } catch { /* Ignore. */ } } // Regression test for https://github.com/nodejs/node-v0.x-archive/issues/5482: diff --git a/test/parallel/test-delayed-require.js b/test/parallel/test-delayed-require.js index 8aecb354698185..355d503d2650d2 100644 --- a/test/parallel/test-delayed-require.js +++ b/test/parallel/test-delayed-require.js @@ -26,7 +26,7 @@ const fixtures = require('../common/fixtures'); setTimeout(common.mustCall(function() { const a = require(fixtures.path('a')); - assert.strictEqual(true, 'A' in a); - assert.strictEqual('A', a.A()); - assert.strictEqual('D', a.D()); + assert.strictEqual('A' in a, true); + assert.strictEqual(a.A(), 'A'); + assert.strictEqual(a.D(), 'D'); }), 50); diff --git a/test/parallel/test-dgram-deprecation-error.js b/test/parallel/test-dgram-deprecation-error.js new file mode 100644 index 00000000000000..89cde12fd37cf1 --- /dev/null +++ b/test/parallel/test-dgram-deprecation-error.js @@ -0,0 +1,84 @@ +'use strict'; + +const assert = require('assert'); +const common = require('../common'); +const dgram = require('dgram'); +const fork = require('child_process').fork; + +const sock = dgram.createSocket('udp4'); + +const testNumber = parseInt(process.argv[2], 10); + +const propertiesToTest = [ + '_handle', + '_receiving', + '_bindState', + '_queue', + '_reuseAddr' +]; + +const methodsToTest = [ + '_healthCheck', + '_stopReceiving' +]; + +const propertyCases = propertiesToTest.map((propName) => { + return [ + () => { + // Test property getter + common.expectWarning( + 'DeprecationWarning', + `Socket.prototype.${propName} is deprecated`, + 'DEP0112' + ); + sock[propName]; + }, + () => { + // Test property setter + common.expectWarning( + 'DeprecationWarning', + `Socket.prototype.${propName} is deprecated`, + 'DEP0112' + ); + sock[propName] = null; + } + ]; +}); + +const methodCases = methodsToTest.map((propName) => { + return () => { + common.expectWarning( + 'DeprecationWarning', + `Socket.prototype.${propName}() is deprecated`, + 'DEP0112' + ); + sock[propName](); + }; +}); + +const cases = [].concat( + ...propertyCases, + ...methodCases +); + +// If we weren't passed a test ID then we need to spawn all of the cases. +// We run the cases in child processes since deprecations print once. +if (Number.isNaN(testNumber)) { + const children = cases.map((_case, i) => + fork(process.argv[1], [ String(i) ])); + + children.forEach((child) => { + child.on('close', (code) => { + // Pass on child exit code + if (code > 0) { + process.exit(code); + } + }); + }); + + return; +} + +// We were passed a test ID - run the test case +assert.ok(cases[testNumber]); +cases[testNumber](); diff --git a/test/parallel/test-dgram-send-bad-arguments.js b/test/parallel/test-dgram-send-bad-arguments.js index 4eb7dca7a38e5d..20356ba50c477a 100644 --- a/test/parallel/test-dgram-send-bad-arguments.js +++ b/test/parallel/test-dgram-send-bad-arguments.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 dgram = require('dgram'); @@ -28,9 +28,16 @@ const buf = Buffer.from('test'); const host = '127.0.0.1'; const sock = dgram.createSocket('udp4'); -assert.throws(() => { - sock.send(); -}, TypeError); // First argument should be a buffer. +// First argument should be a buffer. +common.expectsError( + () => { sock.send(); }, + { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "buffer" argument must be one of type ' + + 'Buffer, Uint8Array, or string. Received type undefined' + } +); // send(buf, offset, length, port, host) assert.throws(() => { sock.send(buf, 1, 1, -1, host); }, RangeError); @@ -38,7 +45,23 @@ assert.throws(() => { sock.send(buf, 1, 1, 0, host); }, RangeError); assert.throws(() => { sock.send(buf, 1, 1, 65536, host); }, RangeError); // send(buf, port, host) -assert.throws(() => { sock.send(23, 12345, host); }, TypeError); +common.expectsError( + () => { sock.send(23, 12345, host); }, + { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "buffer" argument must be one of type ' + + 'Buffer, Uint8Array, or string. Received type number' + } +); // send([buf1, ..], port, host) -assert.throws(() => { sock.send([buf, 23], 12345, host); }, TypeError); +common.expectsError( + () => { sock.send([buf, 23], 12345, host); }, + { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "buffer list arguments" argument must be one of type ' + + 'Buffer or string. Received type object' + } +); diff --git a/test/parallel/test-domain-add-remove.js b/test/parallel/test-domain-add-remove.js new file mode 100644 index 00000000000000..8e1d082125cb0b --- /dev/null +++ b/test/parallel/test-domain-add-remove.js @@ -0,0 +1,26 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const domain = require('domain'); +const EventEmitter = require('events'); + +const d = new domain.Domain(); +const e = new EventEmitter(); +const e2 = new EventEmitter(); + +d.add(e); +assert.strictEqual(e.domain, d); + +// Adding the same event to a domain should not change the member count +let previousMemberCount = d.members.length; +d.add(e); +assert.strictEqual(previousMemberCount, d.members.length); + +d.add(e2); +assert.strictEqual(e2.domain, d); + +previousMemberCount = d.members.length; +d.remove(e2); +assert.notStrictEqual(e2.domain, d); +assert.strictEqual(previousMemberCount - 1, d.members.length); diff --git a/test/parallel/test-errors-systemerror.js b/test/parallel/test-errors-systemerror.js index 957a0dd7b22196..0b5f9b9a107d59 100644 --- a/test/parallel/test-errors-systemerror.js +++ b/test/parallel/test-errors-systemerror.js @@ -111,3 +111,25 @@ const { ERR_TEST } = codes; assert.strictEqual(err.path, 'path'); assert.strictEqual(err.dest, 'path'); } + +{ + const ctx = { + code: 'ERR_TEST', + message: 'Error occurred', + syscall: 'syscall_test' + }; + assert.throws( + () => { + const err = new ERR_TEST(ctx); + err.name = 'SystemError [CUSTOM_ERR_TEST]'; + throw err; + }, + { + code: 'ERR_TEST', + name: 'SystemError [CUSTOM_ERR_TEST]', + message: 'custom message: syscall_test returned ERR_TEST ' + + '(Error occurred)', + info: ctx + } + ); +} diff --git a/test/parallel/test-event-emitter-add-listeners.js b/test/parallel/test-event-emitter-add-listeners.js index 45bfd3832caaaf..6ef39522183d4f 100644 --- a/test/parallel/test-event-emitter-add-listeners.js +++ b/test/parallel/test-event-emitter-add-listeners.js @@ -42,8 +42,8 @@ const EventEmitter = require('events'); }); const hello = common.mustCall(function(a, b) { - assert.strictEqual('a', a); - assert.strictEqual('b', b); + assert.strictEqual(a, 'a'); + assert.strictEqual(b, 'b'); }); ee.once('newListener', function(name, listener) { diff --git a/test/parallel/test-event-emitter-modify-in-emit.js b/test/parallel/test-event-emitter-modify-in-emit.js index 9c28fecbdd8c4c..995fa01d11a1a8 100644 --- a/test/parallel/test-event-emitter-modify-in-emit.js +++ b/test/parallel/test-event-emitter-modify-in-emit.js @@ -74,7 +74,7 @@ callbacks_called = []; e.on('foo', callback2); e.on('foo', callback3); -assert.strictEqual(2, e.listeners('foo').length); +assert.strictEqual(e.listeners('foo').length, 2); e.emit('foo'); assert.deepStrictEqual(['callback2', 'callback3'], callbacks_called); -assert.strictEqual(0, e.listeners('foo').length); +assert.strictEqual(e.listeners('foo').length, 0); diff --git a/test/parallel/test-file-write-stream.js b/test/parallel/test-file-write-stream.js index 4860417dd29bc5..4d9df25d4cd2ac 100644 --- a/test/parallel/test-file-write-stream.js +++ b/test/parallel/test-file-write-stream.js @@ -44,7 +44,7 @@ file .on('open', function(fd) { console.error('open!'); callbacks.open++; - assert.strictEqual('number', typeof fd); + assert.strictEqual(typeof fd, 'number'); }) .on('error', function(err) { throw err; @@ -86,7 +86,7 @@ for (let i = 0; i < 11; i++) { process.on('exit', function() { for (const k in callbacks) { - assert.strictEqual(0, callbacks[k], `${k} count off by ${callbacks[k]}`); + assert.strictEqual(callbacks[k], 0, `${k} count off by ${callbacks[k]}`); } console.log('ok'); }); diff --git a/test/parallel/test-file-write-stream2.js b/test/parallel/test-file-write-stream2.js index 2db06640e18dba..e29bd80ebf792c 100644 --- a/test/parallel/test-file-write-stream2.js +++ b/test/parallel/test-file-write-stream2.js @@ -56,7 +56,7 @@ process.on('exit', function() { function removeTestFile() { try { fs.unlinkSync(filepath); - } catch (e) {} + } catch {} } diff --git a/test/parallel/test-fs-error-messages.js b/test/parallel/test-fs-error-messages.js index b0480059edd37f..96ff606cccec4e 100644 --- a/test/parallel/test-fs-error-messages.js +++ b/test/parallel/test-fs-error-messages.js @@ -26,15 +26,22 @@ const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); const assert = require('assert'); const fs = require('fs'); +const path = require('path'); tmpdir.refresh(); -const nonexistentFile = fixtures.path('non-existent'); -const nonexistentDir = fixtures.path('non-existent', 'foo', 'bar'); -const existingFile = fixtures.path('exit.js'); -const existingFile2 = fixtures.path('a.js'); -const existingDir = tmpdir.path; + +const nonexistentFile = path.join(tmpdir.path, 'non-existent'); +const nonexistentDir = path.join(tmpdir.path, 'non-existent', 'foo', 'bar'); +const existingFile = path.join(tmpdir.path, 'existingFile.js'); +const existingFile2 = path.join(tmpdir.path, 'existingFile2.js'); +const existingDir = path.join(tmpdir.path, 'dir'); const existingDir2 = fixtures.path('keys'); +fs.mkdirSync(existingDir); +fs.writeFileSync(existingFile, 'test', 'utf-8'); +fs.writeFileSync(existingFile2, 'test', 'utf-8'); + + const { COPYFILE_EXCL } = fs.constants; const { internalBinding } = require('internal/test/binding'); const { diff --git a/test/parallel/test-fs-link.js b/test/parallel/test-fs-link.js index d007f4e985b2d5..9b95fc3e026140 100644 --- a/test/parallel/test-fs-link.js +++ b/test/parallel/test-fs-link.js @@ -15,7 +15,7 @@ fs.writeFileSync(srcPath, 'hello world'); function callback(err) { assert.ifError(err); const dstContent = fs.readFileSync(dstPath, 'utf8'); - assert.strictEqual('hello world', dstContent); + assert.strictEqual(dstContent, 'hello world'); } fs.link(srcPath, dstPath, common.mustCall(callback)); diff --git a/test/parallel/test-fs-read-file-sync.js b/test/parallel/test-fs-read-file-sync.js index c8a9941b4990da..ee6f34ac4dccfd 100644 --- a/test/parallel/test-fs-read-file-sync.js +++ b/test/parallel/test-fs-read-file-sync.js @@ -29,6 +29,6 @@ const fn = fixtures.path('elipses.txt'); const s = fs.readFileSync(fn, 'utf8'); for (let i = 0; i < s.length; i++) { - assert.strictEqual('\u2026', s[i]); + assert.strictEqual(s[i], '\u2026'); } -assert.strictEqual(10000, s.length); +assert.strictEqual(s.length, 10000); diff --git a/test/parallel/test-fs-read-stream-fd-leak.js b/test/parallel/test-fs-read-stream-fd-leak.js index 5bf0157ff4e7ae..81712def761340 100644 --- a/test/parallel/test-fs-read-stream-fd-leak.js +++ b/test/parallel/test-fs-read-stream-fd-leak.js @@ -37,8 +37,8 @@ function testLeak(endFn, callback) { } assert.strictEqual( - 0, openCount, + 0, `no leaked file descriptors using ${endFn}() (got ${openCount})` ); diff --git a/test/parallel/test-fs-read-stream.js b/test/parallel/test-fs-read-stream.js index 793b474c9b8292..2a07a09c976574 100644 --- a/test/parallel/test-fs-read-stream.js +++ b/test/parallel/test-fs-read-stream.js @@ -42,7 +42,7 @@ const rangeFile = fixtures.path('x.txt'); file.on('open', common.mustCall(function(fd) { file.length = 0; - assert.strictEqual('number', typeof fd); + assert.strictEqual(typeof fd, 'number'); assert.strictEqual(file.bytesRead, 0); assert.ok(file.readable); @@ -91,12 +91,12 @@ const rangeFile = fixtures.path('x.txt'); const file = fs.createReadStream(fn, { encoding: 'utf8' }); file.length = 0; file.on('data', function(data) { - assert.strictEqual('string', typeof data); + assert.strictEqual(typeof data, 'string'); file.length += data.length; for (let i = 0; i < data.length; i++) { // http://www.fileformat.info/info/unicode/char/2026/index.htm - assert.strictEqual('\u2026', data[i]); + assert.strictEqual(data[i], '\u2026'); } }); @@ -162,7 +162,7 @@ common.expectsError( }); stream.on('end', common.mustCall(function() { - assert.strictEqual('x', stream.data); + assert.strictEqual(stream.data, 'x'); })); } @@ -176,7 +176,7 @@ common.expectsError( }); stream.on('end', common.mustCall(function() { - assert.strictEqual('xy', stream.data); + assert.strictEqual(stream.data, 'xy'); })); } @@ -197,7 +197,7 @@ if (!common.isWindows) { }); stream.on('end', common.mustCall(function() { - assert.strictEqual('xy', stream.data); + assert.strictEqual(stream.data, 'xy'); fs.unlinkSync(filename); })); } else { diff --git a/test/parallel/test-fs-readfile-empty.js b/test/parallel/test-fs-readfile-empty.js index 36eccfb1162713..7bb942fc2d6fe3 100644 --- a/test/parallel/test-fs-readfile-empty.js +++ b/test/parallel/test-fs-readfile-empty.js @@ -35,12 +35,12 @@ fs.readFile(fn, function(err, data) { }); fs.readFile(fn, 'utf8', function(err, data) { - assert.strictEqual('', data); + assert.strictEqual(data, ''); }); fs.readFile(fn, { encoding: 'utf8' }, function(err, data) { - assert.strictEqual('', data); + assert.strictEqual(data, ''); }); assert.ok(fs.readFileSync(fn)); -assert.strictEqual('', fs.readFileSync(fn, 'utf8')); +assert.strictEqual(fs.readFileSync(fn, 'utf8'), ''); diff --git a/test/parallel/test-fs-readfile-fd.js b/test/parallel/test-fs-readfile-fd.js index 7458af7b2e53af..b5d2a33e285f5f 100644 --- a/test/parallel/test-fs-readfile-fd.js +++ b/test/parallel/test-fs-readfile-fd.js @@ -17,7 +17,7 @@ tempFd(function(fd, close) { tempFd(function(fd, close) { fs.readFile(fd, 'utf8', function(err, data) { - assert.strictEqual('', data); + assert.strictEqual(data, ''); close(); }); }); @@ -27,7 +27,7 @@ tempFdSync(function(fd) { }); tempFdSync(function(fd) { - assert.strictEqual('', fs.readFileSync(fd, 'utf8')); + assert.strictEqual(fs.readFileSync(fd, 'utf8'), ''); }); function tempFd(callback) { diff --git a/test/parallel/test-fs-ready-event-stream.js b/test/parallel/test-fs-ready-event-stream.js index 71f7aa76e36c76..f6b380cf26d42c 100644 --- a/test/parallel/test-fs-ready-event-stream.js +++ b/test/parallel/test-fs-ready-event-stream.js @@ -1,13 +1,20 @@ 'use strict'; const common = require('../common'); +const assert = require('assert'); const fs = require('fs'); const path = require('path'); const tmpdir = require('../common/tmpdir'); const readStream = fs.createReadStream(__filename); -readStream.on('ready', common.mustCall(() => {}, 1)); +assert.strictEqual(readStream.pending, true); +readStream.on('ready', common.mustCall(() => { + assert.strictEqual(readStream.pending, false); +})); const writeFile = path.join(tmpdir.path, 'write-fsreadyevent.txt'); tmpdir.refresh(); const writeStream = fs.createWriteStream(writeFile, { autoClose: true }); -writeStream.on('ready', common.mustCall(() => {}, 1)); +assert.strictEqual(writeStream.pending, true); +writeStream.on('ready', common.mustCall(() => { + assert.strictEqual(writeStream.pending, false); +})); diff --git a/test/parallel/test-fs-realpath-pipe.js b/test/parallel/test-fs-realpath-pipe.js index 55010cf78b4a5a..7104e93ff123ed 100644 --- a/test/parallel/test-fs-realpath-pipe.js +++ b/test/parallel/test-fs-realpath-pipe.js @@ -22,7 +22,7 @@ for (const code of [ if (require('fs').realpathSync('/dev/stdin')) { process.exit(2); } - } catch (e) { + } catch { process.exit(1); }` ]) { diff --git a/test/parallel/test-fs-realpath.js b/test/parallel/test-fs-realpath.js index 599616f5224eb7..18b9de471bc3a8 100644 --- a/test/parallel/test-fs-realpath.js +++ b/test/parallel/test-fs-realpath.js @@ -100,7 +100,7 @@ function test_simple_relative_symlink(realpath, realpathSync, callback) { [ [entry, `../${path.basename(tmpDir)}/cycles/root.js`] ].forEach(function(t) { - try { fs.unlinkSync(t[0]); } catch (e) {} + try { fs.unlinkSync(t[0]); } catch {} console.log('fs.symlinkSync(%j, %j, %j)', t[1], t[0], 'file'); fs.symlinkSync(t[1], t[0], 'file'); unlink.push(t[0]); @@ -126,7 +126,7 @@ function test_simple_absolute_symlink(realpath, realpathSync, callback) { [ [entry, expected] ].forEach(function(t) { - try { fs.unlinkSync(t[0]); } catch (e) {} + try { fs.unlinkSync(t[0]); } catch {} console.error('fs.symlinkSync(%j, %j, %j)', t[1], t[0], type); fs.symlinkSync(t[1], t[0], type); unlink.push(t[0]); @@ -151,13 +151,13 @@ function test_deep_relative_file_symlink(realpath, realpathSync, callback) { expected); const linkPath1 = path.join(targetsAbsDir, 'nested-index', 'one', 'symlink1.js'); - try { fs.unlinkSync(linkPath1); } catch (e) {} + try { fs.unlinkSync(linkPath1); } catch {} fs.symlinkSync(linkData1, linkPath1, 'file'); const linkData2 = '../one/symlink1.js'; const entry = path.join(targetsAbsDir, 'nested-index', 'two', 'symlink1-b.js'); - try { fs.unlinkSync(entry); } catch (e) {} + try { fs.unlinkSync(entry); } catch {} fs.symlinkSync(linkData2, entry, 'file'); unlink.push(linkPath1); unlink.push(entry); @@ -178,13 +178,13 @@ function test_deep_relative_dir_symlink(realpath, realpathSync, callback) { const path1b = path.join(targetsAbsDir, 'nested-index', 'one'); const linkPath1b = path.join(path1b, 'symlink1-dir'); const linkData1b = path.relative(path1b, expected); - try { fs.unlinkSync(linkPath1b); } catch (e) {} + try { fs.unlinkSync(linkPath1b); } catch {} fs.symlinkSync(linkData1b, linkPath1b, 'dir'); const linkData2b = '../one/symlink1-dir'; const entry = path.join(targetsAbsDir, 'nested-index', 'two', 'symlink12-dir'); - try { fs.unlinkSync(entry); } catch (e) {} + try { fs.unlinkSync(entry); } catch {} fs.symlinkSync(linkData2b, entry, 'dir'); unlink.push(linkPath1b); unlink.push(entry); @@ -208,7 +208,7 @@ function test_cyclic_link_protection(realpath, realpathSync, callback) { [path.join(tmpDir, '/cycles/realpath-3b'), '../cycles/realpath-3c'], [path.join(tmpDir, '/cycles/realpath-3c'), '../cycles/realpath-3a'] ].forEach(function(t) { - try { fs.unlinkSync(t[0]); } catch (e) {} + try { fs.unlinkSync(t[0]); } catch {} fs.symlinkSync(t[1], t[0], 'dir'); unlink.push(t[0]); }); @@ -235,7 +235,7 @@ function test_cyclic_link_overprotection(realpath, realpathSync, callback) { const link = `${folder}/cycles`; let testPath = cycles; testPath += '/folder/cycles'.repeat(10); - try { fs.unlinkSync(link); } catch (ex) {} + try { fs.unlinkSync(link); } catch {} fs.symlinkSync(cycles, link, 'dir'); unlink.push(link); assertEqualPath(realpathSync(testPath), path.resolve(expected)); @@ -263,7 +263,7 @@ function test_relative_input_cwd(realpath, realpathSync, callback) { ].forEach(function(t) { const fn = t[0]; console.error('fn=%j', fn); - try { fs.unlinkSync(fn); } catch (e) {} + try { fs.unlinkSync(fn); } catch {} const b = path.basename(t[1]); const type = (b === 'root.js' ? 'file' : 'dir'); console.log('fs.symlinkSync(%j, %j, %j)', t[1], fn, type); @@ -302,8 +302,8 @@ function test_deep_symlink_mix(realpath, realpathSync, callback) { $tmpDir/targets/cycles/root.js (hard) */ const entry = tmp('node-test-realpath-f1'); - try { fs.unlinkSync(tmp('node-test-realpath-d2/foo')); } catch (e) {} - try { fs.rmdirSync(tmp('node-test-realpath-d2')); } catch (e) {} + try { fs.unlinkSync(tmp('node-test-realpath-d2/foo')); } catch {} + try { fs.rmdirSync(tmp('node-test-realpath-d2')); } catch {} fs.mkdirSync(tmp('node-test-realpath-d2'), 0o700); try { [ @@ -318,7 +318,7 @@ function test_deep_symlink_mix(realpath, realpathSync, callback) { [`${targetsAbsDir}/nested-index/two/realpath-c`, `${tmpDir}/cycles/root.js`] ].forEach(function(t) { - try { fs.unlinkSync(t[0]); } catch (e) {} + try { fs.unlinkSync(t[0]); } catch {} fs.symlinkSync(t[1], t[0]); unlink.push(t[0]); }); @@ -429,14 +429,14 @@ function test_abs_with_kids(realpath, realpathSync, cb) { ['/a/b/c/x.txt', '/a/link' ].forEach(function(file) { - try { fs.unlinkSync(root + file); } catch (ex) {} + try { fs.unlinkSync(root + file); } catch {} }); ['/a/b/c', '/a/b', '/a', '' ].forEach(function(folder) { - try { fs.rmdirSync(root + folder); } catch (ex) {} + try { fs.rmdirSync(root + folder); } catch {} }); } function setup() { diff --git a/test/parallel/test-fs-write-buffer.js b/test/parallel/test-fs-write-buffer.js index 6e6154642a583d..0ff9fd69a82a3a 100644 --- a/test/parallel/test-fs-write-buffer.js +++ b/test/parallel/test-fs-write-buffer.js @@ -58,11 +58,11 @@ tmpdir.refresh(); const cb = common.mustCall((err, written) => { assert.ifError(err); - assert.strictEqual(2, written); + assert.strictEqual(written, 2); fs.closeSync(fd); const found = fs.readFileSync(filename, 'utf8'); - assert.strictEqual('lo', found); + assert.strictEqual(found, 'lo'); }); fs.write(fd, Buffer.from('hello'), 3, cb); diff --git a/test/parallel/test-fs-write-sync.js b/test/parallel/test-fs-write-sync.js index 4ca7a1dd570eb0..1873c44fb9ae33 100644 --- a/test/parallel/test-fs-write-sync.js +++ b/test/parallel/test-fs-write-sync.js @@ -34,7 +34,7 @@ tmpdir.refresh(); const fd = fs.openSync(filename, 'w'); let written = fs.writeSync(fd, ''); - assert.strictEqual(0, written); + assert.strictEqual(written, 0); fs.writeSync(fd, 'foo'); @@ -50,7 +50,7 @@ tmpdir.refresh(); const fd = fs.openSync(filename, 'w'); let written = fs.writeSync(fd, ''); - assert.strictEqual(0, written); + assert.strictEqual(written, 0); fs.writeSync(fd, 'foo'); @@ -66,7 +66,7 @@ tmpdir.refresh(); const fd = fs.openSync(filename, 'w'); let written = fs.writeSync(fd, ''); - assert.strictEqual(0, written); + assert.strictEqual(written, 0); fs.writeSync(fd, 'foo'); diff --git a/test/parallel/test-heapdump-inspector.js b/test/parallel/test-heapdump-inspector.js index 3d031d87eb1a99..963b85ac3a029a 100644 --- a/test/parallel/test-heapdump-inspector.js +++ b/test/parallel/test-heapdump-inspector.js @@ -7,17 +7,38 @@ common.skipIfInspectorDisabled(); const { validateSnapshotNodes } = require('../common/heap'); const inspector = require('inspector'); -const session = new inspector.Session(); -validateSnapshotNodes('Node / JSBindingsConnection', []); -session.connect(); -validateSnapshotNodes('Node / JSBindingsConnection', [ - { - children: [ - { node_name: 'Node / InspectorSession', edge_name: 'session' }, - { node_name: 'Connection', edge_name: 'wrapped' }, - (edge) => edge.name === 'callback' && - (edge.to.type === undefined || // embedded graph - edge.to.type === 'closure') // snapshot - ] +const snapshotNode = { + children: [ + { node_name: 'Node / InspectorSession', edge_name: 'session' } + ] +}; + +// starts with no JSBindingsConnection (or 1 if coverage enabled). +{ + const expected = []; + if (process.env.NODE_V8_COVERAGE) { + expected.push(snapshotNode); + } + validateSnapshotNodes('Node / JSBindingsConnection', expected); +} + +// JSBindingsConnection should be added. +{ + const session = new inspector.Session(); + session.connect(); + const expected = [ + { + children: [ + { node_name: 'Node / InspectorSession', edge_name: 'session' }, + { node_name: 'Connection', edge_name: 'wrapped' }, + (edge) => edge.name === 'callback' && + (edge.to.type === undefined || // embedded graph + edge.to.type === 'closure') // snapshot + ] + } + ]; + if (process.env.NODE_V8_COVERAGE) { + expected.push(snapshotNode); } -]); + validateSnapshotNodes('Node / JSBindingsConnection', expected); +} diff --git a/test/parallel/test-http-1.0.js b/test/parallel/test-http-1.0.js index 47df50e2897b79..134a5bb9853102 100644 --- a/test/parallel/test-http-1.0.js +++ b/test/parallel/test-http-1.0.js @@ -58,9 +58,9 @@ function test(handler, request_generator, response_validator) { { function handler(req, res) { - assert.strictEqual('1.0', req.httpVersion); - assert.strictEqual(1, req.httpVersionMajor); - assert.strictEqual(0, req.httpVersionMinor); + assert.strictEqual(req.httpVersion, '1.0'); + assert.strictEqual(req.httpVersionMajor, 1); + assert.strictEqual(req.httpVersionMinor, 0); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(body); } @@ -72,8 +72,8 @@ function test(handler, request_generator, response_validator) { function response_validator(server_response, client_got_eof, timed_out) { const m = server_response.split('\r\n\r\n'); assert.strictEqual(m[1], body); - assert.strictEqual(true, client_got_eof); - assert.strictEqual(false, timed_out); + assert.strictEqual(client_got_eof, true); + assert.strictEqual(timed_out, false); } test(handler, request_generator, response_validator); @@ -86,9 +86,9 @@ function test(handler, request_generator, response_validator) { // { function handler(req, res) { - assert.strictEqual('1.0', req.httpVersion); - assert.strictEqual(1, req.httpVersionMajor); - assert.strictEqual(0, req.httpVersionMinor); + assert.strictEqual(req.httpVersion, '1.0'); + assert.strictEqual(req.httpVersionMajor, 1); + assert.strictEqual(req.httpVersionMinor, 0); res.sendDate = false; res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('Hello, '); res._send(''); @@ -112,9 +112,9 @@ function test(handler, request_generator, response_validator) { '\r\n' + 'Hello, world!'; - assert.strictEqual(expected_response, server_response); - assert.strictEqual(true, client_got_eof); - assert.strictEqual(false, timed_out); + assert.strictEqual(server_response, expected_response); + assert.strictEqual(client_got_eof, true); + assert.strictEqual(timed_out, false); } test(handler, request_generator, response_validator); @@ -122,9 +122,9 @@ function test(handler, request_generator, response_validator) { { function handler(req, res) { - assert.strictEqual('1.1', req.httpVersion); - assert.strictEqual(1, req.httpVersionMajor); - assert.strictEqual(1, req.httpVersionMinor); + assert.strictEqual(req.httpVersion, '1.1'); + assert.strictEqual(req.httpVersionMajor, 1); + assert.strictEqual(req.httpVersionMinor, 1); res.sendDate = false; res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('Hello, '); res._send(''); @@ -155,9 +155,9 @@ function test(handler, request_generator, response_validator) { '0\r\n' + '\r\n'; - assert.strictEqual(expected_response, server_response); - assert.strictEqual(true, client_got_eof); - assert.strictEqual(false, timed_out); + assert.strictEqual(server_response, expected_response); + assert.strictEqual(client_got_eof, true); + assert.strictEqual(timed_out, false); } test(handler, request_generator, response_validator); diff --git a/test/parallel/test-http-blank-header.js b/test/parallel/test-http-blank-header.js index 40377fb6684db4..3f2b512fc85567 100644 --- a/test/parallel/test-http-blank-header.js +++ b/test/parallel/test-http-blank-header.js @@ -26,8 +26,8 @@ const http = require('http'); const net = require('net'); const server = http.createServer(common.mustCall((req, res) => { - assert.strictEqual('GET', req.method); - assert.strictEqual('/blah', req.url); + assert.strictEqual(req.method, 'GET'); + assert.strictEqual(req.url, '/blah'); assert.deepStrictEqual({ host: 'example.org:443', origin: 'http://example.org', diff --git a/test/parallel/test-http-chunked.js b/test/parallel/test-http-chunked.js index 9ae2932a5c4149..264a87be6adc7f 100644 --- a/test/parallel/test-http-chunked.js +++ b/test/parallel/test-http-chunked.js @@ -48,7 +48,7 @@ server.listen(0, common.mustCall(() => { x.setEncoding('utf8'); x.on('data', (c) => data += c); x.on('end', common.mustCall(() => { - assert.strictEqual('string', typeof data); + assert.strictEqual(typeof data, 'string'); assert.strictEqual(UTF8_STRING, data); server.close(); })); diff --git a/test/parallel/test-http-client-timeout-on-connect.js b/test/parallel/test-http-client-timeout-on-connect.js index 928f781e261758..3a0098229d9af8 100644 --- a/test/parallel/test-http-client-timeout-on-connect.js +++ b/test/parallel/test-http-client-timeout-on-connect.js @@ -24,7 +24,7 @@ server.listen(0, common.localhostIPv4, common.mustCall(() => { })); req.on('timeout', common.mustCall(() => req.abort())); req.on('error', common.mustCall((err) => { - assert.strictEqual('socket hang up', err.message); + assert.strictEqual(err.message, 'socket hang up'); server.close(); })); })); diff --git a/test/parallel/test-http-client-upload-buf.js b/test/parallel/test-http-client-upload-buf.js index b778d07a826b1d..1c75612c807874 100644 --- a/test/parallel/test-http-client-upload-buf.js +++ b/test/parallel/test-http-client-upload-buf.js @@ -27,8 +27,7 @@ const http = require('http'); const N = 1024; const server = http.createServer(common.mustCall(function(req, res) { - assert.strictEqual('POST', req.method); - + assert.strictEqual(req.method, 'POST'); let bytesReceived = 0; req.on('data', function(chunk) { diff --git a/test/parallel/test-http-client-upload.js b/test/parallel/test-http-client-upload.js index 000bf1d58424a3..830c37da8ef567 100644 --- a/test/parallel/test-http-client-upload.js +++ b/test/parallel/test-http-client-upload.js @@ -25,7 +25,7 @@ const assert = require('assert'); const http = require('http'); const server = http.createServer(common.mustCall(function(req, res) { - assert.strictEqual('POST', req.method); + assert.strictEqual(req.method, 'POST'); req.setEncoding('utf8'); let sent_body = ''; @@ -36,7 +36,7 @@ const server = http.createServer(common.mustCall(function(req, res) { }); req.on('end', common.mustCall(function() { - assert.strictEqual('1\n2\n3\n', sent_body); + assert.strictEqual(sent_body, '1\n2\n3\n'); console.log('request complete from server'); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('hello\n'); diff --git a/test/parallel/test-http-expect-continue.js b/test/parallel/test-http-expect-continue.js index eb4dd23d7b552f..10bcb9d568ff35 100644 --- a/test/parallel/test-http-expect-continue.js +++ b/test/parallel/test-http-expect-continue.js @@ -67,7 +67,7 @@ server.on('listening', common.mustCall(() => { })); req.on('response', common.mustCall((res) => { assert.ok(got_continue, 'Full response received before 100 Continue'); - assert.strictEqual(200, res.statusCode, + assert.strictEqual(res.statusCode, 200, `Final status code was ${res.statusCode}, not 200.`); res.setEncoding('utf8'); res.on('data', function(chunk) { body += chunk; }); diff --git a/test/parallel/test-http-outgoing-settimeout.js b/test/parallel/test-http-outgoing-settimeout.js new file mode 100644 index 00000000000000..3dd27686153672 --- /dev/null +++ b/test/parallel/test-http-outgoing-settimeout.js @@ -0,0 +1,30 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); + +const { OutgoingMessage } = require('http'); + +{ + // tests for settimeout method with socket + const expectedMsecs = 42; + const outgoingMessage = new OutgoingMessage(); + outgoingMessage.socket = { + setTimeout: common.mustCall((msecs) => { + assert.strictEqual(msecs, expectedMsecs); + }) + }; + outgoingMessage.setTimeout(expectedMsecs); +} + +{ + // tests for settimeout method without socket + const expectedMsecs = 23; + const outgoingMessage = new OutgoingMessage(); + outgoingMessage.setTimeout(expectedMsecs); + + outgoingMessage.emit('socket', { + setTimeout: common.mustCall((msecs) => { + assert.strictEqual(msecs, expectedMsecs); + }) + }); +} diff --git a/test/parallel/test-http-parser-bad-ref.js b/test/parallel/test-http-parser-bad-ref.js index aca94361b493aa..5b002b2ce0e926 100644 --- a/test/parallel/test-http-parser-bad-ref.js +++ b/test/parallel/test-http-parser-bad-ref.js @@ -25,7 +25,7 @@ function flushPool() { function demoBug(part1, part2) { flushPool(); - const parser = new HTTPParser(0); + const parser = new HTTPParser(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 new file mode 100644 index 00000000000000..c1eb29fb163d00 --- /dev/null +++ b/test/parallel/test-http-parser-lazy-loaded.js @@ -0,0 +1,37 @@ +// Flags: --expose-internals + +'use strict'; + +const { internalBinding } = require('internal/test/binding'); + +// Monkey patch before requiring anything +class DummyParser { + constructor(type) { + this.test_type = type; + } +} +DummyParser.REQUEST = Symbol(); +internalBinding('http_parser').HTTPParser = DummyParser; + +const common = require('../common'); +const assert = require('assert'); +const { spawn } = require('child_process'); +const { parsers } = require('_http_common'); + +// Test _http_common was not loaded before monkey patching +const parser = parsers.alloc(); +assert.strictEqual(parser instanceof DummyParser, true); +assert.strictEqual(parser.test_type, DummyParser.REQUEST); + +if (process.argv[2] !== 'child') { + // Also test in a child process with IPC (specific case of https://github.com/nodejs/node/issues/23716) + const child = spawn(process.execPath, [ + '--expose-internals', __filename, 'child' + ], { + stdio: ['inherit', 'inherit', 'inherit', 'ipc'] + }); + child.on('exit', common.mustCall((code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + })); +} diff --git a/test/parallel/test-http2-buffersize.js b/test/parallel/test-http2-buffersize.js new file mode 100644 index 00000000000000..be56d8ce3d9344 --- /dev/null +++ b/test/parallel/test-http2-buffersize.js @@ -0,0 +1,51 @@ +'use strict'; + +const { mustCall, hasCrypto, skip } = require('../common'); +if (!hasCrypto) + skip('missing crypto'); +const assert = require('assert'); +const { createServer, connect } = require('http2'); +const Countdown = require('../common/countdown'); + +// This test ensures that `bufferSize` of Http2Session and Http2Stream work +// as expected. +{ + const SOCKETS = 2; + const TIMES = 10; + const BUFFER_SIZE = 30; + const server = createServer(); + + // Other `bufferSize` tests for net module and tls module + // don't assert `bufferSize` of server-side sockets. + server.on('stream', mustCall((stream) => { + stream.on('data', mustCall()); + stream.on('end', mustCall()); + }, SOCKETS)); + + server.listen(0, mustCall(() => { + const authority = `http://localhost:${server.address().port}`; + const client = connect(authority); + const countdown = new Countdown(SOCKETS, () => { + client.close(); + server.close(); + }); + + client.once('connect', mustCall()); + + for (let j = 0; j < SOCKETS; j += 1) { + const stream = client.request({ ':method': 'POST' }); + stream.on('data', () => {}); + stream.on('close', mustCall(() => { + countdown.dec(); + })); + + for (let i = 0; i < TIMES; i += 1) { + stream.write(Buffer.allocUnsafe(BUFFER_SIZE), mustCall()); + const expectedSocketBufferSize = BUFFER_SIZE * (i + 1); + assert.strictEqual(stream.bufferSize, expectedSocketBufferSize); + } + stream.end(); + stream.close(); + } + })); +} diff --git a/test/parallel/test-http2-compat-serverrequest-pipe.js b/test/parallel/test-http2-compat-serverrequest-pipe.js index 53e54cdf913b0e..f5889073060b44 100644 --- a/test/parallel/test-http2-compat-serverrequest-pipe.js +++ b/test/parallel/test-http2-compat-serverrequest-pipe.js @@ -13,7 +13,7 @@ const path = require('path'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); -const loc = fixtures.path('url-tests.js'); +const loc = fixtures.path('person-large.jpg'); const fn = path.join(tmpdir.path, 'http2-url-tests.js'); const server = http2.createServer(); diff --git a/test/parallel/test-http2-pipe-named-pipe.js b/test/parallel/test-http2-pipe-named-pipe.js index 49fc142961d919..7882f79657f701 100644 --- a/test/parallel/test-http2-pipe-named-pipe.js +++ b/test/parallel/test-http2-pipe-named-pipe.js @@ -14,7 +14,7 @@ const path = require('path'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); -const loc = fixtures.path('url-tests.js'); +const loc = fixtures.path('person-large.jpg'); const fn = path.join(tmpdir.path, 'http2-url-tests.js'); const server = http2.createServer(); diff --git a/test/parallel/test-http2-pipe.js b/test/parallel/test-http2-pipe.js index d7dd99df91edb5..2e564d3e329dbc 100644 --- a/test/parallel/test-http2-pipe.js +++ b/test/parallel/test-http2-pipe.js @@ -13,7 +13,7 @@ const path = require('path'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); -const loc = fixtures.path('url-tests.js'); +const loc = fixtures.path('person-large.jpg'); const fn = path.join(tmpdir.path, 'http2-url-tests.js'); const server = http2.createServer(); diff --git a/test/parallel/test-http2-write-empty-string.js b/test/parallel/test-http2-write-empty-string.js index 6e6ce5254ddcfc..ea591176a47251 100644 --- a/test/parallel/test-http2-write-empty-string.js +++ b/test/parallel/test-http2-write-empty-string.js @@ -25,7 +25,7 @@ server.listen(0, common.mustCall(function() { let res = ''; req.on('response', common.mustCall(function(headers) { - assert.strictEqual(200, headers[':status']); + assert.strictEqual(headers[':status'], 200); })); req.on('data', (chunk) => { @@ -33,7 +33,7 @@ server.listen(0, common.mustCall(function() { }); req.on('end', common.mustCall(function() { - assert.strictEqual('1\n2\n3\n', res); + assert.strictEqual(res, '1\n2\n3\n'); client.close(); })); diff --git a/test/parallel/test-icu-punycode.js b/test/parallel/test-icu-punycode.js index 3744891ee098de..2501b1d86e7b88 100644 --- a/test/parallel/test-icu-punycode.js +++ b/test/parallel/test-icu-punycode.js @@ -10,7 +10,10 @@ const icu = internalBinding('icu'); const assert = require('assert'); const tests = require('../fixtures/url-idna.js'); -const wptToASCIITests = require('../fixtures/url-toascii.js'); +const fixtures = require('../common/fixtures'); +const wptToASCIITests = require( + fixtures.path('wpt', 'url', 'resources', 'toascii.json') +); { for (const [i, { ascii, unicode }] of tests.entries()) { diff --git a/test/parallel/test-internal-errors.js b/test/parallel/test-internal-errors.js index 7d5dcce0d40c6a..bf4688d89bd0ca 100644 --- a/test/parallel/test-internal-errors.js +++ b/test/parallel/test-internal-errors.js @@ -10,6 +10,10 @@ const { internalBinding } = require('internal/test/binding'); const assert = require('assert'); const errors = require('internal/errors'); +// Turn off ANSI color formatting for this test file. +const { inspect } = require('util'); +inspect.defaultOptions.colors = false; + errors.E('TEST_ERROR_1', 'Error for testing purposes: %s', Error, TypeError, RangeError); errors.E('TEST_ERROR_2', (a, b) => `${a} ${b}`, Error); diff --git a/test/parallel/test-listen-fd-detached-inherit.js b/test/parallel/test-listen-fd-detached-inherit.js index b4fce58c93390d..4feb7dc3ab03dd 100644 --- a/test/parallel/test-listen-fd-detached-inherit.js +++ b/test/parallel/test-listen-fd-detached-inherit.js @@ -69,7 +69,7 @@ function test() { process.kill(child.pid, 'SIGKILL'); try { parent.kill(); - } catch (e) {} + } catch {} assert.strictEqual(s, 'hello from child\n'); assert.strictEqual(res.statusCode, 200); diff --git a/test/parallel/test-listen-fd-detached.js b/test/parallel/test-listen-fd-detached.js index 6fbc938324549e..09d7f8b6c1a68c 100644 --- a/test/parallel/test-listen-fd-detached.js +++ b/test/parallel/test-listen-fd-detached.js @@ -69,7 +69,7 @@ function test() { process.kill(child.pid, 'SIGKILL'); try { parent.kill(); - } catch (e) {} + } catch {} assert.strictEqual(s, 'hello from child\n'); assert.strictEqual(res.statusCode, 200); diff --git a/test/parallel/test-listen-fd-ebadf.js b/test/parallel/test-listen-fd-ebadf.js index 564dea7f951a1a..3ec40b5c23a1f2 100644 --- a/test/parallel/test-listen-fd-ebadf.js +++ b/test/parallel/test-listen-fd-ebadf.js @@ -34,7 +34,7 @@ let invalidFd = 2; // Get first known bad file descriptor. try { while (fs.fstatSync(++invalidFd)); -} catch (e) { +} catch { // do nothing; we now have an invalid fd } diff --git a/test/parallel/test-loaders-unknown-builtin-module.mjs b/test/parallel/test-loaders-unknown-builtin-module.mjs new file mode 100644 index 00000000000000..db3cfa3582e9e2 --- /dev/null +++ b/test/parallel/test-loaders-unknown-builtin-module.mjs @@ -0,0 +1,12 @@ +// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs +import { expectsError, mustCall } from '../common'; +import assert from 'assert'; + +const unknownBuiltinModule = 'unknown-builtin-module'; + +import(unknownBuiltinModule) +.then(assert.fail, expectsError({ + code: 'ERR_UNKNOWN_BUILTIN_MODULE', + message: `No such built-in module: ${unknownBuiltinModule}` +})) +.then(mustCall()); diff --git a/test/parallel/test-module-loading-error.js b/test/parallel/test-module-loading-error.js index 86932bd759d20c..f2351e708f2e93 100644 --- a/test/parallel/test-module-loading-error.js +++ b/test/parallel/test-module-loading-error.js @@ -45,7 +45,7 @@ if (common.isWindows) { try { // If MUI != 'en' we'll ignore the content of the message localeOk = execSync(powerShellFindMUI).toString('utf8').trim() === 'en'; - } catch (_) { + } catch { // It's only a best effort try to find the MUI } } diff --git a/test/parallel/test-module-multi-extensions.js b/test/parallel/test-module-multi-extensions.js new file mode 100644 index 00000000000000..be17bc5d025508 --- /dev/null +++ b/test/parallel/test-module-multi-extensions.js @@ -0,0 +1,94 @@ +'use strict'; + +// Refs: https://github.com/nodejs/node/issues/4778 + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const Module = require('module'); +const tmpdir = require('../common/tmpdir'); +const file = path.join(tmpdir.path, 'test-extensions.foo.bar'); +const dotfile = path.join(tmpdir.path, '.bar'); +const dotfileWithExtension = path.join(tmpdir.path, '.foo.bar'); + +tmpdir.refresh(); +fs.writeFileSync(file, 'console.log(__filename);', 'utf8'); +fs.writeFileSync(dotfile, 'console.log(__filename);', 'utf8'); +fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); + +{ + require.extensions['.bar'] = common.mustNotCall(); + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions'); + require(modulePath); + require(file); + delete require.cache[file]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions'); + require(modulePath); + assert.throws( + () => require(`${modulePath}.foo`), + new Error(`Cannot find module '${modulePath}.foo'`) + ); + require(`${modulePath}.foo.bar`); + delete require.cache[file]; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + const modulePath = path.join(tmpdir.path, 'test-extensions'); + assert.throws( + () => require(modulePath), + new Error(`Cannot find module '${modulePath}'`) + ); + delete require.cache[file]; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustNotCall(); + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions.foo'); + require(modulePath); + delete require.cache[file]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.foo.bar'] = common.mustNotCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions.foo'); + assert.throws( + () => require(modulePath), + new Error(`Cannot find module '${modulePath}'`) + ); + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustNotCall(); + require(dotfile); + delete require.cache[dotfile]; + delete require.extensions['.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustCall(); + require.extensions['.foo.bar'] = common.mustNotCall(); + require(dotfileWithExtension); + delete require.cache[dotfileWithExtension]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} diff --git a/test/parallel/test-net-connect-buffer.js b/test/parallel/test-net-connect-buffer.js index f58820d58edfdd..81dd8f0c569c71 100644 --- a/test/parallel/test-net-connect-buffer.js +++ b/test/parallel/test-net-connect-buffer.js @@ -44,8 +44,10 @@ tcp.listen(0, common.mustCall(function() { const socket = net.Stream({ highWaterMark: 0 }); let connected = false; + assert.strictEqual(socket.pending, true); socket.connect(this.address().port, common.mustCall(() => connected = true)); + assert.strictEqual(socket.pending, true); assert.strictEqual(socket.connecting, true); assert.strictEqual(socket.readyState, 'opening'); @@ -87,6 +89,10 @@ tcp.listen(0, common.mustCall(function() { console.error('write cb'); assert.ok(connected); assert.strictEqual(socket.bytesWritten, Buffer.from(a + b).length); + assert.strictEqual(socket.pending, false); + })); + socket.on('close', common.mustCall(() => { + assert.strictEqual(socket.pending, true); })); assert.strictEqual(socket.bytesWritten, Buffer.from(a).length); diff --git a/test/parallel/test-net-connect-options-fd.js b/test/parallel/test-net-connect-options-fd.js index 468e230ec7370a..94b831bf5d2ac3 100644 --- a/test/parallel/test-net-connect-options-fd.js +++ b/test/parallel/test-net-connect-options-fd.js @@ -70,7 +70,7 @@ const forAllClients = (cb) => common.mustCall(cb, CLIENT_VARIANTS); }) .on('error', function(err) { console.error(err); - assert.fail(null, null, `[Pipe server]${err}`); + assert.fail(`[Pipe server]${err}`); }) .listen({ path: serverPath }, common.mustCall(function serverOnListen() { const getSocketOpt = (index) => { @@ -94,7 +94,7 @@ const forAllClients = (cb) => common.mustCall(cb, CLIENT_VARIANTS); console.error(`[Pipe]Sending data through fd ${oldHandle.fd}`); this.on('error', function(err) { console.error(err); - assert.fail(null, null, `[Pipe Client]${err}`); + assert.fail(`[Pipe Client]${err}`); }); }); diff --git a/test/parallel/test-net-eaddrinuse.js b/test/parallel/test-net-eaddrinuse.js index 8c3bcc6cf142dc..29508e4582852e 100644 --- a/test/parallel/test-net-eaddrinuse.js +++ b/test/parallel/test-net-eaddrinuse.js @@ -30,7 +30,7 @@ const server2 = net.createServer(function(socket) { }); server1.listen(0, function() { server2.on('error', function(error) { - assert.strictEqual(true, error.message.includes('EADDRINUSE')); + assert.strictEqual(error.message.includes('EADDRINUSE'), true); server1.close(); }); server2.listen(this.address().port); diff --git a/test/parallel/test-net-server-listen-path.js b/test/parallel/test-net-server-listen-path.js index cc73c3fd438abe..cc7c6678b04224 100644 --- a/test/parallel/test-net-server-listen-path.js +++ b/test/parallel/test-net-server-listen-path.js @@ -69,3 +69,23 @@ function randomPipePath() { srv.close(); })); } + +// Test should emit "error" events when listening fails. +{ + const handlePath = randomPipePath(); + const srv1 = net.createServer().listen({ path: handlePath }, () => { + // As the handlePath is in use, binding to the same address again should + // make the server emit an 'EADDRINUSE' error. + const srv2 = net.createServer() + .listen({ + path: handlePath, + writableAll: true, + }, common.mustNotCall()); + + srv2.on('error', common.mustCall((err) => { + srv1.close(); + assert.strictEqual(err.code, 'EADDRINUSE'); + assert(/^listen EADDRINUSE: address already in use/.test(err.message)); + })); + }); +} diff --git a/test/parallel/test-net-socket-setnodelay.js b/test/parallel/test-net-socket-setnodelay.js new file mode 100644 index 00000000000000..be5c8ffc8524dc --- /dev/null +++ b/test/parallel/test-net-socket-setnodelay.js @@ -0,0 +1,43 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); + +const truthyValues = [true, 1, 'true', {}, []]; +const falseyValues = [false, 0, '']; +const genSetNoDelay = (desiredArg) => (enable) => { + assert.strictEqual(enable, desiredArg); +}; + +// setNoDelay should default to true +let socket = new net.Socket({ + handle: { + setNoDelay: common.mustCall(genSetNoDelay(true)) + } +}); +socket.setNoDelay(); + +socket = new net.Socket({ + handle: { + setNoDelay: common.mustCall(genSetNoDelay(true), truthyValues.length) + } +}); +truthyValues.forEach((testVal) => socket.setNoDelay(testVal)); + +socket = new net.Socket({ + handle: { + setNoDelay: common.mustCall(genSetNoDelay(false), falseyValues.length) + } +}); +falseyValues.forEach((testVal) => socket.setNoDelay(testVal)); + +// if a handler doesn't have a setNoDelay function it shouldn't be called. +// In the case below, if it is called an exception will be thrown +socket = new net.Socket({ + handle: { + setNoDelay: null + } +}); +const returned = socket.setNoDelay(true); +assert.ok(returned instanceof net.Socket); diff --git a/test/parallel/test-net-stream.js b/test/parallel/test-net-stream.js index a6ec4548ada6ea..4e7e06bfcf2546 100644 --- a/test/parallel/test-net-stream.js +++ b/test/parallel/test-net-stream.js @@ -34,11 +34,11 @@ s.server = new net.Server(); s.server.connections = 10; s._server = s.server; -assert.strictEqual(10, s.server.connections); +assert.strictEqual(s.server.connections, 10); s.destroy(); -assert.strictEqual(9, s.server.connections); +assert.strictEqual(s.server.connections, 9); s.destroy(); -assert.strictEqual(9, s.server.connections); +assert.strictEqual(s.server.connections, 9); const SIZE = 2E6; const N = 10; @@ -69,5 +69,5 @@ const server = net.createServer(function(socket) { }); process.on('exit', function() { - assert.strictEqual(0, server.connections); + assert.strictEqual(server.connections, 0); }); diff --git a/test/parallel/test-os.js b/test/parallel/test-os.js index 3591ee52104ea4..9b86d3af8b263e 100644 --- a/test/parallel/test-os.js +++ b/test/parallel/test-os.js @@ -92,6 +92,15 @@ assert.ok(uptime > 0); const cpus = os.cpus(); is.array(cpus); assert.ok(cpus.length > 0); +for (const cpu of cpus) { + assert.strictEqual(typeof cpu.model, 'string'); + assert.strictEqual(typeof cpu.speed, 'number'); + assert.strictEqual(typeof cpu.times.user, 'number'); + assert.strictEqual(typeof cpu.times.nice, 'number'); + assert.strictEqual(typeof cpu.times.sys, 'number'); + assert.strictEqual(typeof cpu.times.idle, 'number'); + assert.strictEqual(typeof cpu.times.irq, 'number'); +} const type = os.type(); is.string(type); diff --git a/test/parallel/test-priority-queue.js b/test/parallel/test-priority-queue.js index 702b5528ba9611..f8526e6521c24b 100644 --- a/test/parallel/test-priority-queue.js +++ b/test/parallel/test-priority-queue.js @@ -131,3 +131,33 @@ const PriorityQueue = require('internal/priority_queue'); assert.strictEqual(queue.shift(), undefined); } + + +{ + // Checks that removeAt respects binary heap properties + const queue = new PriorityQueue((a, b) => { + return a.value - b.value; + }, (node, pos) => (node.position = pos)); + + const i3 = { value: 3, position: null }; + const i7 = { value: 7, position: null }; + const i8 = { value: 8, position: null }; + + queue.insert({ value: 1, position: null }); + queue.insert({ value: 6, position: null }); + queue.insert({ value: 2, position: null }); + queue.insert(i7); + queue.insert(i8); + queue.insert(i3); + + assert.strictEqual(i7.position, 4); + queue.removeAt(4); + + // 3 should percolate up to swap with 6 (up) + assert.strictEqual(i3.position, 2); + + queue.removeAt(2); + + // 8 should swap places with 6 (down) + assert.strictEqual(i8.position, 4); +} diff --git a/test/parallel/test-process-env.js b/test/parallel/test-process-env.js index 69379f60061985..51cc637d06e5c4 100644 --- a/test/parallel/test-process-env.js +++ b/test/parallel/test-process-env.js @@ -26,12 +26,12 @@ const assert = require('assert'); // changes in environment should be visible to child processes if (process.argv[2] === 'you-are-the-child') { - assert.strictEqual(false, 'NODE_PROCESS_ENV_DELETED' in process.env); - assert.strictEqual('42', process.env.NODE_PROCESS_ENV); - assert.strictEqual('asdf', process.env.hasOwnProperty); + assert.strictEqual('NODE_PROCESS_ENV_DELETED' in process.env, false); + assert.strictEqual(process.env.NODE_PROCESS_ENV, '42'); + assert.strictEqual(process.env.hasOwnProperty, 'asdf'); const hasOwnProperty = Object.prototype.hasOwnProperty; const has = hasOwnProperty.call(process.env, 'hasOwnProperty'); - assert.strictEqual(true, has); + assert.strictEqual(has, true); process.exit(0); } @@ -41,18 +41,18 @@ if (process.argv[2] === 'you-are-the-child') { assert.strictEqual(Object.prototype.hasOwnProperty, process.env.hasOwnProperty); const has = process.env.hasOwnProperty('hasOwnProperty'); - assert.strictEqual(false, has); + assert.strictEqual(has, false); process.env.hasOwnProperty = 'asdf'; process.env.NODE_PROCESS_ENV = 42; - assert.strictEqual('42', process.env.NODE_PROCESS_ENV); + assert.strictEqual(process.env.NODE_PROCESS_ENV, '42'); process.env.NODE_PROCESS_ENV_DELETED = 42; - assert.strictEqual(true, 'NODE_PROCESS_ENV_DELETED' in process.env); + assert.strictEqual('NODE_PROCESS_ENV_DELETED' in process.env, true); delete process.env.NODE_PROCESS_ENV_DELETED; - assert.strictEqual(false, 'NODE_PROCESS_ENV_DELETED' in process.env); + assert.strictEqual('NODE_PROCESS_ENV_DELETED' in process.env, false); const child = spawn(process.argv[0], [process.argv[1], 'you-are-the-child']); child.stdout.on('data', function(data) { console.log(data.toString()); }); @@ -91,6 +91,7 @@ assert.strictEqual(5, date.getHours()); // case-sensitive on other platforms. process.env.TEST = 'test'; assert.strictEqual(process.env.TEST, 'test'); + // Check both mixed case and lower case, to avoid any regressions that might // simply convert input to lower case. if (common.isWindows) { @@ -100,3 +101,8 @@ if (common.isWindows) { assert.strictEqual(process.env.test, undefined); assert.strictEqual(process.env.teST, undefined); } + +{ + const keys = Object.keys(process.env); + assert.ok(keys.length > 0); +} diff --git a/test/parallel/test-process-getactiverequests.js b/test/parallel/test-process-getactiverequests.js index f55f298298d446..41883d35aa7dbc 100644 --- a/test/parallel/test-process-getactiverequests.js +++ b/test/parallel/test-process-getactiverequests.js @@ -7,4 +7,4 @@ const fs = require('fs'); for (let i = 0; i < 12; i++) fs.open(__filename, 'r', () => {}); -assert.strictEqual(12, process._getActiveRequests().length); +assert.strictEqual(process._getActiveRequests().length, 12); diff --git a/test/parallel/test-process-initgroups.js b/test/parallel/test-process-initgroups.js new file mode 100644 index 00000000000000..49b8833f61a7bc --- /dev/null +++ b/test/parallel/test-process-initgroups.js @@ -0,0 +1,54 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); + +if (common.isWindows || !common.isMainThread) { + assert.strictEqual(process.initgroups, undefined); + return; +} + +[undefined, null, true, {}, [], () => {}].forEach((val) => { + assert.throws( + () => { + process.initgroups(val); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError [ERR_INVALID_ARG_TYPE]', + message: + 'The "user" argument must be ' + + 'one of type number or string. ' + + `Received type ${typeof val}` + } + ); +}); + +[undefined, null, true, {}, [], () => {}].forEach((val) => { + assert.throws( + () => { + process.initgroups('foo', val); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError [ERR_INVALID_ARG_TYPE]', + message: + 'The "extraGroup" argument must be ' + + 'one of type number or string. ' + + `Received type ${typeof val}` + } + ); +}); + +assert.throws( + () => { + process.initgroups( + 'fhqwhgadshgnsdhjsdbkhsdabkfabkveyb', + 'fhqwhgadshgnsdhjsdbkhsdabkfabkveyb' + ); + }, + { + code: 'ERR_UNKNOWN_CREDENTIAL', + message: + 'Group identifier does not exist: fhqwhgadshgnsdhjsdbkhsdabkfabkveyb' + } +); diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index e8527fe574a53a..ba7b9e70b2a9b8 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -2,7 +2,7 @@ const common = require('../common'); const assert = require('assert'); -const expected_keys = ['ares', 'http_parser', 'modules', 'node', +const expected_keys = ['ares', 'modules', 'node', 'uv', 'v8', 'zlib', 'nghttp2', 'napi']; if (common.hasCrypto) { @@ -16,6 +16,9 @@ if (common.hasIntl) { expected_keys.push('unicode'); } +expected_keys.push( + process.versions.llhttp === undefined ? 'http_parser' : 'llhttp'); + expected_keys.sort(); const actual_keys = Object.keys(process.versions).sort(); @@ -24,7 +27,8 @@ assert.deepStrictEqual(actual_keys, expected_keys); const commonTemplate = /^\d+\.\d+\.\d+(?:-.*)?$/; assert(commonTemplate.test(process.versions.ares)); -assert(commonTemplate.test(process.versions.http_parser)); +assert(commonTemplate.test(process.versions.llhttp === undefined ? + process.versions.http_parser : process.versions.llhttp)); assert(commonTemplate.test(process.versions.node)); assert(commonTemplate.test(process.versions.uv)); assert(commonTemplate.test(process.versions.zlib)); diff --git a/test/parallel/test-promises-unhandled-rejections.js b/test/parallel/test-promises-unhandled-rejections.js index d336630f7cf8ce..93ac186a3b45f6 100644 --- a/test/parallel/test-promises-unhandled-rejections.js +++ b/test/parallel/test-promises-unhandled-rejections.js @@ -681,7 +681,7 @@ asyncTest('Throwing an error inside a rejectionHandled handler goes to' + setTimeout(function() { try { p.catch(function() {}); - } catch (e) { + } catch { done(new Error('fail')); } }, 1); diff --git a/test/parallel/test-readline-keys.js b/test/parallel/test-readline-keys.js index f739999110b12f..b1c88e2acee157 100644 --- a/test/parallel/test-readline-keys.js +++ b/test/parallel/test-readline-keys.js @@ -99,15 +99,21 @@ addTest('\n\r\t', [ ]); // space and backspace -addTest('\b\x7f\x1b\b\x1b\x7f \x1b ', [ +addTest('\b\x7f\x1b\b\x1b\x7f\x1b\x1b \x1b ', [ { name: 'backspace', sequence: '\b' }, { name: 'backspace', sequence: '\x7f' }, { name: 'backspace', sequence: '\x1b\b', meta: true }, { name: 'backspace', sequence: '\x1b\x7f', meta: true }, + { name: 'space', sequence: '\x1b\x1b ', meta: true }, { name: 'space', sequence: ' ' }, { name: 'space', sequence: '\x1b ', meta: true }, ]); +// escape key +addTest('\x1b\x1b\x1b', [ + { name: 'escape', sequence: '\x1b\x1b\x1b', meta: true }, +]); + // control keys addTest('\x01\x0b\x10', [ { name: 'a', sequence: '\x01', ctrl: true }, diff --git a/test/parallel/test-repl-persistent-history.js b/test/parallel/test-repl-persistent-history.js index bb10085eccfcf6..32bab3c8ed9f83 100644 --- a/test/parallel/test-repl-persistent-history.js +++ b/test/parallel/test-repl-persistent-history.js @@ -111,6 +111,13 @@ const tests = [ test: [UP], expected: [prompt, replFailedRead, prompt, replDisabled, prompt] }, + { // Tests multiline history + env: {}, + test: ['{', '}', UP, CLEAR], + expected: [prompt, '{', '... ', '}', '{}\n', + prompt, `${prompt}{}`, prompt], + clean: false + }, { before: function before() { if (common.isWindows) { diff --git a/test/parallel/test-repl-syntax-error-handling.js b/test/parallel/test-repl-syntax-error-handling.js index f61ab077eb638c..91a8614d1deb93 100644 --- a/test/parallel/test-repl-syntax-error-handling.js +++ b/test/parallel/test-repl-syntax-error-handling.js @@ -63,7 +63,7 @@ function child() { let caught; try { vm.runInThisContext('haf!@##&$!@$*!@', { displayErrors: false }); - } catch (er) { + } catch { caught = true; } assert(caught); diff --git a/test/parallel/test-require-deps-deprecation.js b/test/parallel/test-require-deps-deprecation.js index 80bf66d7f6b74f..5bee24a5db19ce 100644 --- a/test/parallel/test-require-deps-deprecation.js +++ b/test/parallel/test-require-deps-deprecation.js @@ -34,7 +34,7 @@ common.expectWarning('DeprecationWarning', deprecatedModules.map((m) => { for (const m of deprecatedModules) { try { require(m); - } catch (err) {} + } catch {} } // Instead of checking require, check that resolve isn't pointing toward a diff --git a/test/parallel/test-stdout-close-catch.js b/test/parallel/test-stdout-close-catch.js index e9b559c9f24cd0..6c0db3ea904a7d 100644 --- a/test/parallel/test-stdout-close-catch.js +++ b/test/parallel/test-stdout-close-catch.js @@ -27,7 +27,7 @@ child.stderr.on('data', function(c) { child.on('close', common.mustCall(function(code) { try { output = JSON.parse(output); - } catch (er) { + } catch { console.error(output); process.exit(1); } diff --git a/test/parallel/test-stdout-to-file.js b/test/parallel/test-stdout-to-file.js index a02531ca41fbdb..f23bbea279d324 100644 --- a/test/parallel/test-stdout-to-file.js +++ b/test/parallel/test-stdout-to-file.js @@ -19,7 +19,7 @@ function test(size, useBuffer, cb) { try { fs.unlinkSync(tmpFile); - } catch (e) {} + } catch {} console.log(`${size} chars to ${tmpFile}...`); diff --git a/test/parallel/test-stream-auto-destroy.js b/test/parallel/test-stream-auto-destroy.js new file mode 100644 index 00000000000000..2a1a5190debb57 --- /dev/null +++ b/test/parallel/test-stream-auto-destroy.js @@ -0,0 +1,112 @@ +'use strict'; +const common = require('../common'); +const stream = require('stream'); +const assert = require('assert'); + +{ + const r = new stream.Readable({ + autoDestroy: true, + read() { + this.push('hello'); + this.push('world'); + this.push(null); + }, + destroy: common.mustCall((err, cb) => cb()) + }); + + let ended = false; + + r.resume(); + + r.on('end', common.mustCall(() => { + ended = true; + })); + + r.on('close', common.mustCall(() => { + assert(ended); + })); +} + +{ + const w = new stream.Writable({ + autoDestroy: true, + write(data, enc, cb) { + cb(null); + }, + destroy: common.mustCall((err, cb) => cb()) + }); + + let finished = false; + + w.write('hello'); + w.write('world'); + w.end(); + + w.on('finish', common.mustCall(() => { + finished = true; + })); + + w.on('close', common.mustCall(() => { + assert(finished); + })); +} + +{ + const t = new stream.Transform({ + autoDestroy: true, + transform(data, enc, cb) { + cb(null, data); + }, + destroy: common.mustCall((err, cb) => cb()) + }); + + let ended = false; + let finished = false; + + t.write('hello'); + t.write('world'); + t.end(); + + t.resume(); + + t.on('end', common.mustCall(() => { + ended = true; + })); + + t.on('finish', common.mustCall(() => { + finished = true; + })); + + t.on('close', common.mustCall(() => { + assert(ended); + assert(finished); + })); +} + +{ + const r = new stream.Readable({ + read() { + r2.emit('error', new Error('fail')); + } + }); + const r2 = new stream.Readable({ + autoDestroy: true, + destroy: common.mustCall((err, cb) => cb()) + }); + + r.pipe(r2); +} + +{ + const r = new stream.Readable({ + read() { + w.emit('error', new Error('fail')); + } + }); + const w = new stream.Writable({ + autoDestroy: true, + destroy: common.mustCall((err, cb) => cb()) + }); + + r.pipe(w); +} diff --git a/test/parallel/test-stream-write-destroy.js b/test/parallel/test-stream-write-destroy.js new file mode 100644 index 00000000000000..83b329a6a8a7b3 --- /dev/null +++ b/test/parallel/test-stream-write-destroy.js @@ -0,0 +1,59 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const { Writable } = require('stream'); + +// Test interaction between calling .destroy() on a writable and pending +// writes. + +for (const withPendingData of [ false, true ]) { + for (const useEnd of [ false, true ]) { + const callbacks = []; + + const w = new Writable({ + write(data, enc, cb) { + callbacks.push(cb); + }, + // Effectively disable the HWM to observe 'drain' events more easily. + highWaterMark: 1 + }); + + let chunksWritten = 0; + let drains = 0; + let finished = false; + w.on('drain', () => drains++); + w.on('finish', () => finished = true); + + w.write('abc', () => chunksWritten++); + assert.strictEqual(chunksWritten, 0); + assert.strictEqual(drains, 0); + callbacks.shift()(); + assert.strictEqual(chunksWritten, 1); + assert.strictEqual(drains, 1); + + if (withPendingData) { + // Test 2 cases: There either is or is not data still in the write queue. + // (The second write will never actually get executed either way.) + w.write('def', () => chunksWritten++); + } + if (useEnd) { + // Again, test 2 cases: Either we indicate that we want to end the + // writable or not. + w.end('ghi', () => chunksWritten++); + } else { + w.write('ghi', () => chunksWritten++); + } + + assert.strictEqual(chunksWritten, 1); + w.destroy(); + assert.strictEqual(chunksWritten, 1); + callbacks.shift()(); + assert.strictEqual(chunksWritten, 2); + assert.strictEqual(callbacks.length, 0); + assert.strictEqual(drains, 1); + + // When we used `.end()`, we see the 'finished' event if and only if + // we actually finished processing the write queue. + assert.strictEqual(finished, !withPendingData && useEnd); + } +} diff --git a/test/parallel/test-string-decoder.js b/test/parallel/test-string-decoder.js index 04e1d8c8fe2849..c043795fc6ee5e 100644 --- a/test/parallel/test-string-decoder.js +++ b/test/parallel/test-string-decoder.js @@ -228,7 +228,7 @@ function test(encoding, input, expected, singleSequence) { `input: ${input.toString('hex').match(hexNumberRE)}\n` + `Write sequence: ${JSON.stringify(sequence)}\n` + `Full Decoder State: ${inspect(decoder)}`; - assert.fail(output, expected, message); + assert.fail(message); } }); } diff --git a/test/parallel/test-timers-now.js b/test/parallel/test-timers-now.js index bd8faaa6c732cc..91b3f63496da2b 100644 --- a/test/parallel/test-timers-now.js +++ b/test/parallel/test-timers-now.js @@ -3,7 +3,8 @@ require('../common'); const assert = require('assert'); -const { getLibuvNow } = require('internal/timers'); +const { internalBinding } = require('internal/test/binding'); +const { getLibuvNow } = internalBinding('timers'); // Return value of getLibuvNow() should easily fit in a SMI after start-up. assert(getLibuvNow() < 0x3ffffff); diff --git a/test/parallel/test-timers-ordering.js b/test/parallel/test-timers-ordering.js index d9629e03190679..e163ea55bf2dd8 100644 --- a/test/parallel/test-timers-ordering.js +++ b/test/parallel/test-timers-ordering.js @@ -24,7 +24,8 @@ 'use strict'; require('../common'); const assert = require('assert'); -const { getLibuvNow } = require('internal/timers'); +const { internalBinding } = require('internal/test/binding'); +const { getLibuvNow } = internalBinding('timers'); const N = 30; diff --git a/test/parallel/test-tls-invoke-queued.js b/test/parallel/test-tls-invoke-queued.js index 754b02ba0bae99..482ab847352793 100644 --- a/test/parallel/test-tls-invoke-queued.js +++ b/test/parallel/test-tls-invoke-queued.js @@ -40,8 +40,8 @@ const server = tls.createServer({ c.write('world!', null, common.mustCall(function() { c.destroy(); })); - // Data on next _write() will be written but callback will not be invoked - c.write(' gosh', null, common.mustNotCall()); + // Data on next _write() will be written, and the cb will still be invoked + c.write(' gosh', null, common.mustCall()); })); server.close(); diff --git a/test/parallel/test-tls-net-socket-keepalive.js b/test/parallel/test-tls-net-socket-keepalive.js new file mode 100644 index 00000000000000..c184e902b42685 --- /dev/null +++ b/test/parallel/test-tls-net-socket-keepalive.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const fixtures = require('../common/fixtures'); +const tls = require('tls'); +const net = require('net'); + +// This test ensures that when tls sockets are created with `allowHalfOpen`, +// they won't hang. +const key = fixtures.readKey('agent1-key.pem'); +const cert = fixtures.readKey('agent1-cert.pem'); +const ca = fixtures.readKey('ca1-cert.pem'); +const options = { + key, + cert, + ca: [ca], +}; + +const server = tls.createServer(options, common.mustCall((conn) => { + conn.write('hello'); + conn.on('data', common.mustCall()); + conn.end(); +})).listen(0, common.mustCall(() => { + const netSocket = new net.Socket({ + allowHalfOpen: true, + }); + + const socket = tls.connect({ + socket: netSocket, + rejectUnauthorized: false, + }); + + const { port, address } = server.address(); + + // Doing `net.Socket.connect()` after `tls.connect()` will make tls module + // wrap the socket in StreamWrap. + netSocket.connect({ + port, + address, + }); + + socket.on('end', common.mustCall()); + socket.on('data', common.mustCall()); + socket.on('close', common.mustCall(() => { + server.close(); + })); + + socket.write('hello'); + socket.end(); +})); diff --git a/test/parallel/test-tls-peer-certificate-multi-keys.js b/test/parallel/test-tls-peer-certificate-multi-keys.js index b178daa2ba9328..a2548d6bcffb9e 100644 --- a/test/parallel/test-tls-peer-certificate-multi-keys.js +++ b/test/parallel/test-tls-peer-certificate-multi-keys.js @@ -26,7 +26,6 @@ if (!common.hasCrypto) const assert = require('assert'); const tls = require('tls'); -const util = require('util'); const fixtures = require('../common/fixtures'); const options = { @@ -37,13 +36,22 @@ const options = { const server = tls.createServer(options, function(cleartext) { cleartext.end('World'); }); + +server.once('secureConnection', common.mustCall(function(socket) { + const cert = socket.getCertificate(); + // The server's local cert is the client's peer cert. + assert.deepStrictEqual( + cert.subject.OU, + ['Information Technology', 'Engineering', 'Marketing'] + ); +})); + server.listen(0, common.mustCall(function() { const socket = tls.connect({ port: this.address().port, rejectUnauthorized: false }, common.mustCall(function() { const peerCert = socket.getPeerCertificate(); - console.error(util.inspect(peerCert)); assert.deepStrictEqual( peerCert.subject.OU, ['Information Technology', 'Engineering', 'Marketing'] diff --git a/test/parallel/test-tls-peer-certificate.js b/test/parallel/test-tls-peer-certificate.js index 266f5571410fb4..5eac36628d658e 100644 --- a/test/parallel/test-tls-peer-certificate.js +++ b/test/parallel/test-tls-peer-certificate.js @@ -43,6 +43,8 @@ connect({ }, function(err, pair, cleanup) { assert.ifError(err); const socket = pair.client.conn; + const localCert = socket.getCertificate(); + assert.deepStrictEqual(localCert, {}); let peerCert = socket.getPeerCertificate(); assert.ok(!peerCert.issuerCertificate); diff --git a/test/parallel/test-tls-pfx-authorizationerror.js b/test/parallel/test-tls-pfx-authorizationerror.js index 64b6e1485dc538..a4ea97f104e564 100644 --- a/test/parallel/test-tls-pfx-authorizationerror.js +++ b/test/parallel/test-tls-pfx-authorizationerror.js @@ -22,6 +22,8 @@ const server = tls rejectUnauthorized: false }, common.mustCall(function(c) { + assert.strictEqual(c.getPeerCertificate().serialNumber, + 'FAD50CC6A07F516C'); assert.strictEqual(c.authorizationError, null); c.end(); }) @@ -35,6 +37,8 @@ const server = tls rejectUnauthorized: false }, function() { + assert.strictEqual(client.getCertificate().serialNumber, + 'FAD50CC6A07F516C'); client.end(); server.close(); } diff --git a/test/parallel/test-tls-streamwrap-buffersize.js b/test/parallel/test-tls-streamwrap-buffersize.js new file mode 100644 index 00000000000000..f65a3d6e76b9d8 --- /dev/null +++ b/test/parallel/test-tls-streamwrap-buffersize.js @@ -0,0 +1,72 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const makeDuplexPair = require('../common/duplexpair'); +const tls = require('tls'); +const net = require('net'); + +// This test ensures that `bufferSize` also works for those tlsSockets +// created from `socket` of `Duplex`, with which, TLSSocket will wrap +// sockets in `StreamWrap`. +{ + const iter = 10; + + function createDuplex(port) { + const { clientSide, serverSide } = makeDuplexPair(); + + return new Promise((resolve, reject) => { + const socket = net.connect({ + port, + }, common.mustCall(() => { + clientSide.pipe(socket); + socket.pipe(clientSide); + clientSide.on('close', common.mustCall(() => socket.destroy())); + socket.on('close', common.mustCall(() => clientSide.destroy())); + + resolve(serverSide); + })); + }); + } + + const server = tls.createServer({ + key: fixtures.readKey('agent2-key.pem'), + cert: fixtures.readKey('agent2-cert.pem') + }, common.mustCall((socket) => { + let str = ''; + socket.setEncoding('utf-8'); + socket.on('data', (chunk) => { str += chunk; }); + + socket.on('end', common.mustCall(() => { + assert.strictEqual(str, 'a'.repeat(iter - 1)); + server.close(); + })); + })); + + server.listen(0, common.mustCall(() => { + const { port } = server.address(); + createDuplex(port).then((socket) => { + const client = tls.connect({ + socket, + rejectUnauthorized: false, + }, common.mustCall(() => { + assert.strictEqual(client.bufferSize, 0); + + for (let i = 1; i < iter; i++) { + client.write('a'); + assert.strictEqual(client.bufferSize, i + 1); + } + + // It seems that tlsSockets created from sockets of `Duplex` emit no + // "finish" events. We use "end" event instead. + client.on('end', common.mustCall(() => { + assert.strictEqual(client.bufferSize, undefined); + })); + + client.end(); + })); + }); + })); +} diff --git a/test/parallel/test-trace-events-metadata.js b/test/parallel/test-trace-events-metadata.js index 951f398404ac66..0db8555838cd42 100644 --- a/test/parallel/test-trace-events-metadata.js +++ b/test/parallel/test-trace-events-metadata.js @@ -36,8 +36,9 @@ proc.once('exit', common.mustCall(() => { assert(traces.some((trace) => trace.name === 'node' && - trace.args.process.versions.http_parser === - process.versions.http_parser && + (trace.args.process.versions.http_parser === + process.versions.http_parser || + trace.args.process.versions.llhttp === process.versions.llhttp) && trace.args.process.versions.node === process.versions.node && trace.args.process.versions.v8 === diff --git a/test/parallel/test-tracing-no-crash.js b/test/parallel/test-tracing-no-crash.js index 5b11522911e75d..0ae402f5288cca 100644 --- a/test/parallel/test-tracing-no-crash.js +++ b/test/parallel/test-tracing-no-crash.js @@ -8,7 +8,15 @@ function CheckNoSignalAndErrorCodeOne(code, signal) { assert.strictEqual(code, 1); } -const child = spawn(process.execPath, - ['--trace-event-categories', 'madeup', '-e', - 'throw new Error()'], { stdio: 'inherit' }); +const child = spawn(process.execPath, [ + '--trace-event-categories', 'madeup', '-e', 'throw new Error()' +], { stdio: [ 'inherit', 'inherit', 'pipe' ] }); child.on('exit', common.mustCall(CheckNoSignalAndErrorCodeOne)); + +let stderr; +child.stderr.setEncoding('utf8'); +child.stderr.on('data', (chunk) => stderr += chunk); +child.stderr.on('end', common.mustCall(() => { + assert(stderr.includes('throw new Error()'), stderr); + assert(!stderr.includes('Could not open trace file'), stderr); +})); diff --git a/test/parallel/test-url-format.js b/test/parallel/test-url-format.js index 1f62792dfbcd78..571895832a3ffb 100644 --- a/test/parallel/test-url-format.js +++ b/test/parallel/test-url-format.js @@ -173,6 +173,16 @@ const formatTests = { hash: '#bar' }, + // `#` in path end + `#` in query + '/path/to/%%23?foo=the%231#bar': { + href: '/path/to/%%23?foo=the%231#bar', + pathname: '/path/to/%#', + query: { + foo: 'the#1' + }, + hash: '#bar' + }, + // `?` and `#` in path and search 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag': { href: 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag', diff --git a/test/parallel/test-util-isDeepStrictEqual.js b/test/parallel/test-util-isDeepStrictEqual.js index 938781a43084a5..fd585f7ccf0f1e 100644 --- a/test/parallel/test-util-isDeepStrictEqual.js +++ b/test/parallel/test-util-isDeepStrictEqual.js @@ -459,10 +459,13 @@ utilIsDeepStrict(-0, -0); const obj1 = { [symbol1]: 1 }; const obj2 = { [symbol1]: 1 }; const obj3 = { [Symbol()]: 1 }; + const obj4 = { }; // Add a non enumerable symbol as well. It is going to be ignored! Object.defineProperty(obj2, Symbol(), { value: 1 }); + Object.defineProperty(obj4, symbol1, { value: 1 }); notUtilIsDeepStrict(obj1, obj3); utilIsDeepStrict(obj1, obj2); + notUtilIsDeepStrict(obj1, obj4); // TypedArrays have a fast path. Test for this as well. const a = new Uint8Array(4); const b = new Uint8Array(4); diff --git a/test/parallel/test-v8-coverage.js b/test/parallel/test-v8-coverage.js index 16a55b0fc4b8e8..191835fe0f5af9 100644 --- a/test/parallel/test-v8-coverage.js +++ b/test/parallel/test-v8-coverage.js @@ -108,6 +108,20 @@ function nextdir() { assert.strictEqual(fixtureCoverage, undefined); } +// disables async hooks before writing coverage. +{ + const coverageDirectory = path.join(tmpdir.path, nextdir()); + const output = spawnSync(process.execPath, [ + require.resolve('../fixtures/v8-coverage/async-hooks') + ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } }); + assert.strictEqual(output.status, 0); + const fixtureCoverage = getFixtureCoverage('async-hooks.js', + coverageDirectory); + assert.ok(fixtureCoverage); + // first branch executed. + assert.strictEqual(fixtureCoverage.functions[1].ranges[0].count, 1); +} + // extracts the coverage object for a given fixture name. function getFixtureCoverage(fixtureFile, coverageDirectory) { const coverageFiles = fs.readdirSync(coverageDirectory); diff --git a/test/parallel/test-v8-serdes.js b/test/parallel/test-v8-serdes.js index 94f10dbfe9fb09..c019674f4592e4 100644 --- a/test/parallel/test-v8-serdes.js +++ b/test/parallel/test-v8-serdes.js @@ -98,6 +98,47 @@ const deserializerTypeError = assert.strictEqual(des.readValue().val, hostObject); } +// This test ensures that `v8.Serializer.writeRawBytes()` support +// `TypedArray` and `DataView`. +{ + const text = 'hostObjectTag'; + const data = Buffer.from(text); + const arrayBufferViews = common.getArrayBufferViews(data); + + // `buf` is one of `TypedArray` or `DataView`. + function testWriteRawBytes(buf) { + let writeHostObjectCalled = false; + const ser = new v8.DefaultSerializer(); + + ser._writeHostObject = common.mustCall((object) => { + writeHostObjectCalled = true; + ser.writeUint32(buf.byteLength); + ser.writeRawBytes(buf); + }); + + ser.writeHeader(); + ser.writeValue({ val: hostObject }); + + const des = new v8.DefaultDeserializer(ser.releaseBuffer()); + des._readHostObject = common.mustCall(() => { + assert.strictEqual(writeHostObjectCalled, true); + const length = des.readUint32(); + const buf = des.readRawBytes(length); + assert.strictEqual(buf.toString(), text); + + return hostObject; + }); + + des.readHeader(); + + assert.strictEqual(des.readValue().val, hostObject); + } + + arrayBufferViews.forEach((buf) => { + testWriteRawBytes(buf); + }); +} + { const ser = new v8.DefaultSerializer(); ser._writeHostObject = common.mustCall((object) => { @@ -146,3 +187,46 @@ const deserializerTypeError = assert.throws(v8.Serializer, serializerTypeError); assert.throws(v8.Deserializer, deserializerTypeError); } + + +// `v8.deserialize()` and `new v8.Deserializer()` should support both +// `TypedArray` and `DataView`. +{ + for (const obj of objects) { + const buf = v8.serialize(obj); + + for (const arrayBufferView of common.getArrayBufferViews(buf)) { + assert.deepStrictEqual(v8.deserialize(arrayBufferView), obj); + } + + for (const arrayBufferView of common.getArrayBufferViews(buf)) { + const deserializer = new v8.DefaultDeserializer(arrayBufferView); + deserializer.readHeader(); + const value = deserializer.readValue(); + assert.deepStrictEqual(value, obj); + + const serializer = new v8.DefaultSerializer(); + serializer.writeHeader(); + serializer.writeValue(value); + assert.deepStrictEqual(buf, serializer.releaseBuffer()); + } + } +} + +{ + const INVALID_SOURCE = 'INVALID_SOURCE_TYPE'; + const serializer = new v8.Serializer(); + serializer.writeHeader(); + assert.throws( + () => serializer.writeRawBytes(INVALID_SOURCE), + /^TypeError: source must be a TypedArray or a DataView$/, + ); + assert.throws( + () => v8.deserialize(INVALID_SOURCE), + /^TypeError: buffer must be a TypedArray or a DataView$/, + ); + assert.throws( + () => new v8.Deserializer(INVALID_SOURCE), + /^TypeError: buffer must be a TypedArray or a DataView$/, + ); +} diff --git a/test/parallel/test-vm-basic.js b/test/parallel/test-vm-basic.js index 54b7c45ff8043a..29e2a8b5251934 100644 --- a/test/parallel/test-vm-basic.js +++ b/test/parallel/test-vm-basic.js @@ -178,18 +178,20 @@ const vm = require('vm'); 'filename': 'string', 'columnOffset': 'number', 'lineOffset': 'number', - 'cachedData': 'Uint8Array', + 'cachedData': 'Buffer, TypedArray, or DataView', 'produceCachedData': 'boolean', }; for (const option in optionTypes) { + const typeErrorMessage = `The "options.${option}" property must be ` + + `${option === 'cachedData' ? 'one of' : 'of'} type`; common.expectsError(() => { vm.compileFunction('', undefined, { [option]: null }); }, { type: TypeError, code: 'ERR_INVALID_ARG_TYPE', - message: `The "options.${option}" property must be of type ` + - `${optionTypes[option]}. Received type object` + message: typeErrorMessage + + ` ${optionTypes[option]}. Received type object` }); } @@ -207,6 +209,20 @@ const vm = require('vm'); } ); + // Testing for non Array type-based failures + [Boolean(), Number(), null, Object(), Symbol(), {}].forEach( + (value) => { + common.expectsError(() => { + vm.compileFunction('', value); + }, { + type: TypeError, + code: 'ERR_INVALID_ARG_TYPE', + message: 'The "params" argument must be of type Array. ' + + `Received type ${typeof value}` + }); + } + ); + assert.strictEqual( vm.compileFunction( 'return a;', diff --git a/test/parallel/test-vm-cached-data.js b/test/parallel/test-vm-cached-data.js index e3947d1ae6c166..1b14999cdbc2f7 100644 --- a/test/parallel/test-vm-cached-data.js +++ b/test/parallel/test-vm-cached-data.js @@ -41,12 +41,14 @@ function testProduceConsume() { const data = produce(source); - // It should consume code cache - const script = new vm.Script(source, { - cachedData: data - }); - assert(!script.cachedDataRejected); - assert.strictEqual(script.runInThisContext()(), 'original'); + for (const cachedData of common.getArrayBufferViews(data)) { + // It should consume code cache + const script = new vm.Script(source, { + cachedData + }); + assert(!script.cachedDataRejected); + assert.strictEqual(script.runInThisContext()(), 'original'); + } } testProduceConsume(); @@ -91,5 +93,5 @@ common.expectsError(() => { }, { code: 'ERR_INVALID_ARG_TYPE', type: TypeError, - message: /must be one of type Buffer or Uint8Array/ + message: /must be one of type Buffer, TypedArray, or DataView/ }); diff --git a/test/parallel/test-vm-create-and-run-in-context.js b/test/parallel/test-vm-create-and-run-in-context.js index 8f4ce72c50f246..bd746cf2df7080 100644 --- a/test/parallel/test-vm-create-and-run-in-context.js +++ b/test/parallel/test-vm-create-and-run-in-context.js @@ -29,7 +29,7 @@ const vm = require('vm'); // Run in a new empty context let context = vm.createContext(); let result = vm.runInContext('"passed";', context); -assert.strictEqual('passed', result); +assert.strictEqual(result, 'passed'); // Create a new pre-populated context context = vm.createContext({ 'foo': 'bar', 'thing': 'lala' }); diff --git a/test/parallel/test-vm-low-stack-space.js b/test/parallel/test-vm-low-stack-space.js index 7c1313d47c1ad9..6a49a983d54f5e 100644 --- a/test/parallel/test-vm-low-stack-space.js +++ b/test/parallel/test-vm-low-stack-space.js @@ -6,7 +6,7 @@ const vm = require('vm'); function a() { try { return a(); - } catch (e) { + } catch { // Throw an exception as near to the recursion-based RangeError as possible. return vm.runInThisContext('() => 42')(); } @@ -17,7 +17,7 @@ assert.strictEqual(a(), 42); function b() { try { return b(); - } catch (e) { + } catch { // This writes a lot of noise to stderr, but it still works. return vm.runInNewContext('() => 42')(); } diff --git a/test/parallel/test-vm-module-dynamic-import.js b/test/parallel/test-vm-module-dynamic-import.js index 5c0f6f81fa842b..600f455e93306e 100644 --- a/test/parallel/test-vm-module-dynamic-import.js +++ b/test/parallel/test-vm-module-dynamic-import.js @@ -68,16 +68,34 @@ async function testInvalid() { await result.catch(common.mustCall((e) => { assert.strictEqual(e.code, 'ERR_VM_MODULE_NOT_MODULE'); })); + + const s = new Script('import("foo")', { + importModuleDynamically: common.mustCall((specifier, wrap) => { + return undefined; + }), + }); + let threw = false; + try { + await s.runInThisContext(); + } catch (e) { + threw = true; + assert.strictEqual(e.code, 'ERR_VM_MODULE_NOT_MODULE'); + } + assert(threw); +} + +async function testInvalidimportModuleDynamically() { + assert.throws( + () => new Script( + 'import("foo")', + { importModuleDynamically: false }), + { code: 'ERR_INVALID_ARG_TYPE' } + ); } -const done = common.mustCallAtLeast(3); (async function() { await testNoCallback(); - done(); - await test(); - done(); - await testInvalid(); - done(); + await testInvalidimportModuleDynamically(); }()).then(common.mustCall()); diff --git a/test/parallel/test-vm-module-errors.js b/test/parallel/test-vm-module-errors.js index 05022160832a53..a343a542a10abd 100644 --- a/test/parallel/test-vm-module-errors.js +++ b/test/parallel/test-vm-module-errors.js @@ -98,7 +98,7 @@ async function checkModuleState() { const m = new SourceTextModule('import "foo";'); try { await m.link(common.mustCall(() => ({}))); - } catch (err) { + } catch { assert.strictEqual(m.linkingStatus, 'errored'); m.instantiate(); } @@ -219,7 +219,7 @@ async function checkLinking() { const erroredModule = new SourceTextModule('import "foo";'); try { await erroredModule.link(common.mustCall(() => ({}))); - } catch (err) { + } catch { // ignored } finally { assert.strictEqual(erroredModule.linkingStatus, 'errored'); diff --git a/test/parallel/test-vm-parse-abort-on-uncaught-exception.js b/test/parallel/test-vm-parse-abort-on-uncaught-exception.js index 36f73ea676e5a5..4fcff30321f671 100644 --- a/test/parallel/test-vm-parse-abort-on-uncaught-exception.js +++ b/test/parallel/test-vm-parse-abort-on-uncaught-exception.js @@ -7,8 +7,8 @@ const vm = require('vm'); try { new vm.Script({ toString() { throw new Error('foo'); } }, {}); -} catch (err) {} +} catch {} try { new vm.Script('[', {}); -} catch (err) {} +} catch {} diff --git a/test/parallel/test-whatwg-encoding-textdecoder-fatal.js b/test/parallel/test-whatwg-encoding-textdecoder-fatal.js index be37f5097c504e..aa945b61b10e72 100644 --- a/test/parallel/test-whatwg-encoding-textdecoder-fatal.js +++ b/test/parallel/test-whatwg-encoding-textdecoder-fatal.js @@ -88,3 +88,15 @@ bad.forEach((t) => { assert(!new TextDecoder().fatal); assert(new TextDecoder('utf-8', { fatal: true }).fatal); } + +{ + const notArrayBufferViewExamples = [false, {}, 1, '', new Error()]; + notArrayBufferViewExamples.forEach((invalidInputType) => { + common.expectsError(() => { + new TextDecoder(undefined, null).decode(invalidInputType); + }, { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError + }); + }); +} diff --git a/test/parallel/test-whatwg-encoding-textdecoder.js b/test/parallel/test-whatwg-encoding-textdecoder.js index 37fbe12757134e..6d1db2ec33faad 100644 --- a/test/parallel/test-whatwg-encoding-textdecoder.js +++ b/test/parallel/test-whatwg-encoding-textdecoder.js @@ -75,6 +75,14 @@ if (common.hasIntl) { }); } +// Test TextDecoder, label undefined, options null +{ + const dec = new TextDecoder(undefined, null); + assert.strictEqual(dec.encoding, 'utf-8'); + assert.strictEqual(dec.fatal, false); + assert.strictEqual(dec.ignoreBOM, false); +} + // Test TextDecoder, UTF-16le { const dec = new TextDecoder('utf-16le'); diff --git a/test/parallel/test-whatwg-url-constructor.js b/test/parallel/test-whatwg-url-constructor.js index 16bcac74cc6bcd..282679d7797f2a 100644 --- a/test/parallel/test-whatwg-url-constructor.js +++ b/test/parallel/test-whatwg-url-constructor.js @@ -8,10 +8,12 @@ if (!common.hasIntl) { const fixtures = require('../common/fixtures'); const { URL, URLSearchParams } = require('url'); const { test, assert_equals, assert_true, assert_throws } = - require('../common/wpt'); + require('../common/wpt').harness; const request = { - response: require(fixtures.path('url-tests')) + response: require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') + ) }; /* The following tests are copied from WPT. Modifications to them should be diff --git a/test/parallel/test-whatwg-url-custom-domainto.js b/test/parallel/test-whatwg-url-custom-domainto.js index 556a3ff8410b73..9677d84286ebe4 100644 --- a/test/parallel/test-whatwg-url-custom-domainto.js +++ b/test/parallel/test-whatwg-url-custom-domainto.js @@ -11,7 +11,10 @@ const assert = require('assert'); const { domainToASCII, domainToUnicode } = require('url'); const tests = require('../fixtures/url-idna'); -const wptToASCIITests = require('../fixtures/url-toascii'); +const fixtures = require('../common/fixtures'); +const wptToASCIITests = require( + fixtures.path('wpt', 'url', 'resources', 'toascii.json') +); { const expectedError = common.expectsError( diff --git a/test/parallel/test-whatwg-url-custom-no-enumerable-context.js b/test/parallel/test-whatwg-url-custom-no-enumerable-context.js new file mode 100644 index 00000000000000..f24a47b6d5c8f0 --- /dev/null +++ b/test/parallel/test-whatwg-url-custom-no-enumerable-context.js @@ -0,0 +1,14 @@ +'use strict'; +// This tests that the context of URL objects are not +// enumerable and thus considered by assert libraries. +// See https://github.com/nodejs/node/issues/24211 + +// Tests below are not from WPT. + +require('../common'); +const assert = require('assert'); + +assert.deepStrictEqual( + new URL('./foo', 'https://example.com/'), + new URL('https://example.com/foo') +); diff --git a/test/parallel/test-whatwg-url-custom-parsing.js b/test/parallel/test-whatwg-url-custom-parsing.js index 252e35c8d3552c..34d9062087eb10 100644 --- a/test/parallel/test-whatwg-url-custom-parsing.js +++ b/test/parallel/test-whatwg-url-custom-parsing.js @@ -12,7 +12,9 @@ const URL = require('url').URL; const assert = require('assert'); const fixtures = require('../common/fixtures'); -const tests = require(fixtures.path('url-tests')); +const tests = require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') +); const originalFailures = tests.filter((test) => test.failure); diff --git a/test/parallel/test-whatwg-url-custom-searchparams-sort.js b/test/parallel/test-whatwg-url-custom-searchparams-sort.js index f8884a7e7092a3..49c3b065f957c6 100644 --- a/test/parallel/test-whatwg-url-custom-searchparams-sort.js +++ b/test/parallel/test-whatwg-url-custom-searchparams-sort.js @@ -4,9 +4,14 @@ require('../common'); const { URL, URLSearchParams } = require('url'); -const { test, assert_array_equals } = require('../common/wpt'); +const { test, assert_array_equals } = require('../common/wpt').harness; -// Test bottom-up iterative stable merge sort +// TODO(joyeecheung): upstream this to WPT, if possible - even +// just as a test for large inputs. Other implementations may +// have a similar cutoff anyway. + +// Test bottom-up iterative stable merge sort because we only use that +// algorithm to sort > 100 search params. const tests = [{ input: '', output: [] }]; const pairs = []; for (let i = 10; i < 100; i++) { diff --git a/test/parallel/test-whatwg-url-custom-setters.js b/test/parallel/test-whatwg-url-custom-setters.js index 99b4361831fd3b..e10ebb9fe66968 100644 --- a/test/parallel/test-whatwg-url-custom-setters.js +++ b/test/parallel/test-whatwg-url-custom-setters.js @@ -10,9 +10,10 @@ if (!common.hasIntl) { const assert = require('assert'); const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); +const { test, assert_equals } = require('../common/wpt').harness; const fixtures = require('../common/fixtures'); +// TODO(joyeecheung): we should submit these to the upstream const additionalTestCases = require(fixtures.path('url-setter-tests-additional.js')); diff --git a/test/parallel/test-whatwg-url-historical.js b/test/parallel/test-whatwg-url-historical.js deleted file mode 100644 index 466949cd322d37..00000000000000 --- a/test/parallel/test-whatwg-url-historical.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; -const common = require('../common'); -if (!common.hasIntl) { - // A handful of the tests fail when ICU is not included. - common.skip('missing Intl'); -} - -const URL = require('url').URL; -const { test, assert_equals, assert_throws } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/historical.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -// var objects = [ -// [function() { return window.location }, "location object"], -// [function() { return document.createElement("a") }, "a element"], -// [function() { return document.createElement("area") }, "area element"], -// ]; - -// objects.forEach(function(o) { -// test(function() { -// var object = o[0](); -// assert_false("searchParams" in object, -// o[1] + " should not have a searchParams attribute"); -// }, "searchParams on " + o[1]); -// }); - -test(function() { - var url = new URL("./foo", "http://www.example.org"); - assert_equals(url.href, "http://www.example.org/foo"); - assert_throws(new TypeError(), function() { - url.href = "./bar"; - }); -}, "Setting URL's href attribute and base URLs"); - -test(function() { - assert_equals(URL.domainToASCII, undefined); -}, "URL.domainToASCII should be undefined"); - -test(function() { - assert_equals(URL.domainToUnicode, undefined); -}, "URL.domainToUnicode should be undefined"); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-origin.js b/test/parallel/test-whatwg-url-origin.js index 8a5ad6d3154f8f..5b1aa14cd07642 100644 --- a/test/parallel/test-whatwg-url-origin.js +++ b/test/parallel/test-whatwg-url-origin.js @@ -7,10 +7,12 @@ if (!common.hasIntl) { const fixtures = require('../common/fixtures'); const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); +const { test, assert_equals } = require('../common/wpt').harness; const request = { - response: require(fixtures.path('url-tests')) + response: require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') + ) }; /* The following tests are copied from WPT. Modifications to them should be diff --git a/test/parallel/test-whatwg-url-searchparams-foreach.js b/test/parallel/test-whatwg-url-searchparams-foreach.js deleted file mode 100644 index 833858618f8e5b..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-foreach.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -require('../common'); -const { URL, URLSearchParams } = require('url'); -const { test, assert_array_equals, assert_unreached } = - require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/a8b2b1e/url/urlsearchparams-foreach.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -var i; // Strict mode fix for WPT. -test(function() { - var params = new URLSearchParams('a=1&b=2&c=3'); - var keys = []; - var values = []; - params.forEach(function(value, key) { - keys.push(key); - values.push(value); - }); - assert_array_equals(keys, ['a', 'b', 'c']); - assert_array_equals(values, ['1', '2', '3']); -}, "ForEach Check"); - -test(function() { - let a = new URL("http://a.b/c?a=1&b=2&c=3&d=4"); - let b = a.searchParams; - var c = []; - for (i of b) { - a.search = "x=1&y=2&z=3"; - c.push(i); - } - assert_array_equals(c[0], ["a","1"]); - assert_array_equals(c[1], ["y","2"]); - assert_array_equals(c[2], ["z","3"]); -}, "For-of Check"); - -test(function() { - let a = new URL("http://a.b/c"); - let b = a.searchParams; - for (i of b) { - assert_unreached(i); - } -}, "empty"); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-setters.js b/test/parallel/test-whatwg-url-setters.js index a04b6c93eccf3d..13422bd77690ed 100644 --- a/test/parallel/test-whatwg-url-setters.js +++ b/test/parallel/test-whatwg-url-setters.js @@ -7,11 +7,13 @@ if (!common.hasIntl) { } const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); +const { test, assert_equals } = require('../common/wpt').harness; const fixtures = require('../common/fixtures'); const request = { - response: require(fixtures.path('url-setter-tests')) + response: require(fixtures.path( + 'wpt', 'url', 'resources', 'setters_tests.json' + )) }; /* The following tests are copied from WPT. Modifications to them should be diff --git a/test/parallel/test-whatwg-url-toascii.js b/test/parallel/test-whatwg-url-toascii.js index c85b092c1d250c..4869ab3f1d3bd1 100644 --- a/test/parallel/test-whatwg-url-toascii.js +++ b/test/parallel/test-whatwg-url-toascii.js @@ -7,10 +7,12 @@ if (!common.hasIntl) { const fixtures = require('../common/fixtures'); const { URL } = require('url'); -const { test, assert_equals, assert_throws } = require('../common/wpt'); +const { test, assert_equals, assert_throws } = require('../common/wpt').harness; const request = { - response: require(fixtures.path('url-toascii')) + response: require( + fixtures.path('wpt', 'url', 'resources', 'toascii.json') + ) }; /* The following tests are copied from WPT. Modifications to them should be diff --git a/test/parallel/test-whatwg-url-tojson.js b/test/parallel/test-whatwg-url-tojson.js deleted file mode 100644 index 8e9a30c7e017e4..00000000000000 --- a/test/parallel/test-whatwg-url-tojson.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -require('../common'); -const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/02585db/url/url-tojson.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(() => { - const a = new URL("https://example.com/") - assert_equals(JSON.stringify(a), "\"https://example.com/\"") -}) -/* eslint-enable */ diff --git a/test/pseudo-tty/test-assert-no-color.js b/test/pseudo-tty/test-assert-no-color.js new file mode 100644 index 00000000000000..9412cdcc953ad7 --- /dev/null +++ b/test/pseudo-tty/test-assert-no-color.js @@ -0,0 +1,19 @@ +'use strict'; +require('../common'); +const assert = require('assert').strict; + +process.env.NODE_DISABLE_COLORS = true; + +try { + assert.deepStrictEqual({}, { foo: 'bar' }); +} catch (error) { + const expected = + 'Expected values to be strictly deep-equal:\n' + + '+ actual - expected\n' + + '\n' + + '+ {}\n' + + '- {\n' + + '- foo: \'bar\'\n' + + '- }'; + assert.strictEqual(error.message, expected); +} diff --git a/test/pseudo-tty/test-assert-no-color.out b/test/pseudo-tty/test-assert-no-color.out new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/test/pseudo-tty/test-tty-get-color-depth.js b/test/pseudo-tty/test-tty-get-color-depth.js index d802add1189db2..d4062f5fdb6d39 100644 --- a/test/pseudo-tty/test-tty-get-color-depth.js +++ b/test/pseudo-tty/test-tty-get-color-depth.js @@ -2,7 +2,6 @@ const common = require('../common'); const assert = require('assert').strict; -/* eslint-disable no-restricted-properties */ const { WriteStream } = require('tty'); const fd = common.getTTYfd(); @@ -10,7 +9,7 @@ const writeStream = new WriteStream(fd); { const depth = writeStream.getColorDepth(); - assert.equal(typeof depth, 'number'); + assert.strictEqual(typeof depth, 'number'); assert(depth >= 1 && depth <= 24); } @@ -44,7 +43,7 @@ const writeStream = new WriteStream(fd); [{ TERM: 'dumb', COLORTERM: '1' }, 4], ].forEach(([env, depth], i) => { const actual = writeStream.getColorDepth(env); - assert.equal( + assert.strictEqual( actual, depth, `i: ${i}, expected: ${depth}, actual: ${actual}, env: ${env}` @@ -57,8 +56,8 @@ const writeStream = new WriteStream(fd); const [ value, depth1, depth2 ] = process.platform !== 'win32' ? ['win32', 1, 4] : ['linux', 4, 1]; - assert.equal(writeStream.getColorDepth({}), depth1); + assert.strictEqual(writeStream.getColorDepth({}), depth1); Object.defineProperty(process, 'platform', { value }); - assert.equal(writeStream.getColorDepth({}), depth2); + assert.strictEqual(writeStream.getColorDepth({}), depth2); Object.defineProperty(process, 'platform', platform); } diff --git a/test/pummel/test-fs-watch-non-recursive.js b/test/pummel/test-fs-watch-non-recursive.js index 2b10f9b24da746..da11b423a686e0 100644 --- a/test/pummel/test-fs-watch-non-recursive.js +++ b/test/pummel/test-fs-watch-non-recursive.js @@ -31,13 +31,13 @@ const testsubdir = path.join(testDir, 'testsubdir'); const filepath = path.join(testsubdir, 'watch.txt'); function cleanup() { - try { fs.unlinkSync(filepath); } catch (e) { } - try { fs.rmdirSync(testsubdir); } catch (e) { } + try { fs.unlinkSync(filepath); } catch { } + try { fs.rmdirSync(testsubdir); } catch { } } process.on('exit', cleanup); cleanup(); -try { fs.mkdirSync(testsubdir, 0o700); } catch (e) {} +try { fs.mkdirSync(testsubdir, 0o700); } catch {} // Need a grace period, else the mkdirSync() above fires off an event. setTimeout(function() { diff --git a/test/sequential/test-fs-watch-system-limit.js b/test/pummel/test-fs-watch-system-limit.js similarity index 76% rename from test/sequential/test-fs-watch-system-limit.js rename to test/pummel/test-fs-watch-system-limit.js index e896cbf83b965a..8b9cb62ad0a007 100644 --- a/test/sequential/test-fs-watch-system-limit.js +++ b/test/pummel/test-fs-watch-system-limit.js @@ -2,6 +2,7 @@ const common = require('../common'); const assert = require('assert'); const child_process = require('child_process'); +const fs = require('fs'); const stream = require('stream'); if (!common.isLinux) @@ -9,6 +10,20 @@ if (!common.isLinux) if (!common.enoughTestCpu) common.skip('This test is resource-intensive'); +try { + // Ensure inotify limit is low enough for the test to actually exercise the + // limit with small enough resources. + const limit = Number( + fs.readFileSync('/proc/sys/fs/inotify/max_user_watches', 'utf8')); + if (limit > 16384) + common.skip('inotify limit is quite large'); +} catch (e) { + if (e.code === 'ENOENT') + common.skip('the inotify /proc subsystem does not exist'); + // Fail on other errors. + throw e; +} + const processes = []; const gatherStderr = new stream.PassThrough(); gatherStderr.setEncoding('utf8'); diff --git a/test/pummel/test-vm-memleak.js b/test/pummel/test-vm-memleak.js index cb96512d384556..94e4055a767096 100644 --- a/test/pummel/test-vm-memleak.js +++ b/test/pummel/test-vm-memleak.js @@ -37,7 +37,7 @@ assert(ok, 'Run this test with --max_old_space_size=32.'); const interval = setInterval(function() { try { vm.runInNewContext('throw 1;'); - } catch (e) { + } catch { } const rss = process.memoryUsage().rss; diff --git a/test/pummel/test-vm-race.js b/test/pummel/test-vm-race.js index 7f9514b04e9e73..55f63d31689fb5 100644 --- a/test/pummel/test-vm-race.js +++ b/test/pummel/test-vm-race.js @@ -25,7 +25,7 @@ do { try { script.runInContext(context, { timeout: 5 }); ++sandbox.timeout; - } catch (err) { + } catch { --sandbox.timeout; } } while (Date.now() < giveUp); diff --git a/test/root.status b/test/root.status index 9ed9004c2169d0..9c40512cb68051 100644 --- a/test/root.status +++ b/test/root.status @@ -9,27 +9,6 @@ async-hooks/test-tlswrap: SLOW async-hooks/test-tlswrap: SLOW message/eval_messages: SLOW message/stdin_messages: SLOW -parallel/test-benchmark-assert: SLOW -parallel/test-benchmark-cluster: SLOW -parallel/test-benchmark-crypto: SLOW -parallel/test-benchmark-dns: SLOW -parallel/test-benchmark-domain: SLOW -parallel/test-benchmark-es: SLOW -parallel/test-benchmark-events: SLOW -parallel/test-benchmark-fs: SLOW -parallel/test-benchmark-misc: SLOW -parallel/test-benchmark-module: SLOW -parallel/test-benchmark-os: SLOW -parallel/test-benchmark-process: SLOW -parallel/test-benchmark-querystring: SLOW -parallel/test-benchmark-streams: SLOW -parallel/test-benchmark-string_decoder: SLOW -parallel/test-benchmark-timers: SLOW -parallel/test-benchmark-url: SLOW -parallel/test-benchmark-util: SLOW -parallel/test-benchmark-v8: SLOW -parallel/test-benchmark-vm: SLOW -parallel/test-benchmark-zlib: SLOW parallel/test-buffer-constructor-node-modules-paths: SLOW parallel/test-buffer-indexof: SLOW parallel/test-child-process-spawnsync-input: SLOW @@ -165,13 +144,6 @@ parallel/test-worker-unsupported-things: SLOW parallel/test-worker-workerdata-sharedarraybuffer: SLOW parallel/test-zlib-bytes-read: SLOW parallel/test-zlib-convenience-methods: SLOW -sequential/test-benchmark-buffer: SLOW -sequential/test-benchmark-child-process: SLOW -sequential/test-benchmark-dgram: SLOW -sequential/test-benchmark-http: SLOW -sequential/test-benchmark-net: SLOW -sequential/test-benchmark-path: SLOW -sequential/test-benchmark-tls: SLOW sequential/test-child-process-execsync: SLOW sequential/test-child-process-exit: SLOW sequential/test-child-process-pass-fd: SLOW diff --git a/test/sequential/test-async-wrap-getasyncid.js b/test/sequential/test-async-wrap-getasyncid.js index 851a0b3fbc2118..4ebe3e0472f4ee 100644 --- a/test/sequential/test-async-wrap-getasyncid.js +++ b/test/sequential/test-async-wrap-getasyncid.js @@ -149,7 +149,7 @@ if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check { const { HTTPParser } = internalBinding('http_parser'); - testInitialized(new HTTPParser(0), 'HTTPParser'); + testInitialized(new HTTPParser(HTTPParser.REQUEST), 'HTTPParser'); } diff --git a/test/sequential/test-fs-readfile-tostring-fail.js b/test/sequential/test-fs-readfile-tostring-fail.js index 8dcab75e0fb119..da8f3930f618f9 100644 --- a/test/sequential/test-fs-readfile-tostring-fail.js +++ b/test/sequential/test-fs-readfile-tostring-fail.js @@ -50,7 +50,7 @@ stream.on('finish', common.mustCall(function() { function destroy() { try { fs.unlinkSync(file); - } catch (err) { + } catch { // it may not exist } } diff --git a/test/sequential/test-inspector-enabled.js b/test/sequential/test-inspector-enabled.js index a7a0832793283c..f14e7c17d817c5 100644 --- a/test/sequential/test-inspector-enabled.js +++ b/test/sequential/test-inspector-enabled.js @@ -20,7 +20,10 @@ assert( `; const args = ['--inspect', '-e', script]; -const child = spawn(process.execPath, args, { stdio: 'inherit' }); +const child = spawn(process.execPath, args, { + stdio: 'inherit', + env: { ...process.env, NODE_V8_COVERAGE: '' } +}); child.on('exit', (code, signal) => { process.exit(code || signal); }); diff --git a/test/sequential/test-inspector-module.js b/test/sequential/test-inspector-module.js index eaecd49c982311..26bb7fe9262889 100644 --- a/test/sequential/test-inspector-module.js +++ b/test/sequential/test-inspector-module.js @@ -46,6 +46,17 @@ session.post('Runtime.evaluate', { expression: '2 + 2' }); ); }); +[1, 'a', {}, [], true, Infinity].forEach((i) => { + common.expectsError( + () => session.post('test', {}, i), + { + code: 'ERR_INVALID_CALLBACK', + type: TypeError, + message: 'Callback must be a function' + } + ); +}); + common.expectsError( () => session.connect(), { diff --git a/test/wpt/README.md b/test/wpt/README.md new file mode 100644 index 00000000000000..1810a98c8dc982 --- /dev/null +++ b/test/wpt/README.md @@ -0,0 +1,171 @@ +# Web Platform Tests + +The tests here are drivers for running the [Web Platform Tests][]. + +See [`test/fixtures/wpt/README.md`][] for a hash of the last +updated WPT commit for each module being covered here. + +See the json files in [the `status` folder](./status) for prerequisites, +expected failures, and support status for specific tests in each module. + +Currently there are still some Web Platform Tests titled `test-whatwg-*` +under `test/parallel` that have not been migrated to be run with the +WPT harness and have automatic updates. There are also a few +`test-whatwg-*-custom-*` tests that may need to be upstreamed. +This folder covers the tests that have been migrated. + +
+## How to add tests for a new module + +### 1. Create a status file + +For example, to add the URL tests, add a `test/wpt/status/url.json` file. + +In the beginning, it's fine to leave an empty object `{}` in the file if +it's not yet clear how compliant the implementation is, +the requirements and expected failures can be figured out in a later step +when the tests are run for the first time. + +See [Format of a status JSON file](#status-format) for details. + +### 2. Pull the WPT files + +Use the [git node wpt][] command to download the WPT files into +`test/fixtures/wpt`. For example, to add URL tests: + +```text +$ cd /path/to/node/project +$ git node wpt url +``` + +### 3. Create the test driver + +For example, for the URL tests, add a file `test/wpt/test-whatwg-url.js`: + +```js +'use strict'; + +// This flag is required by the WPT Runner to patch the internals +// for the tests to run in a vm. +// Flags: --expose-internals + +require('../common'); +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('url'); + +// Copy global descriptors from the global object +runner.copyGlobalsFromObject(global, ['URL', 'URLSearchParams']); +// Define any additional globals with descriptors +runner.defineGlobal('DOMException', { + get() { + return require('internal/domexception'); + } +}); + +runner.runJsTests(); +``` + +This driver is capable of running the tests located in `test/fixtures/wpt/url` +with the WPT harness while taking the status file into account. + +### 4. Run the tests + +Run the test using `tools/test.py` and see if there are any failures. +For example, to run all the URL tests under `test/fixtures/wpt/url`: + +```text +$ tools/test.py wpt/test-whatwg-url +``` + +To run a specific test in WPT, for example, `url/url-searchparams.any.js`, +pass the file name as argument to the corresponding test driver: + +```text +node --expose-internals test/wpt/test-whatwg-url.js url-searchparams.any.js +``` + +If there are any failures, update the corresponding status file +(in this case, `test/wpt/status/url.json`) to make the test pass. + +For example, to mark `url/url-searchparams.any.js` as expected to fail, +add this to `test/wpt/status/url.json`: + +```json + "url-searchparams.any.js": { + "fail": "explain why the test fails, ideally with links" + } +``` + +See [Format of a status JSON file](#status-format) for details. + +### 5. Commit the changes and submit a Pull Request + +See [the contributing guide](../../CONTRIBUTING.md). + +## How to update tests for a module + +The tests can be updated in a way similar to how they are added. +Run Step 2 and Step 4 of [adding tests for a new module](#add-tests). + +The [git node wpt][] command maintains the status of the local +WPT subset, if no files are updated after running it for a module, +the local subset is up to date and there is no need to update them +until they are changed in the upstream. + +## How it works + +Note: currently this test suite only supports `.js` tests. There is +ongoing work in the upstream to properly split out the tests into files +that can be run in a shell environment like Node.js. + +### Getting the original test files and harness from WPT + +The original files and harness from WPT are downloaded and stored in +`test/fixtures/wpt`. + +The [git node wpt][] command automate this process while maintaining a map +containing the hash of the last updated commit for each module in +`test/fixtures/wpt/versions.json` and [`test/fixtures/wpt/README.md`][]. +It also maintains the LICENSE file in `test/fixtures/wpt`. + +### Loading and running the tests + +Given a module, the `WPTRunner` class in [`test/common/wpt`](../common/wpt.js) +loads: + +- `.js` test files (for example, `test/common/wpt/url/*.js` for `url`) +- Status file (for example, `test/wpt/status/url.json` for `url`) +- The WPT harness + +Then, for each test, it creates a vm with the globals and mocks, +sets up the harness result hooks, loads the metadata in the test (including +loading extra resources), and runs all the tests in that vm, +skipping tests that cannot be run because of lack of dependency or +expected failures. + + +## Format of a status JSON file + +```text +{ + "something.scope.js": { // the file name + // Optional: If the requirement is not met, this test will be skipped + "requires": ["intl"], // currently only intl is supported + + // Optional: the test will be skipped with the reason printed + "skip": "explain why we cannot run a test that's supposed to pass", + + // Optional: the test will be skipped with the reason printed + "fail": "explain why we the test is expected to fail" + } +} +``` + +A test may have to be skipped because it depends on another irrelevant +Web API, or certain harness has not been ported in our test runner yet. +In that case it needs to be marked with `skip` instead of `fail`. + +[Web Platform Tests]: https://github.com/web-platform-tests/wpt +[git node wpt]: https://github.com/nodejs/node-core-utils/blob/master/docs/git-node.md#git-node-wpt +[`test/fixtures/wpt/README.md`]: ../fixtures/wpt/README.md diff --git a/test/wpt/status/console.json b/test/wpt/status/console.json new file mode 100644 index 00000000000000..3874ed148d8610 --- /dev/null +++ b/test/wpt/status/console.json @@ -0,0 +1,8 @@ +{ + "idlharness.any.js": { + "fail": ".table, .dir and .timeLog parameter lengths are wrong" + }, + "console-is-a-namespace.any.js": { + "fail": "The [[Prototype]]'s [[Prototype]] must be %ObjectPrototype%" + } +} diff --git a/test/wpt/status/url.json b/test/wpt/status/url.json new file mode 100644 index 00000000000000..42b5f6fb1a1146 --- /dev/null +++ b/test/wpt/status/url.json @@ -0,0 +1,15 @@ +{ + "toascii.window.js": { + "requires": ["intl"], + "skip": "TODO: port from .window.js" + }, + "historical.any.js": { + "requires": ["intl"] + }, + "urlencoded-parser.any.js": { + "fail": "missing Request and Response" + }, + "idlharness.any.js": { + "fail": "getter/setter names are wrong, etc." + } +} \ No newline at end of file diff --git a/test/wpt/test-whatwg-console.js b/test/wpt/test-whatwg-console.js new file mode 100644 index 00000000000000..7b23fe8d3e619d --- /dev/null +++ b/test/wpt/test-whatwg-console.js @@ -0,0 +1,13 @@ +'use strict'; + +// Flags: --expose-internals + +require('../common'); +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('console'); + +// Copy global descriptors from the global object +runner.copyGlobalsFromObject(global, ['console']); + +runner.runJsTests(); diff --git a/test/wpt/test-whatwg-url.js b/test/wpt/test-whatwg-url.js new file mode 100644 index 00000000000000..8734452940e84e --- /dev/null +++ b/test/wpt/test-whatwg-url.js @@ -0,0 +1,19 @@ +'use strict'; + +// Flags: --expose-internals + +require('../common'); +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('url'); + +// Copy global descriptors from the global object +runner.copyGlobalsFromObject(global, ['URL', 'URLSearchParams']); +// Needed by urlsearchparams-constructor.any.js +runner.defineGlobal('DOMException', { + get() { + return require('internal/domexception'); + } +}); + +runner.runJsTests(); diff --git a/test/wpt/testcfg.py b/test/wpt/testcfg.py new file mode 100644 index 00000000000000..db235699ddfe57 --- /dev/null +++ b/test/wpt/testcfg.py @@ -0,0 +1,6 @@ +import sys, os +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +import testpy + +def GetConfiguration(context, root): + return testpy.ParallelTestConfiguration(context, root, 'wpt') diff --git a/test/wpt/wpt.status b/test/wpt/wpt.status new file mode 100644 index 00000000000000..de3b3024627a1b --- /dev/null +++ b/test/wpt/wpt.status @@ -0,0 +1,21 @@ +prefix wpt + +# To mark a test as flaky, list the test name in the appropriate section +# below, without ".js", followed by ": PASS,FLAKY". Example: +# sample-test : PASS,FLAKY + +[true] # This section applies to all platforms + +[$system==win32] + +[$system==linux] + +[$system==macos] + +[$arch==arm || $arch==arm64] + +[$system==solaris] # Also applies to SmartOS + +[$system==freebsd] + +[$system==aix] diff --git a/tools/doc/html.js b/tools/doc/html.js index fd74563dd7fc97..9c9c355574d4e5 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -404,7 +404,8 @@ function altDocs(filename, docCreated) { const [, docCreatedMajor, docCreatedMinor] = docCreated.map(Number); const host = 'https://nodejs.org'; const versions = [ - { num: '10.x' }, + { num: '11.x' }, + { num: '10.x', lts: true }, { num: '9.x' }, { num: '8.x', lts: true }, { num: '7.x' }, diff --git a/tools/doc/type-parser.js b/tools/doc/type-parser.js index b57dc6957a9ae0..49d888e88b9900 100644 --- a/tools/doc/type-parser.js +++ b/tools/doc/type-parser.js @@ -36,6 +36,7 @@ const customTypesMap = { `${jsDocPrefix}Reference/Iteration_protocols#The_iterator_protocol`, 'AsyncHook': 'async_hooks.html#async_hooks_async_hooks_createhook_callbacks', + 'AsyncResource': 'async_hooks.html#async_hooks_class_asyncresource', 'Buffer': 'buffer.html#buffer_class_buffer', @@ -45,6 +46,8 @@ const customTypesMap = { 'Cipher': 'crypto.html#crypto_class_cipher', 'Decipher': 'crypto.html#crypto_class_decipher', + 'DiffieHellman': 'crypto.html#crypto_class_diffiehellman', + 'ECDH': 'crypto.html#crypto_class_ecdh', 'Hash': 'crypto.html#crypto_class_hash', 'Hmac': 'crypto.html#crypto_class_hmac', 'Sign': 'crypto.html#crypto_class_sign', @@ -83,6 +86,8 @@ const customTypesMap = { 'Http2Stream': 'http2.html#http2_class_http2stream', 'ServerHttp2Stream': 'http2.html#http2_class_serverhttp2stream', + 'https.Server': 'https.html#https_class_https_server', + 'module': 'modules.html#modules_the_module_object', 'Handle': 'net.html#net_server_listen_handle_backlog_callback', @@ -101,6 +106,8 @@ const customTypesMap = { 'readline.Interface': 'readline.html#readline_class_interface', + 'repl.REPLServer': 'repl.html#repl_class_replserver', + 'Stream': 'stream.html#stream_stream', 'stream.Duplex': 'stream.html#stream_class_stream_duplex', 'stream.Readable': 'stream.html#stream_class_stream_readable', diff --git a/tools/generate_code_cache.js b/tools/generate_code_cache.js index 35411bc5af182a..9609d77c2afca9 100644 --- a/tools/generate_code_cache.js +++ b/tools/generate_code_cache.js @@ -8,8 +8,8 @@ // of `configure`. const { - getCodeCache, getSource, + getCodeCache, cachableBuiltins } = require('internal/bootstrap/cache'); @@ -118,6 +118,8 @@ namespace node { ${cacheDefinitions.join('\n\n')} +const bool native_module_has_code_cache = true; + // The target here will be returned as \`internalBinding('code_cache')\` void DefineCodeCache(Environment* env, v8::Local target) { v8::Isolate* isolate = env->isolate(); diff --git a/tools/license-builder.sh b/tools/license-builder.sh index 82addcd0b40731..58a3b5a209b8c7 100755 --- a/tools/license-builder.sh +++ b/tools/license-builder.sh @@ -58,6 +58,7 @@ else fi addlicense "libuv" "deps/uv" "$(cat ${rootdir}/deps/uv/LICENSE)" +addlicense "llhttp" "deps/llhttp" "$(cat deps/llhttp/LICENSE-MIT)" addlicense "OpenSSL" "deps/openssl" \ "$(sed -e '/^ \*\/$/,$d' -e '/^ [^*].*$/d' -e '/\/\*.*$/d' -e '/^$/d' -e 's/^[/ ]\* *//' ${rootdir}/deps/openssl/openssl/LICENSE)" addlicense "Punycode.js" "lib/punycode.js" \ diff --git a/tools/lint-md.js b/tools/lint-md.js index 3c22cd8704ffc2..cbb658dd418932 100644 --- a/tools/lint-md.js +++ b/tools/lint-md.js @@ -30293,88 +30293,61 @@ function stringify$7(options) { var remark = unified_1().use(remarkParse).use(remarkStringify).freeze(); -const _args = [["remark@8.0.0","D:\\code\\prws\\tools\\node-lint-md-cli-rollup"]]; -const _from = "remark@8.0.0"; -const _id = "remark@8.0.0"; -const _inBundle = false; -const _integrity = "sha512-K0PTsaZvJlXTl9DN6qYlvjTkqSZBFELhROZMrblm2rB+085flN84nz4g/BscKRMqDvhzlK1oQ/xnWQumdeNZYw=="; -const _location = "/remark"; -const _phantomChildren = {}; -const _requested = {"type":"version","registry":true,"raw":"remark@8.0.0","name":"remark","escapedName":"remark","rawSpec":"8.0.0","saveSpec":null,"fetchSpec":"8.0.0"}; -const _requiredBy = ["/"]; -const _resolved = "https://registry.npmjs.org/remark/-/remark-8.0.0.tgz"; -const _spec = "8.0.0"; -const _where = "D:\\code\\prws\\tools\\node-lint-md-cli-rollup"; -const author = {"name":"Titus Wormer","email":"tituswormer@gmail.com","url":"http://wooorm.com"}; -const bugs = {"url":"https://github.com/wooorm/remark/issues"}; -const contributors = [{"name":"Titus Wormer","email":"tituswormer@gmail.com","url":"http://wooorm.com"}]; -const dependencies = {"remark-parse":"^4.0.0","remark-stringify":"^4.0.0","unified":"^6.0.0"}; +const name = "remark"; +const version$1 = "8.0.0"; const description = "Markdown processor powered by plugins"; -const files = ["index.js"]; -const homepage = "http://remark.js.org"; -const keywords = ["markdown","abstract","syntax","tree","ast","parse","stringify","process"]; const license = "MIT"; -const name = "remark"; -const repository = {"type":"git","url":"https://github.com/wooorm/remark/tree/master/packages/remark"}; +const keywords = ["markdown","abstract","syntax","tree","ast","parse","stringify","process"]; +const dependencies = {"remark-parse":"^4.0.0","remark-stringify":"^4.0.0","unified":"^6.0.0"}; +const homepage = "http://remark.js.org"; +const repository = "https://github.com/wooorm/remark/tree/master/packages/remark"; +const bugs = "https://github.com/wooorm/remark/issues"; +const author = "Titus Wormer (http://wooorm.com)"; +const contributors = ["Titus Wormer (http://wooorm.com)"]; +const files = ["index.js"]; const scripts = {}; -const version$1 = "8.0.0"; const xo = false; +const _resolved = "https://registry.npmjs.org/remark/-/remark-8.0.0.tgz"; +const _integrity = "sha512-K0PTsaZvJlXTl9DN6qYlvjTkqSZBFELhROZMrblm2rB+085flN84nz4g/BscKRMqDvhzlK1oQ/xnWQumdeNZYw=="; +const _from = "remark@8.0.0"; var _package = { - _args: _args, - _from: _from, - _id: _id, - _inBundle: _inBundle, - _integrity: _integrity, - _location: _location, - _phantomChildren: _phantomChildren, - _requested: _requested, - _requiredBy: _requiredBy, - _resolved: _resolved, - _spec: _spec, - _where: _where, - author: author, - bugs: bugs, - contributors: contributors, - dependencies: dependencies, + name: name, + version: version$1, description: description, - files: files, - homepage: homepage, - keywords: keywords, license: license, - name: name, + keywords: keywords, + dependencies: dependencies, + homepage: homepage, repository: repository, + bugs: bugs, + author: author, + contributors: contributors, + files: files, scripts: scripts, - version: version$1, - xo: xo + xo: xo, + _resolved: _resolved, + _integrity: _integrity, + _from: _from }; var _package$1 = Object.freeze({ - _args: _args, - _from: _from, - _id: _id, - _inBundle: _inBundle, - _integrity: _integrity, - _location: _location, - _phantomChildren: _phantomChildren, - _requested: _requested, - _requiredBy: _requiredBy, - _resolved: _resolved, - _spec: _spec, - _where: _where, - author: author, - bugs: bugs, - contributors: contributors, - dependencies: dependencies, + name: name, + version: version$1, description: description, - files: files, - homepage: homepage, - keywords: keywords, license: license, - name: name, + keywords: keywords, + dependencies: dependencies, + homepage: homepage, repository: repository, + bugs: bugs, + author: author, + contributors: contributors, + files: files, scripts: scripts, - version: version$1, xo: xo, + _resolved: _resolved, + _integrity: _integrity, + _from: _from, default: _package }); @@ -30382,7 +30355,7 @@ const name$1 = "node-lint-md-cli-rollup"; const description$1 = "remark packaged for node markdown linting"; const version$2 = "1.0.0"; const devDependencies = {"rollup":"^0.55.5","rollup-plugin-commonjs":"^8.0.2","rollup-plugin-json":"^2.3.1","rollup-plugin-node-resolve":"^3.4.0"}; -const dependencies$1 = {"markdown-extensions":"^1.1.0","remark":"^8.0.0","remark-lint":"^6.0.2","remark-preset-lint-node":"^1.0.3","unified-args":"^6.0.0","unified-engine":"^5.1.0"}; +const dependencies$1 = {"markdown-extensions":"^1.1.0","remark":"^8.0.0","remark-lint":"^6.0.2","remark-preset-lint-node":"^1.1.0","unified-args":"^6.0.0","unified-engine":"^5.1.0"}; const scripts$1 = {"build":"rollup -c","build-node":"npm run build && cp dist/* .."}; var _package$2 = { name: name$1, @@ -32479,7 +32452,84 @@ function noInlinePadding(tree, file) { } } +var remarkLintMaximumLineLength = unifiedLintRule('remark-lint:maximum-line-length', maximumLineLength); + var start$6 = unistUtilPosition.start; +var end$4 = unistUtilPosition.end; + +function maximumLineLength(tree, file, pref) { + var style = typeof pref === 'number' && !isNaN(pref) ? pref : 80; + var content = String(file); + var lines = content.split(/\r?\n/); + var length = lines.length; + var index = -1; + var lineLength; + + unistUtilVisit(tree, ['heading', 'table', 'code', 'definition'], ignore); + unistUtilVisit(tree, ['link', 'image', 'inlineCode'], inline); + + /* Iterate over every line, and warn for violating lines. */ + while (++index < length) { + lineLength = lines[index].length; + + if (lineLength > style) { + file.message('Line must be at most ' + style + ' characters', { + line: index + 1, + column: lineLength + 1 + }); + } + } + + /* Finally, whitelist some inline spans, but only if they occur at or after + * the wrap. However, when they do, and there’s white-space after it, they + * are not whitelisted. */ + function inline(node, pos, parent) { + var next = parent.children[pos + 1]; + var initial; + var final; + + /* istanbul ignore if - Nothing to whitelist when generated. */ + if (unistUtilGenerated(node)) { + return + } + + initial = start$6(node); + final = end$4(node); + + /* No whitelisting when starting after the border, or ending before it. */ + if (initial.column > style || final.column < style) { + return + } + + /* No whitelisting when there’s white-space after + * the link. */ + if ( + next && + start$6(next).line === initial.line && + (!next.value || /^(.+?[ \t].+?)/.test(next.value)) + ) { + return + } + + whitelist(initial.line - 1, final.line); + } + + function ignore(node) { + /* istanbul ignore else - Hard to test, as we only run this case on `position: true` */ + if (!unistUtilGenerated(node)) { + whitelist(start$6(node).line - 1, end$4(node).line); + } + } + + /* Whitelist from `initial` to `final`, zero-based. */ + function whitelist(initial, final) { + while (initial < final) { + lines[initial++] = ''; + } + } +} + +var start$7 = unistUtilPosition.start; @@ -32502,7 +32552,7 @@ function noMultipleToplevelHeadings(tree, file, pref) { node ); } else { - duplicate = unistUtilStringifyPosition(start$6(node)); + duplicate = unistUtilStringifyPosition(start$7(node)); } } } @@ -32664,8 +32714,8 @@ var rule$1 = unifiedLintRule; var remarkLintRuleStyle = rule$1('remark-lint:rule-style', ruleStyle); -var start$7 = unistUtilPosition.start; -var end$4 = unistUtilPosition.end; +var start$8 = unistUtilPosition.start; +var end$5 = unistUtilPosition.end; function ruleStyle(tree, file, pref) { var contents = String(file); @@ -32681,8 +32731,8 @@ function ruleStyle(tree, file, pref) { unistUtilVisit(tree, 'thematicBreak', visitor); function visitor(node) { - var initial = start$7(node).offset; - var final = end$4(node).offset; + var initial = start$8(node).offset; + var final = end$5(node).offset; var rule; if (!unistUtilGenerated(node)) { @@ -32701,8 +32751,8 @@ function ruleStyle(tree, file, pref) { var remarkLintTablePipes = unifiedLintRule('remark-lint:table-pipes', tablePipes); -var start$8 = unistUtilPosition.start; -var end$5 = unistUtilPosition.end; +var start$9 = unistUtilPosition.start; +var end$6 = unistUtilPosition.end; var reasonStart = 'Missing initial pipe in table fence'; var reasonEnd = 'Missing final pipe in table fence'; @@ -32730,15 +32780,15 @@ function tablePipes(tree, file) { cells = row.children; head = cells[0]; tail = cells[cells.length - 1]; - initial = contents.slice(start$8(row).offset, start$8(head).offset); - final = contents.slice(end$5(tail).offset, end$5(row).offset); + initial = contents.slice(start$9(row).offset, start$9(head).offset); + final = contents.slice(end$6(tail).offset, end$6(row).offset); if (initial.indexOf('|') === -1) { - file.message(reasonStart, start$8(row)); + file.message(reasonStart, start$9(row)); } if (final.indexOf('|') === -1) { - file.message(reasonEnd, end$5(row)); + file.message(reasonEnd, end$6(row)); } } } @@ -32800,8 +32850,8 @@ var remarkLintCheckboxCharacterStyle = unifiedLintRule( checkboxCharacterStyle ); -var start$9 = unistUtilPosition.start; -var end$6 = unistUtilPosition.end; +var start$10 = unistUtilPosition.start; +var end$7 = unistUtilPosition.end; var checked = {x: true, X: true}; var unchecked = {' ': true, '\t': true}; @@ -32846,8 +32896,8 @@ function checkboxCharacterStyle(tree, file, pref) { } type = types[node.checked]; - initial = start$9(node).offset; - final = (node.children.length ? start$9(node.children[0]) : end$6(node)).offset; + initial = start$10(node).offset; + final = (node.children.length ? start$10(node.children[0]) : end$7(node)).offset; /* For a checkbox to be parsed, it must be followed by a white space. */ value = contents @@ -32881,8 +32931,8 @@ function checkboxCharacterStyle(tree, file, pref) { var remarkLintCodeBlockStyle = unifiedLintRule('remark-lint:code-block-style', codeBlockStyle); -var start$10 = unistUtilPosition.start; -var end$7 = unistUtilPosition.end; +var start$11 = unistUtilPosition.start; +var end$8 = unistUtilPosition.end; var styles = {null: true, fenced: true, indented: true}; @@ -32915,8 +32965,8 @@ function codeBlockStyle(tree, file, pref) { /* Get the style of `node`. */ function check(node) { - var initial = start$10(node).offset; - var final = end$7(node).offset; + var initial = start$11(node).offset; + var final = end$8(node).offset; if (unistUtilGenerated(node)) { return null @@ -33111,8 +33161,8 @@ function strongMarker(tree, file, pref) { var remarkLintTableCellPadding = unifiedLintRule('remark-lint:table-cell-padding', tableCellPadding); -var start$11 = unistUtilPosition.start; -var end$8 = unistUtilPosition.end; +var start$12 = unistUtilPosition.start; +var end$9 = unistUtilPosition.end; var styles$1 = {null: true, padded: true, compact: true}; @@ -33160,8 +33210,8 @@ function tableCellPadding(tree, file, pref) { next = cells[column + 1]; fence = contents.slice( - cell ? end$8(cell).offset : start$11(row).offset, - next ? start$11(next).offset : end$8(row).offset + cell ? end$9(cell).offset : start$12(row).offset, + next ? start$12(next).offset : end$9(row).offset ); pos = fence.indexOf('|'); @@ -33238,7 +33288,7 @@ function tableCellPadding(tree, file, pref) { } function size(node) { - return end$8(node).offset - start$11(node).offset + return end$9(node).offset - start$12(node).offset } var plugins$1 = [ @@ -33258,6 +33308,7 @@ var plugins$1 = [ remarkLintNoHeadingContentIndent, remarkLintNoHeadingIndent, remarkLintNoInlinePadding, + remarkLintMaximumLineLength, remarkLintNoMultipleToplevelHeadings, remarkLintNoShellDollars, remarkLintNoShortcutReferenceImage, diff --git a/tools/lint-pr-commit-message.sh b/tools/lint-pr-commit-message.sh new file mode 100644 index 00000000000000..1998026a16ae39 --- /dev/null +++ b/tools/lint-pr-commit-message.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# Shell script to lint the message of the first commit in a pull request. +# +# Depends on curl, git, node, npm and npx being in $PATH. +# +# The pull request is either: +# 1) supplied as an argument to this shell script +# 2) derived from the HEAD commit via the GitHub API + +GH_API_URL="https://api.github.com" +PR_ID=$1; +if [ -z "${PR_ID}" ]; then + # Attempt to work out the PR number based on current HEAD + if HEAD_COMMIT="$( git rev-parse HEAD )"; then + if SEARCH_RESULTS="$( curl -s ${GH_API_URL}/search/issues?q=sha:${HEAD_COMMIT}+type:pr+repo:nodejs/node )"; then + if FOUND_PR="$( node -p 'JSON.parse(process.argv[1]).items[0].number' "${SEARCH_RESULTS}" 2> /dev/null )"; then + PR_ID=${FOUND_PR} + fi + fi + fi +fi +if [ -z "${PR_ID}" ]; then + echo "Unable to determine the pull request number to check. Please specify, " + echo " e.g. $0 " + exit 1 +fi +# Retrieve the first commit of the pull request via GitHub API +# TODO: If we teach core-validate-commit to ignore "fixup!" and "squash!" +# commits and lint messages for all commits in the pull request +# we could simplify the following to: +# npx -q core-validate-commit --no-validate-metadata ${GH_API_URL}/repos/nodejs/node/pulls/${PR_ID}/commits +if PR_COMMITS="$( curl -s ${GH_API_URL}/repos/nodejs/node/pulls/${PR_ID}/commits )"; then + if FIRST_COMMIT="$( node -p 'JSON.parse(process.argv[1])[0].url' "${PR_COMMITS}" 2> /dev/null )"; then + echo "Linting the first commit message for pull request ${PR_ID}" + echo "according to the guidelines at https://goo.gl/p2fr5Q." + # Print the commit message to make it more obvious what is being checked. + echo "Commit message for ${FIRST_COMMIT##*/} is:" + node -p 'JSON.parse(process.argv[1])[0].commit.message' "${PR_COMMITS}" 2> /dev/null + npx -q core-validate-commit --no-validate-metadata "${FIRST_COMMIT}" + else + echo "Unable to determine the first commit for pull request ${PR_ID}." + exit 1 + fi +fi diff --git a/tools/make-v8.sh b/tools/make-v8.sh index 4365412856d741..1bbf472aae7df2 100755 --- a/tools/make-v8.sh +++ b/tools/make-v8.sh @@ -1,9 +1,27 @@ -#!/bin/bash +#!/bin/bash -xe BUILD_ARCH_TYPE=$1 V8_BUILD_OPTIONS=$2 cd deps/v8 tools/node/fetch_deps.py . -PATH=~/_depot_tools:$PATH tools/dev/v8gen.py $BUILD_ARCH_TYPE --no-goma $V8_BUILD_OPTIONS -PATH=~/_depot_tools:$PATH ninja -C out.gn/$BUILD_ARCH_TYPE/ d8 cctest inspector-test + +if [ "`arch`" == "s390x" ] +then + # set paths manually for now to use locally installed gn + export BUILD_TOOLS=/home/iojs/build-tools + export LD_LIBRARY_PATH=$BUILD_TOOLS:$LD_LIBRARY_PATH + export PATH=$BUILD_TOOLS:$PATH + CXX_PATH=`which $CXX |grep g++` + rm -f "$BUILD_TOOLS/g++" + rm -f "$BUILD_TOOLS/gcc" + ln -s $CXX_PATH "$BUILD_TOOLS/g++" + ln -s $CXX_PATH "$BUILD_TOOLS/gcc" + g++ --version + export PKG_CONFIG_PATH=$BUILD_TOOLS/pkg-config + gn gen -v out.gn/$BUILD_ARCH_TYPE --args='is_component_build=false is_debug=false use_goma=false goma_dir="None" use_custom_libcxx=false v8_target_cpu="s390x" target_cpu="s390x"' + ninja -v -C out.gn/$BUILD_ARCH_TYPE d8 cctest inspector-test +else + PATH=~/_depot_tools:$PATH tools/dev/v8gen.py $BUILD_ARCH_TYPE --no-goma $V8_BUILD_OPTIONS + PATH=~/_depot_tools:$PATH ninja -C out.gn/$BUILD_ARCH_TYPE/ d8 cctest inspector-test +fi diff --git a/tools/msvs/install_tools/install_tools.bat b/tools/msvs/install_tools/install_tools.bat index db10cf1f46049e..3ae1728cbd7033 100644 --- a/tools/msvs/install_tools/install_tools.bat +++ b/tools/msvs/install_tools/install_tools.bat @@ -1,5 +1,7 @@ @echo off +setlocal + cls echo ==================================================== echo Tools for Node.js Native Modules Installation Script @@ -47,7 +49,36 @@ echo script is at your own risk. Please read the Chocolatey's legal terms of use echo and the Boxstarter project license as well as how the community repository echo for Chocolatey.org is maintained. echo. -echo You can close this window to stop now. pause +cls +echo !!!!!WARNING!!!!! +echo ----------------- +echo This script should make installing the tools as easy as possible. Hence, it +echo WILL NOT OFFER ANY CUSTOMIZATION. If there's any parameter you'd like to +echo customize (like installation directory or features), or if there's any +echo special rule or policy that your computer should comply to (like not being +echo able to log in as the user with administrative privileges), please follow the +echo instructions to download and execute the installers directly: +echo https://github.com/nodejs/node-gyp#on-windows +echo. +echo Use of Boxstarter may reboot your computer automatically multiple times. +echo When performing a reboot, Boxstarter will need to disable User Account +echo Control (UAC) to allow the script to run immediately after the reboot. When +echo the scripts have completed, Boxstarter will re-enable UAC. If you prematurely +echo stop the process, UAC will need to be re-enabled manually. +echo. +echo Sometimes the scripts may install all necessary Windows Updates which +echo could cause a high number of reboots that appear to be a reboot loop when +echo in fact it is just a normal Windows Updates reboot cycle. +:acceptretry +echo. +echo Your computer may REBOOT SEVERAL TIMES WITHOUT FURTHER WARNING. +echo Please type YES followed by enter to confirm that you have saved all your +set /p "ACCEPT_PROMPT=work and closed all open programs: " +if /i not "%ACCEPT_PROMPT%"=="yes" ( + echo Please type YES to confirm, or close the window to exit. + goto acceptretry +) + "%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command Start-Process '%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe' -ArgumentList '-NoProfile -InputFormat None -ExecutionPolicy Bypass -Command iex ((New-Object System.Net.WebClient).DownloadString(''https://boxstarter.org/bootstrapper.ps1'')); get-boxstarter -Force; Install-BoxstarterPackage -PackageName ''%~dp0\install_tools.txt''; Read-Host ''Type ENTER to exit'' ' -Verb RunAs diff --git a/tools/node-lint-md-cli-rollup/package-lock.json b/tools/node-lint-md-cli-rollup/package-lock.json index 49fcc015cd6829..2d37506884a12b 100644 --- a/tools/node-lint-md-cli-rollup/package-lock.json +++ b/tools/node-lint-md-cli-rollup/package-lock.json @@ -2108,6 +2108,17 @@ "unist-util-visit": "^1.1.1" } }, + "remark-lint-maximum-line-length": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remark-lint-maximum-line-length/-/remark-lint-maximum-line-length-1.1.0.tgz", + "integrity": "sha512-L+jI6+DReoxHyAWRIxABjX8hPDgxB8B5Lzp0/nDYjWbjl7I4vTsdEvejpmP1K8LVvZ7Ew0XcVHd1zt+p2O8tDg==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, "remark-lint-no-auto-link-without-protocol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/remark-lint-no-auto-link-without-protocol/-/remark-lint-no-auto-link-without-protocol-1.0.2.tgz", @@ -2352,9 +2363,9 @@ } }, "remark-preset-lint-node": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-1.0.3.tgz", - "integrity": "sha512-Ztmm7tcdWWmz/tpCU+bBz9QDRfjrTsa4PUSUWXwPBjQA07asGmw9qUzNTFc1iHXpXVs9xEz1IbVXpWwEJ+9uvA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-1.1.0.tgz", + "integrity": "sha512-wT37p0rYGgSy92XNjd7S5WZmtzRLq5iYT9mhVo/p3dVG9oF5NjOjFNUFu/6JBYgGBmZllftWvhrUpKNg+QXqug==", "requires": { "remark-lint": "^6.0.0", "remark-lint-blockquote-indentation": "^1.0.0", @@ -2370,6 +2381,7 @@ "remark-lint-first-heading-level": "^1.0.0", "remark-lint-hard-break-spaces": "^1.0.1", "remark-lint-heading-style": "^1.0.0", + "remark-lint-maximum-line-length": "^1.1.0", "remark-lint-no-auto-link-without-protocol": "^1.0.0", "remark-lint-no-blockquote-without-caret": "^1.0.0", "remark-lint-no-duplicate-definitions": "^1.0.0", @@ -3173,9 +3185,9 @@ } }, "unist-util-generated": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.2.tgz", - "integrity": "sha512-1HcwiEO62dr0XWGT+abVK4f0aAm8Ik8N08c5nAYVmuSxfvpA9rCcNyX/le8xXj1pJK5nBrGlZefeWB6bN8Pstw==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.3.tgz", + "integrity": "sha512-qlPeDqnQnd84KIqwphzOR+l02cxjDzvEYEBl84EjmKRrX4eUmjyAo8xJv1SCDhJqNjyHRnBMZWNKAiBtXE6hBg==" }, "unist-util-inspect": { "version": "4.1.3", @@ -3191,9 +3203,9 @@ "integrity": "sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw==" }, "unist-util-position": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.1.tgz", - "integrity": "sha512-05QfJDPI7PE1BIUtAxeSV+cDx21xP7+tUZgSval5CA7tr0pHBwybF7OnEa1dOFqg6BfYH/qiMUnWwWj+Frhlww==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.2.tgz", + "integrity": "sha512-npmFu92l/+b1Ao6uGP4I1WFz9hsKv7qleZ4aliw6x0RVu6A9A3tAf57NMpFfzQ02jxRtJZuRn+C8xWT7GWnH0g==" }, "unist-util-remove-position": { "version": "1.1.2", diff --git a/tools/node-lint-md-cli-rollup/package.json b/tools/node-lint-md-cli-rollup/package.json index e2b105f91bcf4f..b3d491717d4d2f 100644 --- a/tools/node-lint-md-cli-rollup/package.json +++ b/tools/node-lint-md-cli-rollup/package.json @@ -12,7 +12,7 @@ "markdown-extensions": "^1.1.0", "remark": "^8.0.0", "remark-lint": "^6.0.2", - "remark-preset-lint-node": "^1.0.3", + "remark-preset-lint-node": "^1.1.0", "unified-args": "^6.0.0", "unified-engine": "^5.1.0" }, diff --git a/tools/node_modules/eslint/lib/cli-engine.js b/tools/node_modules/eslint/lib/cli-engine.js index 5b52459ac830dc..652d68b59b4953 100644 --- a/tools/node_modules/eslint/lib/cli-engine.js +++ b/tools/node_modules/eslint/lib/cli-engine.js @@ -19,8 +19,10 @@ const fs = require("fs"), path = require("path"), defaultOptions = require("../conf/default-cli-options"), Linter = require("./linter"), + lodash = require("lodash"), IgnoredPaths = require("./ignored-paths"), Config = require("./config"), + ConfigOps = require("./config/config-ops"), LintResultCache = require("./util/lint-result-cache"), globUtils = require("./util/glob-utils"), validator = require("./config/config-validator"), @@ -31,6 +33,7 @@ const fs = require("fs"), const debug = require("debug")("eslint:cli-engine"); const resolver = new ModuleResolver(); +const validFixTypes = new Set(["problem", "suggestion", "layout"]); //------------------------------------------------------------------------------ // Typedefs @@ -48,6 +51,7 @@ const resolver = new ModuleResolver(); * @property {string[]} envs An array of environments to load. * @property {string[]} extensions An array of file extensions to check. * @property {boolean|Function} fix Execute in autofix mode. If a function, should return a boolean. + * @property {string[]} fixTypes Array of rule types to apply fixes for. * @property {string[]} globals An array of global variables to declare. * @property {boolean} ignore False disables use of .eslintignore. * @property {string} ignorePath The ignore file to use instead of .eslintignore. @@ -84,6 +88,21 @@ const resolver = new ModuleResolver(); // Helpers //------------------------------------------------------------------------------ +/** + * Determines if each fix type in an array is supported by ESLint and throws + * an error if not. + * @param {string[]} fixTypes An array of fix types to check. + * @returns {void} + * @throws {Error} If an invalid fix type is found. + */ +function validateFixTypes(fixTypes) { + for (const fixType of fixTypes) { + if (!validFixTypes.has(fixType)) { + throw new Error(`Invalid fix type "${fixType}" found.`); + } + } +} + /** * It will calculate the error and warning count for collection of messages per file * @param {Object[]} messages - Collection of messages @@ -142,7 +161,7 @@ function calculateStatsPerRun(results) { * @param {boolean} allowInlineConfig Allow/ignore comments that change config. * @param {boolean} reportUnusedDisableDirectives Allow/ignore comments that change config. * @param {Linter} linter Linter context - * @returns {LintResult} The results for linting on this text. + * @returns {{rules: LintResult, config: Object}} The results for linting on this text and the fully-resolved config for it. * @private */ function processText(text, configHelper, filename, fix, allowInlineConfig, reportUnusedDisableDirectives, linter) { @@ -174,7 +193,6 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor } const autofixingEnabled = typeof fix !== "undefined" && (!processor || processor.supportsAutofix); - const fixedResult = linter.verifyAndFix(text, config, { filename: effectiveFilename, allowInlineConfig, @@ -183,7 +201,6 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor preprocess: processor && (rawText => processor.preprocess(rawText, effectiveFilename)), postprocess: processor && (problemLists => processor.postprocess(problemLists, effectiveFilename)) }); - const stats = calculateStatsPerFile(fixedResult.messages); const result = { @@ -203,7 +220,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor result.source = text; } - return result; + return { result, config }; } /** @@ -213,24 +230,22 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor * @param {Object} configHelper The configuration options for ESLint. * @param {Object} options The CLIEngine options object. * @param {Linter} linter Linter context - * @returns {LintResult} The results for linting on this file. + * @returns {{rules: LintResult, config: Object}} The results for linting on this text and the fully-resolved config for it. * @private */ function processFile(filename, configHelper, options, linter) { - const text = fs.readFileSync(path.resolve(filename), "utf8"), - result = processText( - text, - configHelper, - filename, - options.fix, - options.allowInlineConfig, - options.reportUnusedDisableDirectives, - linter - ); - - return result; - + const text = fs.readFileSync(path.resolve(filename), "utf8"); + + return processText( + text, + configHelper, + filename, + options.fix, + options.allowInlineConfig, + options.reportUnusedDisableDirectives, + linter + ); } /** @@ -272,6 +287,33 @@ function createIgnoreResult(filePath, baseDir) { }; } +/** + * Produces rule warnings (i.e. deprecation) from configured rules + * @param {(Array|Set)} usedRules - Rules configured + * @param {Map} loadedRules - Map of loaded rules + * @returns {Array} Contains rule warnings + * @private + */ +function createRuleDeprecationWarnings(usedRules, loadedRules) { + const usedDeprecatedRules = []; + + usedRules.forEach(name => { + const loadedRule = loadedRules.get(name); + + if (loadedRule && loadedRule.meta && loadedRule.meta.deprecated) { + const deprecatedRule = { ruleId: name }; + const replacedBy = lodash.get(loadedRule, "meta.replacedBy", []); + + if (replacedBy.every(newRule => lodash.isString(newRule))) { + deprecatedRule.replacedBy = replacedBy; + } + + usedDeprecatedRules.push(deprecatedRule); + } + }); + + return usedDeprecatedRules; +} /** * Checks if the given message is an error message. @@ -429,6 +471,33 @@ class CLIEngine { */ this._lintResultCache = new LintResultCache(cacheFile, this.config); } + + // setup special filter for fixes + if (this.options.fix && this.options.fixTypes && this.options.fixTypes.length > 0) { + + debug(`Using fix types ${this.options.fixTypes}`); + + // throw an error if any invalid fix types are found + validateFixTypes(this.options.fixTypes); + + // convert to Set for faster lookup + const fixTypes = new Set(this.options.fixTypes); + + // save original value of options.fix in case it's a function + const originalFix = (typeof this.options.fix === "function") + ? this.options.fix : () => this.options.fix; + + // create a cache of rules (but don't populate until needed) + this._rulesCache = null; + + this.options.fix = lintResult => { + const rule = this._rulesCache.get(lintResult.ruleId); + const matches = rule.meta && fixTypes.has(rule.meta.type); + + return matches && originalFix(lintResult); + }; + } + } getRules() { @@ -511,6 +580,7 @@ class CLIEngine { const startTime = Date.now(); const fileList = globUtils.listFilesToProcess(patterns, options); + const allUsedRules = new Set(); const results = fileList.map(fileInfo => { if (fileInfo.ignored) { return createIgnoreResult(fileInfo.filename, options.cwd); @@ -532,9 +602,20 @@ class CLIEngine { } } + // if there's a cache, populate it + if ("_rulesCache" in this) { + this._rulesCache = this.getRules(); + } + debug(`Processing ${fileInfo.filename}`); - return processFile(fileInfo.filename, configHelper, options, this.linter); + const { result, config } = processFile(fileInfo.filename, configHelper, options, this.linter); + + Object.keys(config.rules) + .filter(ruleId => ConfigOps.getRuleSeverity(config.rules[ruleId])) + .forEach(ruleId => allUsedRules.add(ruleId)); + + return result; }); if (options.cache) { @@ -555,6 +636,8 @@ class CLIEngine { const stats = calculateStatsPerRun(results); + const usedDeprecatedRules = createRuleDeprecationWarnings(allUsedRules, this.getRules()); + debug(`Linting complete in: ${Date.now() - startTime}ms`); return { @@ -562,7 +645,8 @@ class CLIEngine { errorCount: stats.errorCount, warningCount: stats.warningCount, fixableErrorCount: stats.fixableErrorCount, - fixableWarningCount: stats.fixableWarningCount + fixableWarningCount: stats.fixableWarningCount, + usedDeprecatedRules }; } @@ -585,22 +669,34 @@ class CLIEngine { const resolvedFilename = filename && !path.isAbsolute(filename) ? path.resolve(options.cwd, filename) : filename; + let usedDeprecatedRules; if (resolvedFilename && ignoredPaths.contains(resolvedFilename)) { if (warnIgnored) { results.push(createIgnoreResult(resolvedFilename, options.cwd)); } + usedDeprecatedRules = []; } else { - results.push( - processText( - text, - configHelper, - resolvedFilename, - options.fix, - options.allowInlineConfig, - options.reportUnusedDisableDirectives, - this.linter - ) + + // if there's a cache, populate it + if ("_rulesCache" in this) { + this._rulesCache = this.getRules(); + } + + const { result, config } = processText( + text, + configHelper, + resolvedFilename, + options.fix, + options.allowInlineConfig, + options.reportUnusedDisableDirectives, + this.linter + ); + + results.push(result); + usedDeprecatedRules = createRuleDeprecationWarnings( + Object.keys(config.rules).filter(rule => ConfigOps.getRuleSeverity(config.rules[rule])), + this.getRules() ); } @@ -611,7 +707,8 @@ class CLIEngine { errorCount: stats.errorCount, warningCount: stats.warningCount, fixableErrorCount: stats.fixableErrorCount, - fixableWarningCount: stats.fixableWarningCount + fixableWarningCount: stats.fixableWarningCount, + usedDeprecatedRules }; } diff --git a/tools/node_modules/eslint/lib/cli.js b/tools/node_modules/eslint/lib/cli.js index f854015fe9c056..f67eb7274ffa64 100644 --- a/tools/node_modules/eslint/lib/cli.js +++ b/tools/node_modules/eslint/lib/cli.js @@ -64,6 +64,7 @@ function translateOptions(cliOptions) { cacheFile: cliOptions.cacheFile, cacheLocation: cliOptions.cacheLocation, fix: (cliOptions.fix || cliOptions.fixDryRun) && (cliOptions.quiet ? quietFixPredicate : true), + fixTypes: cliOptions.fixType, allowInlineConfig: cliOptions.inlineConfig, reportUnusedDisableDirectives: cliOptions.reportUnusedDisableDirectives }; @@ -187,8 +188,12 @@ const cli = { return 2; } - const engine = new CLIEngine(translateOptions(currentOptions)); + if (currentOptions.fixType && !currentOptions.fix && !currentOptions.fixDryRun) { + log.error("The --fix-type option requires either --fix or --fix-dry-run."); + return 2; + } + const engine = new CLIEngine(translateOptions(currentOptions)); const report = useStdin ? engine.executeOnText(text, currentOptions.stdinFilename, true) : engine.executeOnFiles(files); if (currentOptions.fix) { diff --git a/tools/node_modules/eslint/lib/options.js b/tools/node_modules/eslint/lib/options.js index 9265d151d5c592..ee7357a296aa05 100644 --- a/tools/node_modules/eslint/lib/options.js +++ b/tools/node_modules/eslint/lib/options.js @@ -97,6 +97,11 @@ module.exports = optionator({ default: false, description: "Automatically fix problems without saving the changes to the file system" }, + { + option: "fix-type", + type: "Array", + description: "Specify the types of fixes to apply (problem, suggestion, layout)" + }, { heading: "Ignoring files" }, diff --git a/tools/node_modules/eslint/lib/rules/accessor-pairs.js b/tools/node_modules/eslint/lib/rules/accessor-pairs.js index 68607295438594..032e89430571fa 100644 --- a/tools/node_modules/eslint/lib/rules/accessor-pairs.js +++ b/tools/node_modules/eslint/lib/rules/accessor-pairs.js @@ -72,12 +72,15 @@ function isPropertyDescriptor(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce getter and setter pairs in objects", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/accessor-pairs" }, + schema: [{ type: "object", properties: { @@ -90,6 +93,7 @@ module.exports = { }, additionalProperties: false }], + messages: { getter: "Getter is not present.", setter: "Setter is not present." diff --git a/tools/node_modules/eslint/lib/rules/array-bracket-newline.js b/tools/node_modules/eslint/lib/rules/array-bracket-newline.js index e8f7c502ef493d..a458e69f761687 100644 --- a/tools/node_modules/eslint/lib/rules/array-bracket-newline.js +++ b/tools/node_modules/eslint/lib/rules/array-bracket-newline.js @@ -13,13 +13,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce linebreaks after opening and before closing array brackets", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/array-bracket-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ @@ -42,6 +46,7 @@ module.exports = { ] } ], + messages: { unexpectedOpeningLinebreak: "There should be no linebreak after '['.", unexpectedClosingLinebreak: "There should be no linebreak before ']'.", diff --git a/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js b/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js index f46c3978dfa468..4bead37a12f51e 100644 --- a/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js +++ b/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js @@ -12,13 +12,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside array brackets", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/array-bracket-spacing" }, + fixable: "whitespace", + schema: [ { enum: ["always", "never"] @@ -39,6 +43,7 @@ module.exports = { additionalProperties: false } ], + messages: { unexpectedSpaceAfter: "There should be no space after '{{tokenValue}}'.", unexpectedSpaceBefore: "There should be no space before '{{tokenValue}}'.", diff --git a/tools/node_modules/eslint/lib/rules/array-callback-return.js b/tools/node_modules/eslint/lib/rules/array-callback-return.js index 4d374cf22404d4..bfee39b037bc7d 100644 --- a/tools/node_modules/eslint/lib/rules/array-callback-return.js +++ b/tools/node_modules/eslint/lib/rules/array-callback-return.js @@ -141,6 +141,8 @@ function isCallbackOfArrayMethod(node) { module.exports = { meta: { + type: "problem", + docs: { description: "enforce `return` statements in callbacks of array methods", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/array-element-newline.js b/tools/node_modules/eslint/lib/rules/array-element-newline.js index c4caf8c71c0aac..440290917d39b0 100644 --- a/tools/node_modules/eslint/lib/rules/array-element-newline.js +++ b/tools/node_modules/eslint/lib/rules/array-element-newline.js @@ -13,13 +13,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce line breaks after each array element", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/array-element-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ diff --git a/tools/node_modules/eslint/lib/rules/arrow-body-style.js b/tools/node_modules/eslint/lib/rules/arrow-body-style.js index 92068c75c42463..c2ce3b59e4f436 100644 --- a/tools/node_modules/eslint/lib/rules/arrow-body-style.js +++ b/tools/node_modules/eslint/lib/rules/arrow-body-style.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require braces around arrow function bodies", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/arrow-parens.js b/tools/node_modules/eslint/lib/rules/arrow-parens.js index 7a6ef6f8bed781..637a0c1f1f13a5 100644 --- a/tools/node_modules/eslint/lib/rules/arrow-parens.js +++ b/tools/node_modules/eslint/lib/rules/arrow-parens.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require parentheses around arrow function arguments", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/arrow-spacing.js b/tools/node_modules/eslint/lib/rules/arrow-spacing.js index a1db18fc910bbc..87d381840a95dc 100644 --- a/tools/node_modules/eslint/lib/rules/arrow-spacing.js +++ b/tools/node_modules/eslint/lib/rules/arrow-spacing.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after the arrow in arrow functions", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/block-scoped-var.js b/tools/node_modules/eslint/lib/rules/block-scoped-var.js index 1000fbc83c6557..053cfc334cd11a 100644 --- a/tools/node_modules/eslint/lib/rules/block-scoped-var.js +++ b/tools/node_modules/eslint/lib/rules/block-scoped-var.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the use of variables within the scope they are defined", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/block-spacing.js b/tools/node_modules/eslint/lib/rules/block-spacing.js index 838c2c7016b62f..6496f8596d31b7 100644 --- a/tools/node_modules/eslint/lib/rules/block-spacing.js +++ b/tools/node_modules/eslint/lib/rules/block-spacing.js @@ -13,6 +13,8 @@ const util = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow or enforce spaces inside of blocks after opening block and before closing block", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/brace-style.js b/tools/node_modules/eslint/lib/rules/brace-style.js index 236a01096ab196..d172124d2f48f7 100644 --- a/tools/node_modules/eslint/lib/rules/brace-style.js +++ b/tools/node_modules/eslint/lib/rules/brace-style.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent brace style for blocks", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/callback-return.js b/tools/node_modules/eslint/lib/rules/callback-return.js index f55fed87db0598..c5263cde46b752 100644 --- a/tools/node_modules/eslint/lib/rules/callback-return.js +++ b/tools/node_modules/eslint/lib/rules/callback-return.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `return` statements after callbacks", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/camelcase.js b/tools/node_modules/eslint/lib/rules/camelcase.js index 41040450f94294..8aeb4b5bd0df92 100644 --- a/tools/node_modules/eslint/lib/rules/camelcase.js +++ b/tools/node_modules/eslint/lib/rules/camelcase.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce camelcase naming convention", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/capitalized-comments.js b/tools/node_modules/eslint/lib/rules/capitalized-comments.js index 8fabde287cc9be..86427ba7acc5d0 100644 --- a/tools/node_modules/eslint/lib/rules/capitalized-comments.js +++ b/tools/node_modules/eslint/lib/rules/capitalized-comments.js @@ -108,13 +108,17 @@ function createRegExpForIgnorePatterns(normalizedOptions) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce or disallow capitalization of the first letter of a comment", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/capitalized-comments" }, + fixable: "code", + schema: [ { enum: ["always", "never"] }, { diff --git a/tools/node_modules/eslint/lib/rules/class-methods-use-this.js b/tools/node_modules/eslint/lib/rules/class-methods-use-this.js index b7d94135bb70dc..a15ab6b89e480f 100644 --- a/tools/node_modules/eslint/lib/rules/class-methods-use-this.js +++ b/tools/node_modules/eslint/lib/rules/class-methods-use-this.js @@ -11,12 +11,15 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce that class methods utilize `this`", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/class-methods-use-this" }, + schema: [{ type: "object", properties: { diff --git a/tools/node_modules/eslint/lib/rules/comma-dangle.js b/tools/node_modules/eslint/lib/rules/comma-dangle.js index 9bc6c3fa8cc7bd..96799b30796349 100644 --- a/tools/node_modules/eslint/lib/rules/comma-dangle.js +++ b/tools/node_modules/eslint/lib/rules/comma-dangle.js @@ -76,13 +76,17 @@ function normalizeOptions(optionValue) { module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow trailing commas", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/comma-dangle" }, + fixable: "code", + schema: { definitions: { value: { diff --git a/tools/node_modules/eslint/lib/rules/comma-spacing.js b/tools/node_modules/eslint/lib/rules/comma-spacing.js index d3f82b3a4b9f14..2db0035b545348 100644 --- a/tools/node_modules/eslint/lib/rules/comma-spacing.js +++ b/tools/node_modules/eslint/lib/rules/comma-spacing.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after commas", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/comma-style.js b/tools/node_modules/eslint/lib/rules/comma-style.js index 7f996b344d4c16..2586cf66e9226b 100644 --- a/tools/node_modules/eslint/lib/rules/comma-style.js +++ b/tools/node_modules/eslint/lib/rules/comma-style.js @@ -13,13 +13,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent comma style", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/comma-style" }, + fixable: "code", + schema: [ { enum: ["first", "last"] @@ -37,6 +41,7 @@ module.exports = { additionalProperties: false } ], + messages: { unexpectedLineBeforeAndAfterComma: "Bad line breaking before and after ','.", expectedCommaFirst: "',' should be placed first.", diff --git a/tools/node_modules/eslint/lib/rules/complexity.js b/tools/node_modules/eslint/lib/rules/complexity.js index bc66d303b6340f..af583c02791dd0 100644 --- a/tools/node_modules/eslint/lib/rules/complexity.js +++ b/tools/node_modules/eslint/lib/rules/complexity.js @@ -20,6 +20,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum cyclomatic complexity allowed in a program", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js index 060b2c5b40d5a2..188d863d0d0f83 100644 --- a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js +++ b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside computed property brackets", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/consistent-return.js b/tools/node_modules/eslint/lib/rules/consistent-return.js index 6185d094fb59c0..ffd7ef20589490 100644 --- a/tools/node_modules/eslint/lib/rules/consistent-return.js +++ b/tools/node_modules/eslint/lib/rules/consistent-return.js @@ -53,6 +53,8 @@ function isClassConstructor(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `return` statements to either always or never specify values", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/consistent-this.js b/tools/node_modules/eslint/lib/rules/consistent-this.js index 5cc3a647dab551..4bdcdfdc10e8f0 100644 --- a/tools/node_modules/eslint/lib/rules/consistent-this.js +++ b/tools/node_modules/eslint/lib/rules/consistent-this.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce consistent naming when capturing the current execution context", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/constructor-super.js b/tools/node_modules/eslint/lib/rules/constructor-super.js index 3cbc2f59f894b4..e4cdb099b3bf52 100644 --- a/tools/node_modules/eslint/lib/rules/constructor-super.js +++ b/tools/node_modules/eslint/lib/rules/constructor-super.js @@ -92,6 +92,8 @@ function isPossibleConstructor(node) { module.exports = { meta: { + type: "problem", + docs: { description: "require `super()` calls in constructors", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/curly.js b/tools/node_modules/eslint/lib/rules/curly.js index ad8da821c1cba4..ee12da71352372 100644 --- a/tools/node_modules/eslint/lib/rules/curly.js +++ b/tools/node_modules/eslint/lib/rules/curly.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce consistent brace style for all control statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/default-case.js b/tools/node_modules/eslint/lib/rules/default-case.js index cf123198f4ae87..3061265ed8ec4f 100644 --- a/tools/node_modules/eslint/lib/rules/default-case.js +++ b/tools/node_modules/eslint/lib/rules/default-case.js @@ -12,6 +12,8 @@ const DEFAULT_COMMENT_PATTERN = /^no default$/i; module.exports = { meta: { + type: "suggestion", + docs: { description: "require `default` cases in `switch` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/dot-location.js b/tools/node_modules/eslint/lib/rules/dot-location.js index 34d2d4eaab8d78..0eefec2eaffee0 100644 --- a/tools/node_modules/eslint/lib/rules/dot-location.js +++ b/tools/node_modules/eslint/lib/rules/dot-location.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent newlines before and after dots", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/dot-notation.js b/tools/node_modules/eslint/lib/rules/dot-notation.js index a7062df8a5babc..55ccea4ce38f4c 100644 --- a/tools/node_modules/eslint/lib/rules/dot-notation.js +++ b/tools/node_modules/eslint/lib/rules/dot-notation.js @@ -19,6 +19,8 @@ const keywords = require("../util/keywords"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce dot notation whenever possible", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/eol-last.js b/tools/node_modules/eslint/lib/rules/eol-last.js index 3ecf4227399307..84f4d45f176bbc 100644 --- a/tools/node_modules/eslint/lib/rules/eol-last.js +++ b/tools/node_modules/eslint/lib/rules/eol-last.js @@ -16,18 +16,23 @@ const lodash = require("lodash"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow newline at the end of files", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/eol-last" }, + fixable: "whitespace", + schema: [ { enum: ["always", "never", "unix", "windows"] } ], + messages: { missing: "Newline required at end of file but not found.", unexpected: "Newline not allowed at end of file." diff --git a/tools/node_modules/eslint/lib/rules/eqeqeq.js b/tools/node_modules/eslint/lib/rules/eqeqeq.js index 2c5e9ae9e4fdad..715c5ce7c027c7 100644 --- a/tools/node_modules/eslint/lib/rules/eqeqeq.js +++ b/tools/node_modules/eslint/lib/rules/eqeqeq.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require the use of `===` and `!==`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/for-direction.js b/tools/node_modules/eslint/lib/rules/for-direction.js index b93c4c2caa4b66..db079b267935cb 100644 --- a/tools/node_modules/eslint/lib/rules/for-direction.js +++ b/tools/node_modules/eslint/lib/rules/for-direction.js @@ -11,14 +11,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "enforce \"for\" loop update clause moving the counter in the right direction.", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/for-direction" }, + fixable: null, schema: [], + messages: { incorrectDirection: "The update clause in this loop moves the variable in the wrong direction." } diff --git a/tools/node_modules/eslint/lib/rules/func-call-spacing.js b/tools/node_modules/eslint/lib/rules/func-call-spacing.js index 9aae3e2517e05b..c49aa9e59f7e9c 100644 --- a/tools/node_modules/eslint/lib/rules/func-call-spacing.js +++ b/tools/node_modules/eslint/lib/rules/func-call-spacing.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing between function identifiers and their invocations", category: "Stylistic Issues", @@ -25,6 +27,7 @@ module.exports = { }, fixable: "whitespace", + schema: { anyOf: [ { @@ -58,6 +61,7 @@ module.exports = { } ] }, + messages: { unexpected: "Unexpected newline between function name and paren.", missing: "Missing space between function name and paren." diff --git a/tools/node_modules/eslint/lib/rules/func-name-matching.js b/tools/node_modules/eslint/lib/rules/func-name-matching.js index 89c07c3514c6b2..f14c998dc7fb90 100644 --- a/tools/node_modules/eslint/lib/rules/func-name-matching.js +++ b/tools/node_modules/eslint/lib/rules/func-name-matching.js @@ -70,6 +70,8 @@ const optionsObject = { module.exports = { meta: { + type: "suggestion", + docs: { description: "require function names to match the name of the variable or property to which they are assigned", category: "Stylistic Issues", @@ -88,6 +90,7 @@ module.exports = { items: [optionsObject] }] }, + messages: { matchProperty: "Function name `{{funcName}}` should match property name `{{name}}`", matchVariable: "Function name `{{funcName}}` should match variable name `{{name}}`", diff --git a/tools/node_modules/eslint/lib/rules/func-names.js b/tools/node_modules/eslint/lib/rules/func-names.js index 31f302918116e6..4ccbae0f0cb849 100644 --- a/tools/node_modules/eslint/lib/rules/func-names.js +++ b/tools/node_modules/eslint/lib/rules/func-names.js @@ -26,6 +26,8 @@ function isFunctionName(variable) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow named `function` expressions", category: "Stylistic Issues", @@ -58,6 +60,7 @@ module.exports = { } ] }, + messages: { unnamed: "Unexpected unnamed {{name}}.", named: "Unexpected named {{name}}." diff --git a/tools/node_modules/eslint/lib/rules/func-style.js b/tools/node_modules/eslint/lib/rules/func-style.js index ff48792d29af5d..b7e368cbd2ea08 100644 --- a/tools/node_modules/eslint/lib/rules/func-style.js +++ b/tools/node_modules/eslint/lib/rules/func-style.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the consistent use of either `function` declarations or expressions", category: "Stylistic Issues", @@ -31,6 +33,7 @@ module.exports = { additionalProperties: false } ], + messages: { expression: "Expected a function expression.", declaration: "Expected a function declaration." diff --git a/tools/node_modules/eslint/lib/rules/function-paren-newline.js b/tools/node_modules/eslint/lib/rules/function-paren-newline.js index d78e88038e2030..37256484f4a16e 100644 --- a/tools/node_modules/eslint/lib/rules/function-paren-newline.js +++ b/tools/node_modules/eslint/lib/rules/function-paren-newline.js @@ -16,13 +16,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent line breaks inside function parentheses", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/function-paren-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ @@ -42,6 +46,7 @@ module.exports = { ] } ], + messages: { expectedBefore: "Expected newline before ')'.", expectedAfter: "Expected newline after '('.", diff --git a/tools/node_modules/eslint/lib/rules/generator-star-spacing.js b/tools/node_modules/eslint/lib/rules/generator-star-spacing.js index 97868dd3fa980e..6f860290cec8b6 100644 --- a/tools/node_modules/eslint/lib/rules/generator-star-spacing.js +++ b/tools/node_modules/eslint/lib/rules/generator-star-spacing.js @@ -27,6 +27,8 @@ const OVERRIDE_SCHEMA = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing around `*` operators in generator functions", category: "ECMAScript 6", @@ -56,6 +58,7 @@ module.exports = { ] } ], + messages: { missingBefore: "Missing space before *.", missingAfter: "Missing space after *.", diff --git a/tools/node_modules/eslint/lib/rules/getter-return.js b/tools/node_modules/eslint/lib/rules/getter-return.js index 452ba49f595783..dc3d9d6b627e62 100644 --- a/tools/node_modules/eslint/lib/rules/getter-return.js +++ b/tools/node_modules/eslint/lib/rules/getter-return.js @@ -44,13 +44,17 @@ function getId(node) { module.exports = { meta: { + type: "problem", + docs: { description: "enforce `return` statements in getters", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/getter-return" }, + fixable: null, + schema: [ { type: "object", @@ -62,6 +66,7 @@ module.exports = { additionalProperties: false } ], + messages: { expected: "Expected to return a value in {{name}}.", expectedAlways: "Expected {{name}} to always return a value." diff --git a/tools/node_modules/eslint/lib/rules/global-require.js b/tools/node_modules/eslint/lib/rules/global-require.js index a5f5335d01dc12..6576cfb6a1f5ad 100644 --- a/tools/node_modules/eslint/lib/rules/global-require.js +++ b/tools/node_modules/eslint/lib/rules/global-require.js @@ -48,6 +48,8 @@ function isShadowed(scope, node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `require()` calls to be placed at top-level module scope", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/guard-for-in.js b/tools/node_modules/eslint/lib/rules/guard-for-in.js index 0f85e4984aa2cf..6e8452a4844a6e 100644 --- a/tools/node_modules/eslint/lib/rules/guard-for-in.js +++ b/tools/node_modules/eslint/lib/rules/guard-for-in.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `for-in` loops to include an `if` statement", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/handle-callback-err.js b/tools/node_modules/eslint/lib/rules/handle-callback-err.js index f6e6c108ce15c2..c62016d5895dcc 100644 --- a/tools/node_modules/eslint/lib/rules/handle-callback-err.js +++ b/tools/node_modules/eslint/lib/rules/handle-callback-err.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require error handling in callbacks", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/id-blacklist.js b/tools/node_modules/eslint/lib/rules/id-blacklist.js index ba9b5d4b398261..7b8facbabe0868 100644 --- a/tools/node_modules/eslint/lib/rules/id-blacklist.js +++ b/tools/node_modules/eslint/lib/rules/id-blacklist.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified identifiers", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/id-length.js b/tools/node_modules/eslint/lib/rules/id-length.js index eaed26217ddf65..d72eb08876ab37 100644 --- a/tools/node_modules/eslint/lib/rules/id-length.js +++ b/tools/node_modules/eslint/lib/rules/id-length.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce minimum and maximum identifier lengths", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/id-match.js b/tools/node_modules/eslint/lib/rules/id-match.js index 608ef17d11485b..4755c779ca96a0 100644 --- a/tools/node_modules/eslint/lib/rules/id-match.js +++ b/tools/node_modules/eslint/lib/rules/id-match.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require identifiers to match a specified regular expression", category: "Stylistic Issues", @@ -27,6 +29,12 @@ module.exports = { properties: { properties: { type: "boolean" + }, + onlyDeclarations: { + type: "boolean" + }, + ignoreDestructuring: { + type: "boolean" } } } @@ -36,15 +44,25 @@ module.exports = { create(context) { //-------------------------------------------------------------------------- - // Helpers + // Options //-------------------------------------------------------------------------- - const pattern = context.options[0] || "^.+$", regexp = new RegExp(pattern); const options = context.options[1] || {}, properties = !!options.properties, - onlyDeclarations = !!options.onlyDeclarations; + onlyDeclarations = !!options.onlyDeclarations, + ignoreDestructuring = !!options.ignoreDestructuring; + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + // contains reported nodes to avoid reporting twice on destructuring with shorthand notation + const reported = new Map(); + const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]); + const DECLARATION_TYPES = new Set(["FunctionDeclaration", "VariableDeclarator"]); + const IMPORT_TYPES = new Set(["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"]); /** * Checks if a string matches the provided pattern @@ -56,6 +74,26 @@ module.exports = { return !regexp.test(name); } + /** + * Checks if a parent of a node is an ObjectPattern. + * @param {ASTNode} node The node to check. + * @returns {boolean} if the node is inside an ObjectPattern + * @private + */ + function isInsideObjectPattern(node) { + let { parent } = node; + + while (parent) { + if (parent.type === "ObjectPattern") { + return true; + } + + parent = parent.parent; + } + + return false; + } + /** * Verifies if we should report an error or not based on the effective * parent node and the identifier name. @@ -64,9 +102,8 @@ module.exports = { * @returns {boolean} whether an error should be reported or not */ function shouldReport(effectiveParent, name) { - return effectiveParent.type !== "CallExpression" && - effectiveParent.type !== "NewExpression" && - isInvalid(name); + return (!onlyDeclarations || DECLARATION_TYPES.has(effectiveParent.type)) && + !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && isInvalid(name); } /** @@ -76,14 +113,17 @@ module.exports = { * @private */ function report(node) { - context.report({ - node, - message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.", - data: { - name: node.name, - pattern - } - }); + if (!reported.has(node)) { + context.report({ + node, + message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.", + data: { + name: node.name, + pattern + } + }); + reported.set(node, true); + } } return { @@ -106,36 +146,70 @@ module.exports = { report(node); } - // Report AssignmentExpressions only if they are the left side of the assignment + // Report AssignmentExpressions left side's assigned variable id } else if (effectiveParent.type === "AssignmentExpression" && - (effectiveParent.right.type !== "MemberExpression" || effectiveParent.left.type === "MemberExpression" && - effectiveParent.left.property.name === name)) { + effectiveParent.left.property.name === node.name) { + if (isInvalid(name)) { + report(node); + } + + // Report AssignmentExpressions only if they are the left side of the assignment + } else if (effectiveParent.type === "AssignmentExpression" && effectiveParent.right.type !== "MemberExpression") { if (isInvalid(name)) { report(node); } } - } else if (parent.type === "Property") { + /* + * Properties have their own rules, and + * AssignmentPattern nodes can be treated like Properties: + * e.g.: const { no_camelcased = false } = bar; + */ + } else if (parent.type === "Property" || parent.type === "AssignmentPattern") { + + if (parent.parent && parent.parent.type === "ObjectPattern") { + if (parent.shorthand && parent.value.left && isInvalid(name)) { + + report(node); + } + + const assignmentKeyEqualsValue = parent.key.name === parent.value.name; - if (!properties || parent.key.name !== name) { + // prevent checking righthand side of destructured object + if (!assignmentKeyEqualsValue && parent.key === node) { + return; + } + + const valueIsInvalid = parent.value.name && isInvalid(name); + + // ignore destructuring if the option is set, unless a new identifier is created + if (valueIsInvalid && !(assignmentKeyEqualsValue && ignoreDestructuring)) { + report(node); + } + } + + // never check properties or always ignore destructuring + if (!properties || (ignoreDestructuring && isInsideObjectPattern(node))) { return; } - if (shouldReport(effectiveParent, name)) { + // don't check right hand side of AssignmentExpression to prevent duplicate warnings + if (parent.right !== node && shouldReport(effectiveParent, name)) { report(node); } - } else { - const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator"; + // Check if it's an import specifier + } else if (IMPORT_TYPES.has(parent.type)) { - if (onlyDeclarations && !isDeclaration) { - return; - } - - if (shouldReport(effectiveParent, name)) { + // Report only if the local imported identifier is invalid + if (parent.local && parent.local.name === node.name && isInvalid(name)) { report(node); } + + // Report anything that is invalid that isn't a CallExpression + } else if (shouldReport(effectiveParent, name)) { + report(node); } } diff --git a/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js b/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js index a7ad1122b50544..cd729f8ad931ee 100644 --- a/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js +++ b/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js @@ -9,13 +9,17 @@ //------------------------------------------------------------------------------ module.exports = { meta: { + type: "layout", + docs: { description: "enforce the location of arrow function bodies", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/implicit-arrow-linebreak" }, + fixable: "whitespace", + schema: [ { enum: ["beside", "below"] diff --git a/tools/node_modules/eslint/lib/rules/indent-legacy.js b/tools/node_modules/eslint/lib/rules/indent-legacy.js index e6dc92163b0bbb..16687b521ed31a 100644 --- a/tools/node_modules/eslint/lib/rules/indent-legacy.js +++ b/tools/node_modules/eslint/lib/rules/indent-legacy.js @@ -21,16 +21,19 @@ const astUtils = require("../util/ast-utils"); /* istanbul ignore next: this rule has known coverage issues, but it's deprecated and shouldn't be updated in the future anyway. */ module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent indentation", category: "Stylistic Issues", recommended: false, - replacedBy: ["indent"], url: "https://eslint.org/docs/rules/indent-legacy" }, deprecated: true, + replacedBy: ["indent"], + fixable: "whitespace", schema: [ diff --git a/tools/node_modules/eslint/lib/rules/indent.js b/tools/node_modules/eslint/lib/rules/indent.js index 940c080a0378d4..dc9fbaf908b815 100644 --- a/tools/node_modules/eslint/lib/rules/indent.js +++ b/tools/node_modules/eslint/lib/rules/indent.js @@ -490,6 +490,8 @@ const ELEMENT_LIST_SCHEMA = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent indentation", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/init-declarations.js b/tools/node_modules/eslint/lib/rules/init-declarations.js index 412b96dc0abff9..755090917f909b 100644 --- a/tools/node_modules/eslint/lib/rules/init-declarations.js +++ b/tools/node_modules/eslint/lib/rules/init-declarations.js @@ -44,6 +44,8 @@ function isInitialized(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow initialization in variable declarations", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/jsx-quotes.js b/tools/node_modules/eslint/lib/rules/jsx-quotes.js index 3dd9567d7374e4..603d55330b536c 100644 --- a/tools/node_modules/eslint/lib/rules/jsx-quotes.js +++ b/tools/node_modules/eslint/lib/rules/jsx-quotes.js @@ -38,6 +38,8 @@ const QUOTE_SETTINGS = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce the consistent use of either double or single quotes in JSX attributes", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/key-spacing.js b/tools/node_modules/eslint/lib/rules/key-spacing.js index 75578b2c747c3b..2d1315fde09271 100644 --- a/tools/node_modules/eslint/lib/rules/key-spacing.js +++ b/tools/node_modules/eslint/lib/rules/key-spacing.js @@ -128,6 +128,8 @@ const messages = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing between keys and values in object literal properties", category: "Stylistic Issues", @@ -360,10 +362,9 @@ module.exports = { */ function isKeyValueProperty(property) { return !( - property.method || + (property.method || property.shorthand || - property.kind !== "init" || - property.type !== "Property" // Could be "ExperimentalSpreadProperty" or "SpreadElement" + property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadElement" ); } diff --git a/tools/node_modules/eslint/lib/rules/keyword-spacing.js b/tools/node_modules/eslint/lib/rules/keyword-spacing.js index 2a66779e7aaad1..66ce2cb34c0e2b 100644 --- a/tools/node_modules/eslint/lib/rules/keyword-spacing.js +++ b/tools/node_modules/eslint/lib/rules/keyword-spacing.js @@ -65,6 +65,8 @@ function isCloseParenOfTemplate(token) { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after keywords", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/line-comment-position.js b/tools/node_modules/eslint/lib/rules/line-comment-position.js index 7f45a94b6b5679..7c791d5f2778bd 100644 --- a/tools/node_modules/eslint/lib/rules/line-comment-position.js +++ b/tools/node_modules/eslint/lib/rules/line-comment-position.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce position of line comments", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/linebreak-style.js b/tools/node_modules/eslint/lib/rules/linebreak-style.js index cd432dbcca160c..5345d53f2887f6 100644 --- a/tools/node_modules/eslint/lib/rules/linebreak-style.js +++ b/tools/node_modules/eslint/lib/rules/linebreak-style.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent linebreak style", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/lines-around-comment.js b/tools/node_modules/eslint/lib/rules/lines-around-comment.js index 67fd2032b3ea0d..30175cd3663509 100644 --- a/tools/node_modules/eslint/lib/rules/lines-around-comment.js +++ b/tools/node_modules/eslint/lib/rules/lines-around-comment.js @@ -52,6 +52,8 @@ function getCommentLineNums(comments) { module.exports = { meta: { + type: "layout", + docs: { description: "require empty lines around comments", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/lines-around-directive.js b/tools/node_modules/eslint/lib/rules/lines-around-directive.js index e8d613a41f03af..02bbe13b4fc589 100644 --- a/tools/node_modules/eslint/lib/rules/lines-around-directive.js +++ b/tools/node_modules/eslint/lib/rules/lines-around-directive.js @@ -14,13 +14,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow newlines around directives", category: "Stylistic Issues", recommended: false, - replacedBy: ["padding-line-between-statements"], url: "https://eslint.org/docs/rules/lines-around-directive" }, + schema: [{ oneOf: [ { @@ -41,8 +43,10 @@ module.exports = { } ] }], + fixable: "whitespace", - deprecated: true + deprecated: true, + replacedBy: ["padding-line-between-statements"] }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/lines-between-class-members.js b/tools/node_modules/eslint/lib/rules/lines-between-class-members.js index 8d4e6dd8c18268..5c1e69277a52f3 100644 --- a/tools/node_modules/eslint/lib/rules/lines-between-class-members.js +++ b/tools/node_modules/eslint/lib/rules/lines-between-class-members.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow an empty line between class members", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-classes-per-file.js b/tools/node_modules/eslint/lib/rules/max-classes-per-file.js index bf6b4ba31c6c1e..3193a731c94e33 100644 --- a/tools/node_modules/eslint/lib/rules/max-classes-per-file.js +++ b/tools/node_modules/eslint/lib/rules/max-classes-per-file.js @@ -15,18 +15,22 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of classes per file", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/max-classes-per-file" }, + schema: [ { type: "integer", minimum: 1 } ], + messages: { maximumExceeded: "Number of classes per file must not exceed {{ max }}" } diff --git a/tools/node_modules/eslint/lib/rules/max-depth.js b/tools/node_modules/eslint/lib/rules/max-depth.js index 368dcfa6681a77..34d58b0d31e10e 100644 --- a/tools/node_modules/eslint/lib/rules/max-depth.js +++ b/tools/node_modules/eslint/lib/rules/max-depth.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum depth that blocks can be nested", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-len.js b/tools/node_modules/eslint/lib/rules/max-len.js index 88a388309b2cdf..13dd72160cc879 100644 --- a/tools/node_modules/eslint/lib/rules/max-len.js +++ b/tools/node_modules/eslint/lib/rules/max-len.js @@ -65,6 +65,8 @@ const OPTIONS_OR_INTEGER_SCHEMA = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce a maximum line length", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js index ccf6304e4b27ea..8c64a20bcc34c3 100644 --- a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js +++ b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js @@ -69,6 +69,8 @@ function getCommentLineNumbers(comments) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of line of code in a function", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-lines.js b/tools/node_modules/eslint/lib/rules/max-lines.js index 7eb959795abea7..730e05ab41cf11 100644 --- a/tools/node_modules/eslint/lib/rules/max-lines.js +++ b/tools/node_modules/eslint/lib/rules/max-lines.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of lines per file", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js b/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js index 8cc80ae7aab41a..d4ecb4e2a5c2c3 100644 --- a/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js +++ b/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum depth that callbacks can be nested", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-params.js b/tools/node_modules/eslint/lib/rules/max-params.js index 4089e8ae899359..f678974acf33d2 100644 --- a/tools/node_modules/eslint/lib/rules/max-params.js +++ b/tools/node_modules/eslint/lib/rules/max-params.js @@ -19,6 +19,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of parameters in function definitions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-statements-per-line.js b/tools/node_modules/eslint/lib/rules/max-statements-per-line.js index 566f04ab53b056..f3fb8e9d5cff3c 100644 --- a/tools/node_modules/eslint/lib/rules/max-statements-per-line.js +++ b/tools/node_modules/eslint/lib/rules/max-statements-per-line.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce a maximum number of statements allowed per line", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-statements.js b/tools/node_modules/eslint/lib/rules/max-statements.js index 525790df80623e..e32dedad632f3f 100644 --- a/tools/node_modules/eslint/lib/rules/max-statements.js +++ b/tools/node_modules/eslint/lib/rules/max-statements.js @@ -19,6 +19,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of statements allowed in function blocks", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/multiline-comment-style.js b/tools/node_modules/eslint/lib/rules/multiline-comment-style.js index 5dd39e00a7723a..73eab7c5741bb6 100644 --- a/tools/node_modules/eslint/lib/rules/multiline-comment-style.js +++ b/tools/node_modules/eslint/lib/rules/multiline-comment-style.js @@ -12,12 +12,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a particular style for multiline comments", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/multiline-comment-style" }, + fixable: "whitespace", schema: [{ enum: ["starred-block", "separate-lines", "bare-block"] }] }, diff --git a/tools/node_modules/eslint/lib/rules/multiline-ternary.js b/tools/node_modules/eslint/lib/rules/multiline-ternary.js index 6a22a1113c1580..d1d577a4ffaca1 100644 --- a/tools/node_modules/eslint/lib/rules/multiline-ternary.js +++ b/tools/node_modules/eslint/lib/rules/multiline-ternary.js @@ -13,12 +13,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce newlines between operands of ternary expressions", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/multiline-ternary" }, + schema: [ { enum: ["always", "always-multiline", "never"] diff --git a/tools/node_modules/eslint/lib/rules/new-cap.js b/tools/node_modules/eslint/lib/rules/new-cap.js index cc33e3b8175483..834f4605ed2838 100644 --- a/tools/node_modules/eslint/lib/rules/new-cap.js +++ b/tools/node_modules/eslint/lib/rules/new-cap.js @@ -74,6 +74,8 @@ function calculateCapIsNewExceptions(config) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require constructor names to begin with a capital letter", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/new-parens.js b/tools/node_modules/eslint/lib/rules/new-parens.js index fab302000c9c19..0637a8fbca24c7 100644 --- a/tools/node_modules/eslint/lib/rules/new-parens.js +++ b/tools/node_modules/eslint/lib/rules/new-parens.js @@ -21,6 +21,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require parentheses when invoking a constructor with no arguments", category: "Stylistic Issues", @@ -29,7 +31,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/newline-after-var.js b/tools/node_modules/eslint/lib/rules/newline-after-var.js index 62ccb3db29e97e..83fd420d733234 100644 --- a/tools/node_modules/eslint/lib/rules/newline-after-var.js +++ b/tools/node_modules/eslint/lib/rules/newline-after-var.js @@ -18,11 +18,12 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow an empty line after variable declarations", category: "Stylistic Issues", recommended: false, - replacedBy: ["padding-line-between-statements"], url: "https://eslint.org/docs/rules/newline-after-var" }, @@ -34,7 +35,9 @@ module.exports = { fixable: "whitespace", - deprecated: true + deprecated: true, + + replacedBy: ["padding-line-between-statements"] }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/newline-before-return.js b/tools/node_modules/eslint/lib/rules/newline-before-return.js index 5bc1f7031b057a..2743bf7a8bea34 100644 --- a/tools/node_modules/eslint/lib/rules/newline-before-return.js +++ b/tools/node_modules/eslint/lib/rules/newline-before-return.js @@ -11,16 +11,19 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require an empty line before `return` statements", category: "Stylistic Issues", recommended: false, - replacedBy: ["padding-line-between-statements"], url: "https://eslint.org/docs/rules/newline-before-return" }, + fixable: "whitespace", schema: [], - deprecated: true + deprecated: true, + replacedBy: ["padding-line-between-statements"] }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js b/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js index 2adcdfe45a6009..9d9931376829a6 100644 --- a/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js +++ b/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js @@ -14,13 +14,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require a newline after each call in a method chain", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/newline-per-chained-call" }, + fixable: "whitespace", + schema: [{ type: "object", properties: { diff --git a/tools/node_modules/eslint/lib/rules/no-alert.js b/tools/node_modules/eslint/lib/rules/no-alert.js index 1c08460f340b91..21f10b3c399397 100644 --- a/tools/node_modules/eslint/lib/rules/no-alert.js +++ b/tools/node_modules/eslint/lib/rules/no-alert.js @@ -74,6 +74,8 @@ function isGlobalThisReferenceOrGlobalWindow(scope, node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `alert`, `confirm`, and `prompt`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-array-constructor.js b/tools/node_modules/eslint/lib/rules/no-array-constructor.js index 51676f782119a6..90c6d6bbd59281 100644 --- a/tools/node_modules/eslint/lib/rules/no-array-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-array-constructor.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `Array` constructors", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js b/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js index 55d489eb6dd586..fc65f539a3e6aa 100644 --- a/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js +++ b/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js @@ -10,12 +10,15 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow using an async function as a Promise executor", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/no-async-promise-executor" }, + fixable: null, schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-await-in-loop.js b/tools/node_modules/eslint/lib/rules/no-await-in-loop.js index ef0bda90bf95e5..9ca89866a6e114 100644 --- a/tools/node_modules/eslint/lib/rules/no-await-in-loop.js +++ b/tools/node_modules/eslint/lib/rules/no-await-in-loop.js @@ -55,13 +55,17 @@ function isLooped(node, parent) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow `await` inside of loops", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/no-await-in-loop" }, + schema: [], + messages: { unexpectedAwait: "Unexpected `await` inside a loop." } diff --git a/tools/node_modules/eslint/lib/rules/no-bitwise.js b/tools/node_modules/eslint/lib/rules/no-bitwise.js index 36bbdaf349cfdf..df492937c0b5bb 100644 --- a/tools/node_modules/eslint/lib/rules/no-bitwise.js +++ b/tools/node_modules/eslint/lib/rules/no-bitwise.js @@ -22,6 +22,8 @@ const BITWISE_OPERATORS = [ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow bitwise operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js b/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js index 51f78edb1fee62..bf4c8891ad1adf 100644 --- a/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js @@ -10,13 +10,17 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow use of the `Buffer()` constructor", category: "Node.js and CommonJS", recommended: false, url: "https://eslint.org/docs/rules/no-buffer-constructor" }, + schema: [], + messages: { deprecated: "{{expr}} is deprecated. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead." } diff --git a/tools/node_modules/eslint/lib/rules/no-caller.js b/tools/node_modules/eslint/lib/rules/no-caller.js index 9756b212ffe5f8..1703ad867dc0a6 100644 --- a/tools/node_modules/eslint/lib/rules/no-caller.js +++ b/tools/node_modules/eslint/lib/rules/no-caller.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `arguments.caller` or `arguments.callee`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-case-declarations.js b/tools/node_modules/eslint/lib/rules/no-case-declarations.js index c05795200e6679..1d54e221625e70 100644 --- a/tools/node_modules/eslint/lib/rules/no-case-declarations.js +++ b/tools/node_modules/eslint/lib/rules/no-case-declarations.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow lexical declarations in case clauses", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-catch-shadow.js b/tools/node_modules/eslint/lib/rules/no-catch-shadow.js index f749490f31e463..60a0493b3431a8 100644 --- a/tools/node_modules/eslint/lib/rules/no-catch-shadow.js +++ b/tools/node_modules/eslint/lib/rules/no-catch-shadow.js @@ -18,15 +18,18 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `catch` clause parameters from shadowing variables in the outer scope", category: "Variables", recommended: false, - url: "https://eslint.org/docs/rules/no-catch-shadow", - replacedBy: ["no-shadow"] + url: "https://eslint.org/docs/rules/no-catch-shadow" }, - deprecated: true, + replacedBy: ["no-shadow"], + + deprecated: true, schema: [], messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-class-assign.js b/tools/node_modules/eslint/lib/rules/no-class-assign.js index 9b28d40d4a3801..7bc65df1ba6004 100644 --- a/tools/node_modules/eslint/lib/rules/no-class-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-class-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning class members", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js b/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js index 6903bd06544edd..f5c8d5f417b20a 100644 --- a/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js +++ b/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js @@ -10,14 +10,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow comparing against -0", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/no-compare-neg-zero" }, + fixable: null, schema: [], + messages: { unexpected: "Do not use the '{{operator}}' operator to compare against -0." } diff --git a/tools/node_modules/eslint/lib/rules/no-cond-assign.js b/tools/node_modules/eslint/lib/rules/no-cond-assign.js index caf9563e9521bc..aed3e4a7a9b642 100644 --- a/tools/node_modules/eslint/lib/rules/no-cond-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-cond-assign.js @@ -19,6 +19,8 @@ const NODE_DESCRIPTIONS = { module.exports = { meta: { + type: "problem", + docs: { description: "disallow assignment operators in conditional expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js b/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js index 503174e9a67eeb..f18ec194530c19 100644 --- a/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js +++ b/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js @@ -27,6 +27,8 @@ function isConditional(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow arrow functions where they could be confused with comparisons", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-console.js b/tools/node_modules/eslint/lib/rules/no-console.js index 5fb3a159be82d7..d3a2e34475168f 100644 --- a/tools/node_modules/eslint/lib/rules/no-console.js +++ b/tools/node_modules/eslint/lib/rules/no-console.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `console`", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-const-assign.js b/tools/node_modules/eslint/lib/rules/no-const-assign.js index 3188bd34d3b28d..32f8154cc23eae 100644 --- a/tools/node_modules/eslint/lib/rules/no-const-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-const-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning `const` variables", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-constant-condition.js b/tools/node_modules/eslint/lib/rules/no-constant-condition.js index 48b1fbf689f966..88984c36e7f70f 100644 --- a/tools/node_modules/eslint/lib/rules/no-constant-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-constant-condition.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow constant expressions in conditions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-continue.js b/tools/node_modules/eslint/lib/rules/no-continue.js index 3075b77f9fdebd..96718d17a3db4b 100644 --- a/tools/node_modules/eslint/lib/rules/no-continue.js +++ b/tools/node_modules/eslint/lib/rules/no-continue.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `continue` statements", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-control-regex.js b/tools/node_modules/eslint/lib/rules/no-control-regex.js index 24bb6be6671edd..24e6b197be0b44 100644 --- a/tools/node_modules/eslint/lib/rules/no-control-regex.js +++ b/tools/node_modules/eslint/lib/rules/no-control-regex.js @@ -6,7 +6,7 @@ "use strict"; const RegExpValidator = require("regexpp").RegExpValidator; -const collector = new class { +const collector = new (class { constructor() { this.ecmaVersion = 2018; this._source = ""; @@ -41,7 +41,7 @@ const collector = new class { } return this._controlChars; } -}(); +})(); //------------------------------------------------------------------------------ // Rule Definition @@ -49,6 +49,8 @@ const collector = new class { module.exports = { meta: { + type: "problem", + docs: { description: "disallow control characters in regular expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-debugger.js b/tools/node_modules/eslint/lib/rules/no-debugger.js index 5d63bb7e141e0c..95a28a862151be 100644 --- a/tools/node_modules/eslint/lib/rules/no-debugger.js +++ b/tools/node_modules/eslint/lib/rules/no-debugger.js @@ -11,14 +11,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow the use of `debugger`", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/no-debugger" }, + fixable: null, schema: [], + messages: { unexpected: "Unexpected 'debugger' statement." } diff --git a/tools/node_modules/eslint/lib/rules/no-delete-var.js b/tools/node_modules/eslint/lib/rules/no-delete-var.js index f54a396ec2d552..aeab951d75ff82 100644 --- a/tools/node_modules/eslint/lib/rules/no-delete-var.js +++ b/tools/node_modules/eslint/lib/rules/no-delete-var.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow deleting variables", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-div-regex.js b/tools/node_modules/eslint/lib/rules/no-div-regex.js index c050249fd6ef6c..408e006528b584 100644 --- a/tools/node_modules/eslint/lib/rules/no-div-regex.js +++ b/tools/node_modules/eslint/lib/rules/no-div-regex.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow division operators explicitly at the beginning of regular expressions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-args.js b/tools/node_modules/eslint/lib/rules/no-dupe-args.js index e5a7f4154e72bf..4e42336ae3dc34 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-args.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-args.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate arguments in `function` definitions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js index d0fc35973608df..97f63a2896282b 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate class members", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-keys.js b/tools/node_modules/eslint/lib/rules/no-dupe-keys.js index 31493bd048d0a8..9b9c02f5efc9a1 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-keys.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-keys.js @@ -84,6 +84,8 @@ class ObjectInfo { module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate keys in object literals", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js index 128b1fc1b1cf8e..93c8548f91ad75 100644 --- a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js +++ b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate case labels", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js b/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js index 32071da15fd2cf..1d5bdfdc1a2631 100644 --- a/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js +++ b/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js @@ -101,6 +101,8 @@ function handleExports(context, importsInFile, exportsInFile) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate module imports", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-else-return.js b/tools/node_modules/eslint/lib/rules/no-else-return.js index 1000fa807ac1f2..eebdec76e0e7d4 100644 --- a/tools/node_modules/eslint/lib/rules/no-else-return.js +++ b/tools/node_modules/eslint/lib/rules/no-else-return.js @@ -18,6 +18,8 @@ const FixTracker = require("../util/fix-tracker"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `else` blocks after `return` statements in `if` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-empty-character-class.js b/tools/node_modules/eslint/lib/rules/no-empty-character-class.js index e3f06b069a8661..6d2fb3c50186b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty-character-class.js +++ b/tools/node_modules/eslint/lib/rules/no-empty-character-class.js @@ -29,6 +29,8 @@ const regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+])*\/[gimuys]*$/; module.exports = { meta: { + type: "problem", + docs: { description: "disallow empty character classes in regular expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-empty-function.js b/tools/node_modules/eslint/lib/rules/no-empty-function.js index c8039314ab0075..a443796e4e2861 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty-function.js +++ b/tools/node_modules/eslint/lib/rules/no-empty-function.js @@ -90,6 +90,8 @@ function getKind(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow empty functions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-empty-pattern.js b/tools/node_modules/eslint/lib/rules/no-empty-pattern.js index 939710560fab0a..9f34bfde92e2e9 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty-pattern.js +++ b/tools/node_modules/eslint/lib/rules/no-empty-pattern.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow empty destructuring patterns", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-empty.js b/tools/node_modules/eslint/lib/rules/no-empty.js index 2f4c258a26fd32..9d72969e67eb6f 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty.js +++ b/tools/node_modules/eslint/lib/rules/no-empty.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow empty block statements", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-eq-null.js b/tools/node_modules/eslint/lib/rules/no-eq-null.js index eadd16de37f39c..b8dead96d2514c 100644 --- a/tools/node_modules/eslint/lib/rules/no-eq-null.js +++ b/tools/node_modules/eslint/lib/rules/no-eq-null.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `null` comparisons without type-checking operators", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-eval.js b/tools/node_modules/eslint/lib/rules/no-eval.js index c3ea87d466d7e6..39d91e776e9c79 100644 --- a/tools/node_modules/eslint/lib/rules/no-eval.js +++ b/tools/node_modules/eslint/lib/rules/no-eval.js @@ -76,6 +76,8 @@ function isMember(node, name) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `eval()`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-ex-assign.js b/tools/node_modules/eslint/lib/rules/no-ex-assign.js index 1c7beccf89e08e..4cc179a6e8f00f 100644 --- a/tools/node_modules/eslint/lib/rules/no-ex-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-ex-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning exceptions in `catch` clauses", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-extend-native.js b/tools/node_modules/eslint/lib/rules/no-extend-native.js index a1bf49f1325eff..13895f0d06bb1b 100644 --- a/tools/node_modules/eslint/lib/rules/no-extend-native.js +++ b/tools/node_modules/eslint/lib/rules/no-extend-native.js @@ -24,6 +24,8 @@ const propertyDefinitionMethods = new Set(["defineProperty", "defineProperties"] module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow extending native types", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-extra-bind.js b/tools/node_modules/eslint/lib/rules/no-extra-bind.js index 6d6cad13e97deb..abbe1868e89837 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-bind.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-bind.js @@ -22,6 +22,8 @@ const SIDE_EFFECT_FREE_NODE_TYPES = new Set(["Literal", "Identifier", "ThisExpre module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary calls to `.bind()`", category: "Best Practices", @@ -30,7 +32,6 @@ module.exports = { }, schema: [], - fixable: "code", messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js index 5eac6b53fe4f19..615603177a5a76 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary boolean casts", category: "Possible Errors", @@ -25,7 +27,6 @@ module.exports = { }, schema: [], - fixable: "code", messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-extra-label.js b/tools/node_modules/eslint/lib/rules/no-extra-label.js index 9310e90f71e7a9..f8acf7b2834fde 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-label.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-label.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary labels", category: "Best Practices", @@ -25,7 +27,6 @@ module.exports = { }, schema: [], - fixable: "code", messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-extra-parens.js b/tools/node_modules/eslint/lib/rules/no-extra-parens.js index 47c58946cf18e1..3a21b69580b820 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-parens.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-parens.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils.js"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow unnecessary parentheses", category: "Possible Errors", @@ -382,8 +384,7 @@ module.exports = { * Allow extra parens around a new expression if * there are intervening parentheses. */ - callee.type === "MemberExpression" && - doesMemberExpressionContainCallExpression(callee) + (callee.type === "MemberExpression" && doesMemberExpressionContainCallExpression(callee)) ) ) { report(node.callee); @@ -574,15 +575,13 @@ module.exports = { * If `let` is the only thing on the left side of the loop, it's the loop variable: `for ((let) of foo);` * Removing it will cause a syntax error, because it will be parsed as the start of a VariableDeclarator. */ - firstLeftToken.range[1] === node.left.range[1] || - - /* + (firstLeftToken.range[1] === node.left.range[1] || /* * If `let` is followed by a `[` token, it's a property access on the `let` value: `for ((let[foo]) of bar);` * Removing it will cause the property access to be parsed as a destructuring declaration of `foo` instead. */ astUtils.isOpeningBracketToken( sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken) - ) + )) ) ) { tokensToIgnore.add(firstLeftToken); diff --git a/tools/node_modules/eslint/lib/rules/no-extra-semi.js b/tools/node_modules/eslint/lib/rules/no-extra-semi.js index 4d40b5e1538123..d87a181672f851 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-semi.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-semi.js @@ -18,6 +18,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary semicolons", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-fallthrough.js b/tools/node_modules/eslint/lib/rules/no-fallthrough.js index ce4f91ad9643ce..b7fa221050dd94 100644 --- a/tools/node_modules/eslint/lib/rules/no-fallthrough.js +++ b/tools/node_modules/eslint/lib/rules/no-fallthrough.js @@ -55,6 +55,8 @@ function hasBlankLinesBetween(node, token) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow fallthrough of `case` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-floating-decimal.js b/tools/node_modules/eslint/lib/rules/no-floating-decimal.js index a62846cc10ff95..c835d6a545fa8e 100644 --- a/tools/node_modules/eslint/lib/rules/no-floating-decimal.js +++ b/tools/node_modules/eslint/lib/rules/no-floating-decimal.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow leading or trailing decimal points in numeric literals", category: "Best Practices", @@ -25,7 +27,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-func-assign.js b/tools/node_modules/eslint/lib/rules/no-func-assign.js index 029f6a9d7d15c3..ae96ab01f43057 100644 --- a/tools/node_modules/eslint/lib/rules/no-func-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-func-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning `function` declarations", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-global-assign.js b/tools/node_modules/eslint/lib/rules/no-global-assign.js index 3397bdbe0009fc..73f36b25e4763e 100644 --- a/tools/node_modules/eslint/lib/rules/no-global-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-global-assign.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow assignments to native objects or read-only global variables", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js index 3bfe3f0d3a2c3f..826d9398cab56e 100644 --- a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js +++ b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js @@ -152,6 +152,8 @@ function getNonEmptyOperand(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow shorthand type conversions", category: "Best Practices", @@ -160,6 +162,7 @@ module.exports = { }, fixable: "code", + schema: [{ type: "object", properties: { diff --git a/tools/node_modules/eslint/lib/rules/no-implicit-globals.js b/tools/node_modules/eslint/lib/rules/no-implicit-globals.js index c4717b6a374e86..2eea2b28463250 100644 --- a/tools/node_modules/eslint/lib/rules/no-implicit-globals.js +++ b/tools/node_modules/eslint/lib/rules/no-implicit-globals.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow variable and `function` declarations in the global scope", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-implied-eval.js b/tools/node_modules/eslint/lib/rules/no-implied-eval.js index de294bc8858f94..d31b5dfee8041f 100644 --- a/tools/node_modules/eslint/lib/rules/no-implied-eval.js +++ b/tools/node_modules/eslint/lib/rules/no-implied-eval.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `eval()`-like methods", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-inline-comments.js b/tools/node_modules/eslint/lib/rules/no-inline-comments.js index 2fb21909229c11..c282d16e75411a 100644 --- a/tools/node_modules/eslint/lib/rules/no-inline-comments.js +++ b/tools/node_modules/eslint/lib/rules/no-inline-comments.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow inline comments after code", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js index 032c0a0f096788..60508d3e864eda 100644 --- a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js +++ b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow variable or `function` declarations in nested blocks", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js index 7169e0ca77054c..74659001fdb9ce 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js @@ -19,6 +19,8 @@ const undefined1 = void 0; module.exports = { meta: { + type: "problem", + docs: { description: "disallow invalid regular expression strings in `RegExp` constructors", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-this.js b/tools/node_modules/eslint/lib/rules/no-invalid-this.js index 480deebc14cded..e9be4445260bdb 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-this.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-this.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `this` keywords outside of classes or class-like objects", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js index de6934c635ac33..7920ebdc564857 100644 --- a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js +++ b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js @@ -27,6 +27,8 @@ const LINE_BREAK = astUtils.createGlobalLinebreakMatcher(); module.exports = { meta: { + type: "problem", + docs: { description: "disallow irregular whitespace outside of strings and comments", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-iterator.js b/tools/node_modules/eslint/lib/rules/no-iterator.js index ca12fcda477639..82319a3fb1dfb6 100644 --- a/tools/node_modules/eslint/lib/rules/no-iterator.js +++ b/tools/node_modules/eslint/lib/rules/no-iterator.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of the `__iterator__` property", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-label-var.js b/tools/node_modules/eslint/lib/rules/no-label-var.js index 3f5aba4fc1e326..fdba2defc350c6 100644 --- a/tools/node_modules/eslint/lib/rules/no-label-var.js +++ b/tools/node_modules/eslint/lib/rules/no-label-var.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow labels that share a name with a variable", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-labels.js b/tools/node_modules/eslint/lib/rules/no-labels.js index bd6ec57a350e0f..34db20725b0af3 100644 --- a/tools/node_modules/eslint/lib/rules/no-labels.js +++ b/tools/node_modules/eslint/lib/rules/no-labels.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow labeled statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js index 5e22aacf00f8a6..6b51795863b379 100644 --- a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js +++ b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary nested blocks", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-lonely-if.js b/tools/node_modules/eslint/lib/rules/no-lonely-if.js index 3ecc41e8cf6e22..4bbb5399ff9519 100644 --- a/tools/node_modules/eslint/lib/rules/no-lonely-if.js +++ b/tools/node_modules/eslint/lib/rules/no-lonely-if.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `if` statements as the only statement in `else` blocks", category: "Stylistic Issues", @@ -18,7 +20,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-loop-func.js b/tools/node_modules/eslint/lib/rules/no-loop-func.js index d103cb5335083f..e6063806a5dec2 100644 --- a/tools/node_modules/eslint/lib/rules/no-loop-func.js +++ b/tools/node_modules/eslint/lib/rules/no-loop-func.js @@ -154,6 +154,8 @@ function isSafe(loopNode, reference) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `function` declarations and expressions inside loop statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js index b70ca82675089d..84c08dfb08e717 100644 --- a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js +++ b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow magic numbers", category: "Best Practices", @@ -40,6 +42,7 @@ module.exports = { }, additionalProperties: false }], + messages: { useConst: "Number constants declarations must use 'const'.", noMagic: "No magic number: {{raw}}." diff --git a/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js b/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js index e410efed9c943b..4fa650ed52725a 100644 --- a/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js +++ b/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js @@ -101,13 +101,17 @@ const kinds = Object.keys(hasCharacterSequence); module.exports = { meta: { + type: "problem", + docs: { description: "disallow characters which are made with multiple code points in character class syntax", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/no-misleading-character-class" }, + schema: [], + messages: { surrogatePairWithoutUFlag: "Unexpected surrogate pair in character class. Use 'u' flag.", combiningClass: "Unexpected combined character in character class.", diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js index d4ead20062dda8..22ed65f5b1f0fd 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js @@ -71,12 +71,15 @@ function includesBothInAGroup(groups, left, right) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow mixed binary operators", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/no-mixed-operators" }, + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js index 1058f3a511e120..438ac668a805af 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `require` calls to be mixed with regular variable declarations", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js index 7cb4b4ceeaea38..1fc0b6074b8fd7 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "disallow mixed spaces and tabs for indentation", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-multi-assign.js b/tools/node_modules/eslint/lib/rules/no-multi-assign.js index ca3f778ac6fd87..8524a1a571ef9e 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-assign.js @@ -12,12 +12,15 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow use of chained assignment expressions", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/no-multi-assign" }, + schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js index 41bcd4fb61193f..f1792c31ed7e7e 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow multiple spaces", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-multi-str.js b/tools/node_modules/eslint/lib/rules/no-multi-str.js index ee0aaaa4c0c6e6..844842392df7d3 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-str.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-str.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow multiline strings", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js index a111786a30829f..f945cfeffe2b07 100644 --- a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js +++ b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "disallow multiple empty lines", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-native-reassign.js b/tools/node_modules/eslint/lib/rules/no-native-reassign.js index b1064b0bb36661..9ecfb4da7cbee9 100644 --- a/tools/node_modules/eslint/lib/rules/no-native-reassign.js +++ b/tools/node_modules/eslint/lib/rules/no-native-reassign.js @@ -12,16 +12,19 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow assignments to native objects or read-only global variables", category: "Best Practices", recommended: false, - replacedBy: ["no-global-assign"], url: "https://eslint.org/docs/rules/no-native-reassign" }, deprecated: true, + replacedBy: ["no-global-assign"], + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/no-negated-condition.js b/tools/node_modules/eslint/lib/rules/no-negated-condition.js index 254dcb5c23c7e9..e55a8287487de3 100644 --- a/tools/node_modules/eslint/lib/rules/no-negated-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-negated-condition.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow negated conditions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js b/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js index 7f08814c941ffd..0084ad1570bb00 100644 --- a/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js +++ b/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js @@ -12,15 +12,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow negating the left operand in `in` expressions", category: "Possible Errors", recommended: false, - replacedBy: ["no-unsafe-negation"], url: "https://eslint.org/docs/rules/no-negated-in-lhs" }, - deprecated: true, + replacedBy: ["no-unsafe-negation"], + + deprecated: true, schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js index 15e72f20d1cb7f..87a11e87962a8f 100644 --- a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow nested ternary expressions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-new-func.js b/tools/node_modules/eslint/lib/rules/no-new-func.js index 8ee327baa1c445..23e92f7bf3030c 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-func.js +++ b/tools/node_modules/eslint/lib/rules/no-new-func.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators with the `Function` object", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-new-object.js b/tools/node_modules/eslint/lib/rules/no-new-object.js index 3f68cbc1b51b29..f5cc28664f4e1c 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-object.js +++ b/tools/node_modules/eslint/lib/rules/no-new-object.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `Object` constructors", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-new-require.js b/tools/node_modules/eslint/lib/rules/no-new-require.js index f74daa7569c984..1eae0659430fbd 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-require.js +++ b/tools/node_modules/eslint/lib/rules/no-new-require.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators with calls to `require`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-new-symbol.js b/tools/node_modules/eslint/lib/rules/no-new-symbol.js index a537268e38dc1d..ccf757ed6a0cee 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-symbol.js +++ b/tools/node_modules/eslint/lib/rules/no-new-symbol.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow `new` operators with the `Symbol` object", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js index e8d516212b67aa..ae2aeec0341243 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js +++ b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators with the `String`, `Number`, and `Boolean` objects", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-new.js b/tools/node_modules/eslint/lib/rules/no-new.js index f9121bc18f656a..2e0702597eade3 100644 --- a/tools/node_modules/eslint/lib/rules/no-new.js +++ b/tools/node_modules/eslint/lib/rules/no-new.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators outside of assignments or comparisons", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-obj-calls.js b/tools/node_modules/eslint/lib/rules/no-obj-calls.js index 320343cb2c01e6..92492b7a26ed79 100644 --- a/tools/node_modules/eslint/lib/rules/no-obj-calls.js +++ b/tools/node_modules/eslint/lib/rules/no-obj-calls.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow calling global object properties as functions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-octal-escape.js b/tools/node_modules/eslint/lib/rules/no-octal-escape.js index e9509b87f821ec..fc073b14033410 100644 --- a/tools/node_modules/eslint/lib/rules/no-octal-escape.js +++ b/tools/node_modules/eslint/lib/rules/no-octal-escape.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow octal escape sequences in string literals", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-octal.js b/tools/node_modules/eslint/lib/rules/no-octal.js index d782c23a39b719..db1fa40aa5df0a 100644 --- a/tools/node_modules/eslint/lib/rules/no-octal.js +++ b/tools/node_modules/eslint/lib/rules/no-octal.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow octal literals", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-param-reassign.js b/tools/node_modules/eslint/lib/rules/no-param-reassign.js index be1a559178a973..243bb6412cff22 100644 --- a/tools/node_modules/eslint/lib/rules/no-param-reassign.js +++ b/tools/node_modules/eslint/lib/rules/no-param-reassign.js @@ -12,6 +12,8 @@ const stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Progra module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow reassigning `function` parameters", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-path-concat.js b/tools/node_modules/eslint/lib/rules/no-path-concat.js index 1dee7bda1117a6..dad56a4f56a9d0 100644 --- a/tools/node_modules/eslint/lib/rules/no-path-concat.js +++ b/tools/node_modules/eslint/lib/rules/no-path-concat.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow string concatenation with `__dirname` and `__filename`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-plusplus.js b/tools/node_modules/eslint/lib/rules/no-plusplus.js index f754b3672194cd..4c854de1a06ff7 100644 --- a/tools/node_modules/eslint/lib/rules/no-plusplus.js +++ b/tools/node_modules/eslint/lib/rules/no-plusplus.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the unary operators `++` and `--`", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-process-env.js b/tools/node_modules/eslint/lib/rules/no-process-env.js index 71b27ffd72069b..a66d9709b09b4f 100644 --- a/tools/node_modules/eslint/lib/rules/no-process-env.js +++ b/tools/node_modules/eslint/lib/rules/no-process-env.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `process.env`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-process-exit.js b/tools/node_modules/eslint/lib/rules/no-process-exit.js index 2d22d7fd96a120..fcfc6b2af59d0e 100644 --- a/tools/node_modules/eslint/lib/rules/no-process-exit.js +++ b/tools/node_modules/eslint/lib/rules/no-process-exit.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `process.exit()`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-proto.js b/tools/node_modules/eslint/lib/rules/no-proto.js index e37c6c22e628b8..80b9650941696d 100644 --- a/tools/node_modules/eslint/lib/rules/no-proto.js +++ b/tools/node_modules/eslint/lib/rules/no-proto.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of the `__proto__` property", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js b/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js index f52847f44d4b0e..171395306725eb 100644 --- a/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js +++ b/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow calling some `Object.prototype` methods directly on objects", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-redeclare.js b/tools/node_modules/eslint/lib/rules/no-redeclare.js index 79ab21137ecf93..e88436d7c57b73 100644 --- a/tools/node_modules/eslint/lib/rules/no-redeclare.js +++ b/tools/node_modules/eslint/lib/rules/no-redeclare.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow variable redeclaration", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-regex-spaces.js b/tools/node_modules/eslint/lib/rules/no-regex-spaces.js index 089e06028655ed..d0f7293d20eef1 100644 --- a/tools/node_modules/eslint/lib/rules/no-regex-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-regex-spaces.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow multiple spaces in regular expressions", category: "Possible Errors", @@ -21,7 +23,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js index 72b02c032aa823..1a2629a8ec95e8 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js @@ -17,6 +17,8 @@ const DEFAULT_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'.", module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified global variables", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js index fdebb8ca3ada0c..b8fcca1aaf8b6f 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js @@ -53,6 +53,8 @@ const arrayOfStringsOrObjects = { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified modules when loaded by `import`", category: "ECMAScript 6", @@ -234,31 +236,47 @@ module.exports = { return restrictedPatterns.length > 0 && restrictedPatternsMatcher.ignores(importSource); } - return { - ImportDeclaration(node) { - const importSource = node.source.value.trim(); - const importNames = node.specifiers.reduce((set, specifier) => { - if (specifier.type === "ImportDefaultSpecifier") { - set.add("default"); - } else if (specifier.type === "ImportNamespaceSpecifier") { - set.add("*"); - } else { - set.add(specifier.imported.name); - } - return set; - }, new Set()); - - if (isRestrictedForEverythingImported(importSource, importNames)) { - reportPathForEverythingImported(importSource, node); + /** + * Checks a node to see if any problems should be reported. + * @param {ASTNode} node The node to check. + * @returns {void} + * @private + */ + function checkNode(node) { + const importSource = node.source.value.trim(); + const importNames = node.specifiers ? node.specifiers.reduce((set, specifier) => { + if (specifier.type === "ImportDefaultSpecifier") { + set.add("default"); + } else if (specifier.type === "ImportNamespaceSpecifier") { + set.add("*"); + } else if (specifier.imported) { + set.add(specifier.imported.name); + } else if (specifier.local) { + set.add(specifier.local.name); } + return set; + }, new Set()) : new Set(); - if (isRestrictedPath(importSource, importNames)) { - reportPath(node); - } - if (isRestrictedPattern(importSource)) { - reportPathForPatterns(node); - } + if (isRestrictedForEverythingImported(importSource, importNames)) { + reportPathForEverythingImported(importSource, node); + } + + if (isRestrictedPath(importSource, importNames)) { + reportPath(node); + } + if (isRestrictedPattern(importSource)) { + reportPathForPatterns(node); } + } + + return { + ImportDeclaration: checkNode, + ExportNamedDeclaration(node) { + if (node.source) { + checkNode(node); + } + }, + ExportAllDeclaration: checkNode }; } }; diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-modules.js b/tools/node_modules/eslint/lib/rules/no-restricted-modules.js index d63d2ce4f45881..ef8748a7d04baf 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-modules.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-modules.js @@ -47,6 +47,8 @@ const arrayOfStringsOrObjects = { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified modules when loaded by `require`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-properties.js b/tools/node_modules/eslint/lib/rules/no-restricted-properties.js index c0f1cfb6d3834e..eede6ad1c161dd 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-properties.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-properties.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow certain properties on certain objects", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js index c472d9432e69d7..74eea1478911aa 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified syntax", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-return-assign.js b/tools/node_modules/eslint/lib/rules/no-return-assign.js index 519f9e0d039dac..b3c39ea2b8c4b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-return-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-return-assign.js @@ -22,6 +22,8 @@ const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionE module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow assignment operators in `return` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-return-await.js b/tools/node_modules/eslint/lib/rules/no-return-await.js index 5f531a18310c1b..24cb45ee5a7e52 100644 --- a/tools/node_modules/eslint/lib/rules/no-return-await.js +++ b/tools/node_modules/eslint/lib/rules/no-return-await.js @@ -14,6 +14,8 @@ const message = "Redundant use of `await` on a return value."; module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary `return await`", category: "Best Practices", @@ -22,7 +24,9 @@ module.exports = { url: "https://eslint.org/docs/rules/no-return-await" }, + fixable: null, + schema: [ ] }, diff --git a/tools/node_modules/eslint/lib/rules/no-script-url.js b/tools/node_modules/eslint/lib/rules/no-script-url.js index ba74dafb8e274d..40e9bfe8b27544 100644 --- a/tools/node_modules/eslint/lib/rules/no-script-url.js +++ b/tools/node_modules/eslint/lib/rules/no-script-url.js @@ -13,6 +13,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `javascript:` urls", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-self-assign.js b/tools/node_modules/eslint/lib/rules/no-self-assign.js index 87d1f2ff4f76de..d493855efe9c68 100644 --- a/tools/node_modules/eslint/lib/rules/no-self-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-self-assign.js @@ -165,6 +165,8 @@ function eachSelfAssignment(left, right, props, report) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow assignments where both sides are exactly the same", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-self-compare.js b/tools/node_modules/eslint/lib/rules/no-self-compare.js index 6ebc3870feb6b7..8986240ec5c842 100644 --- a/tools/node_modules/eslint/lib/rules/no-self-compare.js +++ b/tools/node_modules/eslint/lib/rules/no-self-compare.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow comparisons where both sides are exactly the same", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-sequences.js b/tools/node_modules/eslint/lib/rules/no-sequences.js index e74943d81095d4..2570912f348e91 100644 --- a/tools/node_modules/eslint/lib/rules/no-sequences.js +++ b/tools/node_modules/eslint/lib/rules/no-sequences.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow comma operators", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js b/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js index 70052f56f2d2ed..9bdd50868042c3 100644 --- a/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js +++ b/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow identifiers from shadowing restricted names", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-shadow.js b/tools/node_modules/eslint/lib/rules/no-shadow.js index 955fc05e582030..f910230d6a27f3 100644 --- a/tools/node_modules/eslint/lib/rules/no-shadow.js +++ b/tools/node_modules/eslint/lib/rules/no-shadow.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow variable declarations from shadowing variables declared in the outer scope", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-spaced-func.js b/tools/node_modules/eslint/lib/rules/no-spaced-func.js index 42d1e4b243a4d0..8535881f435e48 100644 --- a/tools/node_modules/eslint/lib/rules/no-spaced-func.js +++ b/tools/node_modules/eslint/lib/rules/no-spaced-func.js @@ -12,16 +12,19 @@ module.exports = { meta: { + type: "layout", + docs: { description: "disallow spacing between function identifiers and their applications (deprecated)", category: "Stylistic Issues", recommended: false, - replacedBy: ["func-call-spacing"], url: "https://eslint.org/docs/rules/no-spaced-func" }, deprecated: true, + replacedBy: ["func-call-spacing"], + fixable: "whitespace", schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js b/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js index 1cc6f7ccba9569..985109c36b267d 100644 --- a/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js +++ b/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow sparse arrays", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-sync.js b/tools/node_modules/eslint/lib/rules/no-sync.js index eb7b787d38c35a..a0096e3d04313f 100644 --- a/tools/node_modules/eslint/lib/rules/no-sync.js +++ b/tools/node_modules/eslint/lib/rules/no-sync.js @@ -13,6 +13,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow synchronous methods", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-tabs.js b/tools/node_modules/eslint/lib/rules/no-tabs.js index c22a94da38bee1..0002f5592900c1 100644 --- a/tools/node_modules/eslint/lib/rules/no-tabs.js +++ b/tools/node_modules/eslint/lib/rules/no-tabs.js @@ -18,6 +18,8 @@ const anyNonWhitespaceRegex = /\S/; module.exports = { meta: { + type: "layout", + docs: { description: "disallow all tabs", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js b/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js index ed74fcc6f7f16c..c286ec69000d60 100644 --- a/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js +++ b/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow template literal placeholder syntax in regular strings", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-ternary.js b/tools/node_modules/eslint/lib/rules/no-ternary.js index 4dcc8db069e991..890f2abfa0c59a 100644 --- a/tools/node_modules/eslint/lib/rules/no-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-ternary.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow ternary operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-this-before-super.js b/tools/node_modules/eslint/lib/rules/no-this-before-super.js index 8a489879eddf31..93fb094e9bc139 100644 --- a/tools/node_modules/eslint/lib/rules/no-this-before-super.js +++ b/tools/node_modules/eslint/lib/rules/no-this-before-super.js @@ -36,6 +36,8 @@ function isConstructorFunction(node) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow `this`/`super` before calling `super()` in constructors", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-throw-literal.js b/tools/node_modules/eslint/lib/rules/no-throw-literal.js index 301354b6b2c909..c4a6b86bfb4cc9 100644 --- a/tools/node_modules/eslint/lib/rules/no-throw-literal.js +++ b/tools/node_modules/eslint/lib/rules/no-throw-literal.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow throwing literals as exceptions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js b/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js index cca7af2aac322b..18f0340ef011c7 100644 --- a/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow trailing whitespace at the end of lines", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-undef-init.js b/tools/node_modules/eslint/lib/rules/no-undef-init.js index f00b05d4ff0d2e..67f3944d47e7f4 100644 --- a/tools/node_modules/eslint/lib/rules/no-undef-init.js +++ b/tools/node_modules/eslint/lib/rules/no-undef-init.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow initializing variables to `undefined`", category: "Variables", @@ -21,7 +23,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-undef.js b/tools/node_modules/eslint/lib/rules/no-undef.js index c8347d50d1aa15..f923644eca114e 100644 --- a/tools/node_modules/eslint/lib/rules/no-undef.js +++ b/tools/node_modules/eslint/lib/rules/no-undef.js @@ -25,6 +25,8 @@ function hasTypeOfOperator(node) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow the use of undeclared variables unless mentioned in `/*global */` comments", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-undefined.js b/tools/node_modules/eslint/lib/rules/no-undefined.js index 8491ab5d54035e..b92f6700637c30 100644 --- a/tools/node_modules/eslint/lib/rules/no-undefined.js +++ b/tools/node_modules/eslint/lib/rules/no-undefined.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `undefined` as an identifier", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js b/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js index c76488a94313c4..926803b992d98a 100644 --- a/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js +++ b/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow dangling underscores in identifiers", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js b/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js index 181a00b2d0d4fa..3bed96fc77d069 100644 --- a/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js +++ b/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow confusing multiline expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js b/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js index fecd8ba5cca285..95898c5f19d814 100644 --- a/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js @@ -165,6 +165,8 @@ function updateModifiedFlag(conditions, modifiers) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow unmodified loop conditions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js b/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js index 6b58b018da0ec2..3a7dd5fad7db19 100644 --- a/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js @@ -24,6 +24,8 @@ const OPERATOR_INVERSES = { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow ternary operators when simpler alternatives exist", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-unreachable.js b/tools/node_modules/eslint/lib/rules/no-unreachable.js index 80d246307c31ea..8ea2583f7cb251 100644 --- a/tools/node_modules/eslint/lib/rules/no-unreachable.js +++ b/tools/node_modules/eslint/lib/rules/no-unreachable.js @@ -101,6 +101,8 @@ class ConsecutiveRange { module.exports = { meta: { + type: "problem", + docs: { description: "disallow unreachable code after `return`, `throw`, `continue`, and `break` statements", category: "Possible Errors", @@ -180,7 +182,6 @@ module.exports = { ContinueStatement: reportIfUnreachable, DebuggerStatement: reportIfUnreachable, DoWhileStatement: reportIfUnreachable, - EmptyStatement: reportIfUnreachable, ExpressionStatement: reportIfUnreachable, ForInStatement: reportIfUnreachable, ForOfStatement: reportIfUnreachable, diff --git a/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js b/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js index 1ebdd2e3775da3..ab612ae6526f66 100644 --- a/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js +++ b/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js @@ -20,6 +20,8 @@ const SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaratio module.exports = { meta: { + type: "problem", + docs: { description: "disallow control flow statements in `finally` blocks", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js b/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js index b04f80106c64af..3a0402eb0d5d34 100644 --- a/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js +++ b/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js @@ -41,12 +41,15 @@ function isNegation(node) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow negating the left operand of relational operators", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/no-unsafe-negation" }, + schema: [], fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-unused-expressions.js b/tools/node_modules/eslint/lib/rules/no-unused-expressions.js index fedfac17d1fb15..854298b411978b 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-expressions.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-expressions.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unused expressions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-unused-labels.js b/tools/node_modules/eslint/lib/rules/no-unused-labels.js index 3e1dcb6601fece..c9e097df458ba4 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-labels.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-labels.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unused labels", category: "Best Practices", @@ -19,7 +21,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-unused-vars.js b/tools/node_modules/eslint/lib/rules/no-unused-vars.js index 6f36813aca57a5..e76e3251038c00 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-vars.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-vars.js @@ -18,6 +18,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow unused variables", category: "Variables", @@ -223,6 +225,32 @@ module.exports = { return false; } + /** + * Gets a list of function definitions for a specified variable. + * @param {Variable} variable - eslint-scope variable object. + * @returns {ASTNode[]} Function nodes. + * @private + */ + function getFunctionDefinitions(variable) { + const functionDefinitions = []; + + variable.defs.forEach(def => { + const { type, node } = def; + + // FunctionDeclarations + if (type === "FunctionName") { + functionDefinitions.push(node); + } + + // FunctionExpressions + if (type === "Variable" && node.init && + (node.init.type === "FunctionExpression" || node.init.type === "ArrowFunctionExpression")) { + functionDefinitions.push(node.init); + } + }); + return functionDefinitions; + } + /** * Checks the position of given nodes. * @@ -372,22 +400,18 @@ module.exports = { return ref.isRead() && ( // self update. e.g. `a += 1`, `a++` - ( - parent.type === "AssignmentExpression" && + (// in RHS of an assignment for itself. e.g. `a = a + 1` + (( + parent.type === "AssignmentExpression" && granpa.type === "ExpressionStatement" && parent.left === id - ) || + ) || ( parent.type === "UpdateExpression" && granpa.type === "ExpressionStatement" - ) || - - // in RHS of an assignment for itself. e.g. `a = a + 1` - ( - rhsNode && - isInside(id, rhsNode) && - !isInsideOfStorableFunction(id, rhsNode) - ) + ) || rhsNode && + isInside(id, rhsNode) && + !isInsideOfStorableFunction(id, rhsNode))) ); } @@ -435,7 +459,7 @@ module.exports = { * @private */ function isUsedVariable(variable) { - const functionNodes = variable.defs.filter(def => def.type === "FunctionName").map(def => def.node), + const functionNodes = getFunctionDefinitions(variable), isFunctionDefinition = functionNodes.length > 0; let rhsNode = null; diff --git a/tools/node_modules/eslint/lib/rules/no-use-before-define.js b/tools/node_modules/eslint/lib/rules/no-use-before-define.js index 64d82570279233..500cd3a4103672 100644 --- a/tools/node_modules/eslint/lib/rules/no-use-before-define.js +++ b/tools/node_modules/eslint/lib/rules/no-use-before-define.js @@ -136,6 +136,8 @@ function isInInitializer(variable, reference) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow the use of variables before they are defined", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-call.js b/tools/node_modules/eslint/lib/rules/no-useless-call.js index 0778b374f4f612..74e8bec08bcf3b 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-call.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-call.js @@ -49,6 +49,8 @@ function isValidThisArg(expectedThis, thisArg, sourceCode) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary calls to `.call()` and `.apply()`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js index 189f50853c8dd1..ef1f856f3efc5a 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js @@ -18,6 +18,8 @@ const MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{propert module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary computed property keys in object literals", category: "ECMAScript 6", @@ -26,7 +28,6 @@ module.exports = { }, schema: [], - fixable: "code" }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/no-useless-concat.js b/tools/node_modules/eslint/lib/rules/no-useless-concat.js index e8e36aa1c1a8b2..df310119032979 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-concat.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-concat.js @@ -66,6 +66,8 @@ function getRight(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary concatenation of literals or template literals", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js index 59e40bef8f4b66..c10376450eb5b5 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js @@ -142,6 +142,8 @@ function isRedundantSuperCall(body, ctorParams) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary constructors", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-escape.js b/tools/node_modules/eslint/lib/rules/no-useless-escape.js index 7f4b87ed92cfab..c3c0421cc0c5b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-escape.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-escape.js @@ -79,6 +79,8 @@ function parseRegExp(regExpText) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary escape characters", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-rename.js b/tools/node_modules/eslint/lib/rules/no-useless-rename.js index 83a03deb63022a..337f875b4564d8 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-rename.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-rename.js @@ -11,13 +11,17 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow renaming import, export, and destructured assignments to the same name", category: "ECMAScript 6", recommended: false, url: "https://eslint.org/docs/rules/no-useless-rename" }, + fixable: "code", + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-return.js b/tools/node_modules/eslint/lib/rules/no-useless-return.js index b5b8ebc32a1e85..bb11b4b3619c8e 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-return.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-return.js @@ -66,12 +66,15 @@ function isInFinally(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow redundant return statements", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/no-useless-return" }, + fixable: "code", schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-var.js b/tools/node_modules/eslint/lib/rules/no-var.js index 2c32a023dc9a81..edaed98f62e9d3 100644 --- a/tools/node_modules/eslint/lib/rules/no-var.js +++ b/tools/node_modules/eslint/lib/rules/no-var.js @@ -180,6 +180,8 @@ function hasReferenceInTDZ(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `let` or `const` instead of `var`", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-void.js b/tools/node_modules/eslint/lib/rules/no-void.js index 1d3d887da66873..d2b5d2f9631dff 100644 --- a/tools/node_modules/eslint/lib/rules/no-void.js +++ b/tools/node_modules/eslint/lib/rules/no-void.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `void` operators", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-warning-comments.js b/tools/node_modules/eslint/lib/rules/no-warning-comments.js index 5ff76e3a391138..9ea39b490f824d 100644 --- a/tools/node_modules/eslint/lib/rules/no-warning-comments.js +++ b/tools/node_modules/eslint/lib/rules/no-warning-comments.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified warning terms in comments", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js b/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js index 4b71a9ec17d99c..1ecc51db67c030 100644 --- a/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js +++ b/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow whitespace before properties", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-with.js b/tools/node_modules/eslint/lib/rules/no-with.js index d72dcdfb21e4d6..ecdf22c7d91d6a 100644 --- a/tools/node_modules/eslint/lib/rules/no-with.js +++ b/tools/node_modules/eslint/lib/rules/no-with.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `with` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js b/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js index e447ef886b3c03..01763cea92f381 100644 --- a/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js +++ b/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js @@ -12,13 +12,17 @@ const POSITION_SCHEMA = { enum: ["beside", "below", "any"] }; module.exports = { meta: { + type: "layout", + docs: { description: "enforce the location of single-line statements", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/nonblock-statement-body-position" }, + fixable: "whitespace", + schema: [ POSITION_SCHEMA, { diff --git a/tools/node_modules/eslint/lib/rules/object-curly-newline.js b/tools/node_modules/eslint/lib/rules/object-curly-newline.js index 494e78cff4aacb..c460ea56bc3128 100644 --- a/tools/node_modules/eslint/lib/rules/object-curly-newline.js +++ b/tools/node_modules/eslint/lib/rules/object-curly-newline.js @@ -134,13 +134,17 @@ function areLineBreaksRequired(node, options, first, last) { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent line breaks inside braces", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/object-curly-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ diff --git a/tools/node_modules/eslint/lib/rules/object-curly-spacing.js b/tools/node_modules/eslint/lib/rules/object-curly-spacing.js index e7c847a6a9546e..bde4f14253eeec 100644 --- a/tools/node_modules/eslint/lib/rules/object-curly-spacing.js +++ b/tools/node_modules/eslint/lib/rules/object-curly-spacing.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside braces", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/object-property-newline.js b/tools/node_modules/eslint/lib/rules/object-property-newline.js index 65baf0a95e37a7..3e2c0171577594 100644 --- a/tools/node_modules/eslint/lib/rules/object-property-newline.js +++ b/tools/node_modules/eslint/lib/rules/object-property-newline.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "enforce placing object properties on separate lines", category: "Stylistic Issues", @@ -38,8 +40,7 @@ module.exports = { create(context) { const allowSameLine = context.options[0] && ( - Boolean(context.options[0].allowAllPropertiesOnSameLine) || - Boolean(context.options[0].allowMultiplePropertiesPerLine) // Deprecated + (Boolean(context.options[0].allowAllPropertiesOnSameLine) || Boolean(context.options[0].allowMultiplePropertiesPerLine)) // Deprecated ); const errorMessage = allowSameLine ? "Object properties must go on a new line if they aren't all on the same line." diff --git a/tools/node_modules/eslint/lib/rules/object-shorthand.js b/tools/node_modules/eslint/lib/rules/object-shorthand.js index 21f039f8b6ed3a..ff6a51a4d1762a 100644 --- a/tools/node_modules/eslint/lib/rules/object-shorthand.js +++ b/tools/node_modules/eslint/lib/rules/object-shorthand.js @@ -24,6 +24,8 @@ const astUtils = require("../util/ast-utils"); //------------------------------------------------------------------------------ module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow method and property shorthand syntax for object literals", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js b/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js index e17529b6bed487..e7e40d66c0ced4 100644 --- a/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js +++ b/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow newlines around variable declarations", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/one-var.js b/tools/node_modules/eslint/lib/rules/one-var.js index 3efd0f27f7f301..44f05fb700a0d6 100644 --- a/tools/node_modules/eslint/lib/rules/one-var.js +++ b/tools/node_modules/eslint/lib/rules/one-var.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce variables to be declared either together or separately in functions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/operator-assignment.js b/tools/node_modules/eslint/lib/rules/operator-assignment.js index 8e4b7025edab06..8bb01737dd62cd 100644 --- a/tools/node_modules/eslint/lib/rules/operator-assignment.js +++ b/tools/node_modules/eslint/lib/rules/operator-assignment.js @@ -89,6 +89,8 @@ function canBeFixed(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow assignment operator shorthand where possible", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/operator-linebreak.js b/tools/node_modules/eslint/lib/rules/operator-linebreak.js index be2709a1bdaae6..cd6e996b1b10bd 100644 --- a/tools/node_modules/eslint/lib/rules/operator-linebreak.js +++ b/tools/node_modules/eslint/lib/rules/operator-linebreak.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent linebreak style for operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/padded-blocks.js b/tools/node_modules/eslint/lib/rules/padded-blocks.js index 370d47bccff458..7c0b56ba7f8553 100644 --- a/tools/node_modules/eslint/lib/rules/padded-blocks.js +++ b/tools/node_modules/eslint/lib/rules/padded-blocks.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow padding within blocks", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js b/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js index 4af85fef015aad..3e55a2516d0156 100644 --- a/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js +++ b/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js @@ -400,13 +400,17 @@ const StatementTypes = { module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow padding lines between statements", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/padding-line-between-statements" }, + fixable: "whitespace", + schema: { definitions: { paddingType: { diff --git a/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js b/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js index 1bc140b101bc06..b4bbf33f296ab8 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js +++ b/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js @@ -132,6 +132,8 @@ function hasDuplicateParams(paramsList) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require using arrow functions for callbacks", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/prefer-const.js b/tools/node_modules/eslint/lib/rules/prefer-const.js index 8b3bc5e0e436d3..a40ad353950df0 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-const.js +++ b/tools/node_modules/eslint/lib/rules/prefer-const.js @@ -330,6 +330,8 @@ function findUp(node, type, shouldStop) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `const` declarations for variables that are never reassigned after declared", category: "ECMAScript 6", @@ -357,6 +359,8 @@ module.exports = { const shouldMatchAnyDestructuredVariable = options.destructuring !== "all"; const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true; const variables = []; + let reportCount = 0; + let name = ""; /** * Reports given identifier nodes if all of the nodes should be declared @@ -377,14 +381,41 @@ module.exports = { if (nodes.length && (shouldMatchAnyDestructuredVariable || nodesToReport.length === nodes.length)) { const varDeclParent = findUp(nodes[0], "VariableDeclaration", parentNode => parentNode.type.endsWith("Statement")); - const shouldFix = varDeclParent && + const isVarDecParentNull = varDeclParent === null; + + if (!isVarDecParentNull && varDeclParent.declarations.length > 0) { + const firstDeclaration = varDeclParent.declarations[0]; + + if (firstDeclaration.init) { + const firstDecParent = firstDeclaration.init.parent; + + /* + * First we check the declaration type and then depending on + * if the type is a "VariableDeclarator" or its an "ObjectPattern" + * we compare the name from the first identifier, if the names are different + * we assign the new name and reset the count of reportCount and nodeCount in + * order to check each block for the number of reported errors and base our fix + * based on comparing nodes.length and nodesToReport.length. + */ + + if (firstDecParent.type === "VariableDeclarator") { + + if (firstDecParent.id.name !== name) { + name = firstDecParent.id.name; + reportCount = 0; + } + + if (firstDecParent.id.type === "ObjectPattern") { + if (firstDecParent.init.name !== name) { + name = firstDecParent.init.name; + reportCount = 0; + } + } + } + } + } - /* - * If there are multiple variable declarations, like {let a = 1, b = 2}, then - * do not attempt to fix if one of the declarations should be `const`. It's - * too hard to know how the developer would want to automatically resolve the issue. - */ - varDeclParent.declarations.length === 1 && + let shouldFix = varDeclParent && // Don't do a fix unless the variable is initialized (or it's in a for-in or for-of loop) (varDeclParent.parent.type === "ForInStatement" || varDeclParent.parent.type === "ForOfStatement" || varDeclParent.declarations[0].init) && @@ -396,6 +427,21 @@ module.exports = { */ nodesToReport.length === nodes.length; + if (!isVarDecParentNull && varDeclParent.declarations && varDeclParent.declarations.length !== 1) { + + if (varDeclParent && varDeclParent.declarations && varDeclParent.declarations.length >= 1) { + + /* + * Add nodesToReport.length to a count, then comparing the count to the length + * of the declarations in the current block. + */ + + reportCount += nodesToReport.length; + + shouldFix = shouldFix && (reportCount === varDeclParent.declarations.length); + } + } + nodesToReport.forEach(node => { context.report({ node, diff --git a/tools/node_modules/eslint/lib/rules/prefer-destructuring.js b/tools/node_modules/eslint/lib/rules/prefer-destructuring.js index 112ea64613c6da..119fae560895e7 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-destructuring.js +++ b/tools/node_modules/eslint/lib/rules/prefer-destructuring.js @@ -10,12 +10,15 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require destructuring from arrays and/or objects", category: "ECMAScript 6", recommended: false, url: "https://eslint.org/docs/rules/prefer-destructuring" }, + schema: [ { diff --git a/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js b/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js index 051a91c81cb446..ca7358aa013bda 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js +++ b/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js @@ -38,6 +38,8 @@ function isParseInt(calleeNode) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals", category: "ECMAScript 6", @@ -46,7 +48,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js index 8e54de2496a44f..a8dac696be0b70 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js +++ b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js @@ -212,6 +212,8 @@ function defineFixer(node, sourceCode) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead.", @@ -219,8 +221,10 @@ module.exports = { recommended: false, url: "https://eslint.org/docs/rules/prefer-object-spread" }, + schema: [], fixable: "code", + messages: { useSpreadMessage: "Use an object spread instead of `Object.assign` eg: `{ ...foo }`", useLiteralMessage: "Use an object literal instead of `Object.assign`. eg: `{ foo: bar }`" diff --git a/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js b/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js index e3d298a743caec..0db5ae874cfd9f 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js +++ b/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js @@ -12,13 +12,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require using Error objects as Promise rejection reasons", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/prefer-promise-reject-errors" }, + fixable: null, + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/prefer-reflect.js b/tools/node_modules/eslint/lib/rules/prefer-reflect.js index 765163e0eb3a14..796bbdf05fd446 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-reflect.js +++ b/tools/node_modules/eslint/lib/rules/prefer-reflect.js @@ -11,16 +11,19 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `Reflect` methods where applicable", category: "ECMAScript 6", recommended: false, - replacedBy: [], url: "https://eslint.org/docs/rules/prefer-reflect" }, deprecated: true, + replacedBy: [], + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/prefer-rest-params.js b/tools/node_modules/eslint/lib/rules/prefer-rest-params.js index 133456e4d176cf..95a562c4a2f4de 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-rest-params.js +++ b/tools/node_modules/eslint/lib/rules/prefer-rest-params.js @@ -62,6 +62,8 @@ function isNotNormalMemberAccess(reference) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require rest parameters instead of `arguments`", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/prefer-spread.js b/tools/node_modules/eslint/lib/rules/prefer-spread.js index 9bf69c80f7b900..790fd3b82aab41 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-spread.js +++ b/tools/node_modules/eslint/lib/rules/prefer-spread.js @@ -49,6 +49,8 @@ function isValidThisArg(expectedThis, thisArg, context) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require spread operators instead of `.apply()`", category: "ECMAScript 6", @@ -57,7 +59,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/prefer-template.js b/tools/node_modules/eslint/lib/rules/prefer-template.js index 0471d61caef9f8..386674a92ef9c3 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-template.js +++ b/tools/node_modules/eslint/lib/rules/prefer-template.js @@ -141,6 +141,8 @@ function endsWithTemplateCurly(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require template literals instead of string concatenation", category: "ECMAScript 6", @@ -149,7 +151,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/quote-props.js b/tools/node_modules/eslint/lib/rules/quote-props.js index 36739494da4058..7184bd34d35fd1 100644 --- a/tools/node_modules/eslint/lib/rules/quote-props.js +++ b/tools/node_modules/eslint/lib/rules/quote-props.js @@ -17,6 +17,8 @@ const espree = require("espree"), module.exports = { meta: { + type: "suggestion", + docs: { description: "require quotes around object literal property names", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/quotes.js b/tools/node_modules/eslint/lib/rules/quotes.js index 8dd61c3e3718b6..e0db17fcb7c45f 100644 --- a/tools/node_modules/eslint/lib/rules/quotes.js +++ b/tools/node_modules/eslint/lib/rules/quotes.js @@ -76,6 +76,8 @@ const AVOID_ESCAPE = "avoid-escape"; module.exports = { meta: { + type: "layout", + docs: { description: "enforce the consistent use of either backticks, double, or single quotes", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/radix.js b/tools/node_modules/eslint/lib/rules/radix.js index f71220beb4e5c6..5d3805d0a70679 100644 --- a/tools/node_modules/eslint/lib/rules/radix.js +++ b/tools/node_modules/eslint/lib/rules/radix.js @@ -78,6 +78,8 @@ function isDefaultRadix(radix) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the consistent use of the radix argument when using `parseInt()`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/require-atomic-updates.js b/tools/node_modules/eslint/lib/rules/require-atomic-updates.js index c6cf0d74774002..e8dbe17b88dcd8 100644 --- a/tools/node_modules/eslint/lib/rules/require-atomic-updates.js +++ b/tools/node_modules/eslint/lib/rules/require-atomic-updates.js @@ -12,14 +12,18 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow assignments that can lead to race conditions due to usage of `await` or `yield`", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/require-atomic-updates" }, + fixable: null, schema: [], + messages: { nonAtomicUpdate: "Possible race condition: `{{value}}` might be reassigned based on an outdated value of `{{value}}`." } diff --git a/tools/node_modules/eslint/lib/rules/require-await.js b/tools/node_modules/eslint/lib/rules/require-await.js index de39f372fd62ef..5e614c50251fed 100644 --- a/tools/node_modules/eslint/lib/rules/require-await.js +++ b/tools/node_modules/eslint/lib/rules/require-await.js @@ -31,12 +31,15 @@ function capitalizeFirstLetter(text) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow async functions which have no `await` expression", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/require-await" }, + schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/require-jsdoc.js b/tools/node_modules/eslint/lib/rules/require-jsdoc.js index 91b90b7d10a381..949314993b64fb 100644 --- a/tools/node_modules/eslint/lib/rules/require-jsdoc.js +++ b/tools/node_modules/eslint/lib/rules/require-jsdoc.js @@ -6,6 +6,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require JSDoc comments", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js b/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js index 55ca4ff89a66b6..880405e9a25dbf 100644 --- a/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js +++ b/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js @@ -22,15 +22,19 @@ const { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the use of `u` flag on RegExp", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/require-unicode-regexp" }, + messages: { requireUFlag: "Use the 'u' flag." }, + schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/require-yield.js b/tools/node_modules/eslint/lib/rules/require-yield.js index 83a29876f0912a..7bb7cf9a872bd8 100644 --- a/tools/node_modules/eslint/lib/rules/require-yield.js +++ b/tools/node_modules/eslint/lib/rules/require-yield.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require generator functions to contain `yield`", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js b/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js index e87d881298bac2..04539395ef4ec1 100644 --- a/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js +++ b/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js @@ -11,13 +11,17 @@ module.exports = { meta: { + type: "layout", + docs: { description: "enforce spacing between rest and spread operators and their expressions", category: "ECMAScript 6", recommended: false, url: "https://eslint.org/docs/rules/rest-spread-spacing" }, + fixable: "whitespace", + schema: [ { enum: ["always", "never"] diff --git a/tools/node_modules/eslint/lib/rules/semi-spacing.js b/tools/node_modules/eslint/lib/rules/semi-spacing.js index 75b53055a69bde..56ae687d8560a0 100644 --- a/tools/node_modules/eslint/lib/rules/semi-spacing.js +++ b/tools/node_modules/eslint/lib/rules/semi-spacing.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after semicolons", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/semi-style.js b/tools/node_modules/eslint/lib/rules/semi-style.js index 34899bb5444abc..dd76b68f82beac 100644 --- a/tools/node_modules/eslint/lib/rules/semi-style.js +++ b/tools/node_modules/eslint/lib/rules/semi-style.js @@ -65,12 +65,15 @@ function isLastChild(node) { module.exports = { meta: { + type: "layout", + docs: { description: "enforce location of semicolons", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/semi-style" }, + schema: [{ enum: ["last", "first"] }], fixable: "whitespace" }, diff --git a/tools/node_modules/eslint/lib/rules/semi.js b/tools/node_modules/eslint/lib/rules/semi.js index 129d106414defc..e8f4c959d4c7df 100644 --- a/tools/node_modules/eslint/lib/rules/semi.js +++ b/tools/node_modules/eslint/lib/rules/semi.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow semicolons instead of ASI", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/sort-imports.js b/tools/node_modules/eslint/lib/rules/sort-imports.js index 8735be5d307144..76997cc73d894b 100644 --- a/tools/node_modules/eslint/lib/rules/sort-imports.js +++ b/tools/node_modules/eslint/lib/rules/sort-imports.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce sorted import declarations within modules", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/sort-keys.js b/tools/node_modules/eslint/lib/rules/sort-keys.js index 6e538f73291179..0668e617d3c785 100644 --- a/tools/node_modules/eslint/lib/rules/sort-keys.js +++ b/tools/node_modules/eslint/lib/rules/sort-keys.js @@ -73,12 +73,15 @@ const isValidOrders = { module.exports = { meta: { + type: "suggestion", + docs: { description: "require object keys to be sorted", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/sort-keys" }, + schema: [ { enum: ["asc", "desc"] diff --git a/tools/node_modules/eslint/lib/rules/sort-vars.js b/tools/node_modules/eslint/lib/rules/sort-vars.js index 334deb0657f3ef..b6a2c86779c095 100644 --- a/tools/node_modules/eslint/lib/rules/sort-vars.js +++ b/tools/node_modules/eslint/lib/rules/sort-vars.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require variables within the same declaration block to be sorted", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-before-blocks.js b/tools/node_modules/eslint/lib/rules/space-before-blocks.js index 4f22ae6b65382d..872338effc29b3 100644 --- a/tools/node_modules/eslint/lib/rules/space-before-blocks.js +++ b/tools/node_modules/eslint/lib/rules/space-before-blocks.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before blocks", category: "Stylistic Issues", @@ -32,13 +34,13 @@ module.exports = { type: "object", properties: { keywords: { - enum: ["always", "never"] + enum: ["always", "never", "off"] }, functions: { - enum: ["always", "never"] + enum: ["always", "never", "off"] }, classes: { - enum: ["always", "never"] + enum: ["always", "never", "off"] } }, additionalProperties: false @@ -51,18 +53,27 @@ module.exports = { create(context) { const config = context.options[0], sourceCode = context.getSourceCode(); - let checkFunctions = true, - checkKeywords = true, - checkClasses = true; + let alwaysFunctions = true, + alwaysKeywords = true, + alwaysClasses = true, + neverFunctions = false, + neverKeywords = false, + neverClasses = false; if (typeof config === "object") { - checkFunctions = config.functions !== "never"; - checkKeywords = config.keywords !== "never"; - checkClasses = config.classes !== "never"; + alwaysFunctions = config.functions === "always"; + alwaysKeywords = config.keywords === "always"; + alwaysClasses = config.classes === "always"; + neverFunctions = config.functions === "never"; + neverKeywords = config.keywords === "never"; + neverClasses = config.classes === "never"; } else if (config === "never") { - checkFunctions = false; - checkKeywords = false; - checkClasses = false; + alwaysFunctions = false; + alwaysKeywords = false; + alwaysClasses = false; + neverFunctions = true; + neverKeywords = true; + neverClasses = true; } /** @@ -88,35 +99,35 @@ module.exports = { const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node); const parent = context.getAncestors().pop(); let requireSpace; + let requireNoSpace; if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") { - requireSpace = checkFunctions; + requireSpace = alwaysFunctions; + requireNoSpace = neverFunctions; } else if (node.type === "ClassBody") { - requireSpace = checkClasses; + requireSpace = alwaysClasses; + requireNoSpace = neverClasses; } else { - requireSpace = checkKeywords; + requireSpace = alwaysKeywords; + requireNoSpace = neverKeywords; } - if (requireSpace) { - if (!hasSpace) { - context.report({ - node, - message: "Missing space before opening brace.", - fix(fixer) { - return fixer.insertTextBefore(node, " "); - } - }); - } - } else { - if (hasSpace) { - context.report({ - node, - message: "Unexpected space before opening brace.", - fix(fixer) { - return fixer.removeRange([precedingToken.range[1], node.range[0]]); - } - }); - } + if (requireSpace && !hasSpace) { + context.report({ + node, + message: "Missing space before opening brace.", + fix(fixer) { + return fixer.insertTextBefore(node, " "); + } + }); + } else if (requireNoSpace && hasSpace) { + context.report({ + node, + message: "Unexpected space before opening brace.", + fix(fixer) { + return fixer.removeRange([precedingToken.range[1], node.range[0]]); + } + }); } } } diff --git a/tools/node_modules/eslint/lib/rules/space-before-function-paren.js b/tools/node_modules/eslint/lib/rules/space-before-function-paren.js index 81697d64f1f1f8..64ba72bf9ead29 100644 --- a/tools/node_modules/eslint/lib/rules/space-before-function-paren.js +++ b/tools/node_modules/eslint/lib/rules/space-before-function-paren.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before `function` definition opening parenthesis", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-in-parens.js b/tools/node_modules/eslint/lib/rules/space-in-parens.js index aa1374380342a5..88f4f0b50e150d 100644 --- a/tools/node_modules/eslint/lib/rules/space-in-parens.js +++ b/tools/node_modules/eslint/lib/rules/space-in-parens.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside parentheses", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-infix-ops.js b/tools/node_modules/eslint/lib/rules/space-infix-ops.js index 17b49cc1184ca1..45b76795eae14e 100644 --- a/tools/node_modules/eslint/lib/rules/space-infix-ops.js +++ b/tools/node_modules/eslint/lib/rules/space-infix-ops.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require spacing around infix operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-unary-ops.js b/tools/node_modules/eslint/lib/rules/space-unary-ops.js index 5032b46c3b05c8..b56fa4f2fac396 100644 --- a/tools/node_modules/eslint/lib/rules/space-unary-ops.js +++ b/tools/node_modules/eslint/lib/rules/space-unary-ops.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before or after unary operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/spaced-comment.js b/tools/node_modules/eslint/lib/rules/spaced-comment.js index 6fbe2aac790ff4..d4c86d27cf8fc7 100644 --- a/tools/node_modules/eslint/lib/rules/spaced-comment.js +++ b/tools/node_modules/eslint/lib/rules/spaced-comment.js @@ -151,6 +151,8 @@ function createNeverStylePattern(markers) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce consistent spacing after the `//` or `/*` in a comment", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/strict.js b/tools/node_modules/eslint/lib/rules/strict.js index 8b5757738de09c..bec1baf4653961 100644 --- a/tools/node_modules/eslint/lib/rules/strict.js +++ b/tools/node_modules/eslint/lib/rules/strict.js @@ -80,6 +80,8 @@ function isSimpleParameterList(params) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow strict mode directives", category: "Strict Mode", diff --git a/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js b/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js index 23dfff6133d3a6..e94b3292106ddf 100644 --- a/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js +++ b/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js @@ -17,12 +17,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce spacing around colons of switch statements", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/switch-colon-spacing" }, + schema: [ { type: "object", @@ -33,6 +36,7 @@ module.exports = { additionalProperties: false } ], + fixable: "whitespace" }, diff --git a/tools/node_modules/eslint/lib/rules/symbol-description.js b/tools/node_modules/eslint/lib/rules/symbol-description.js index 271012b5429d48..7bb4e2dec699d4 100644 --- a/tools/node_modules/eslint/lib/rules/symbol-description.js +++ b/tools/node_modules/eslint/lib/rules/symbol-description.js @@ -18,6 +18,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require symbol descriptions", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js index 6702d730cd37e8..ea801cbe5d2ea9 100644 --- a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js +++ b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js @@ -24,6 +24,8 @@ const CLOSE_PAREN = /^\}/; module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing around embedded expressions of template strings", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/template-tag-spacing.js b/tools/node_modules/eslint/lib/rules/template-tag-spacing.js index aee7ac108be16c..f258cde3d88e09 100644 --- a/tools/node_modules/eslint/lib/rules/template-tag-spacing.js +++ b/tools/node_modules/eslint/lib/rules/template-tag-spacing.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing between template tags and their literals", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/unicode-bom.js b/tools/node_modules/eslint/lib/rules/unicode-bom.js index 03b2d5ae68e463..20f48e22b3c6b2 100644 --- a/tools/node_modules/eslint/lib/rules/unicode-bom.js +++ b/tools/node_modules/eslint/lib/rules/unicode-bom.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow Unicode byte order mark (BOM)", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/use-isnan.js b/tools/node_modules/eslint/lib/rules/use-isnan.js index 5bad5b3c6ddb5b..343ca0454441e4 100644 --- a/tools/node_modules/eslint/lib/rules/use-isnan.js +++ b/tools/node_modules/eslint/lib/rules/use-isnan.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "require calls to `isNaN()` when checking for `NaN`", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/valid-jsdoc.js b/tools/node_modules/eslint/lib/rules/valid-jsdoc.js index 42d66a8a79b518..b434491bfad873 100644 --- a/tools/node_modules/eslint/lib/rules/valid-jsdoc.js +++ b/tools/node_modules/eslint/lib/rules/valid-jsdoc.js @@ -16,6 +16,8 @@ const doctrine = require("doctrine"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce valid JSDoc comments", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/valid-typeof.js b/tools/node_modules/eslint/lib/rules/valid-typeof.js index ac4e74f20ba6c5..e3245e8f306ca9 100644 --- a/tools/node_modules/eslint/lib/rules/valid-typeof.js +++ b/tools/node_modules/eslint/lib/rules/valid-typeof.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "enforce comparing `typeof` expressions against valid strings", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/vars-on-top.js b/tools/node_modules/eslint/lib/rules/vars-on-top.js index 0489aa61fcc232..d69c223388f05f 100644 --- a/tools/node_modules/eslint/lib/rules/vars-on-top.js +++ b/tools/node_modules/eslint/lib/rules/vars-on-top.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `var` declarations be placed at the top of their containing scope", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/wrap-iife.js b/tools/node_modules/eslint/lib/rules/wrap-iife.js index d006d30a0042fb..ce272235b4f035 100644 --- a/tools/node_modules/eslint/lib/rules/wrap-iife.js +++ b/tools/node_modules/eslint/lib/rules/wrap-iife.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require parentheses around immediate `function` invocations", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/wrap-regex.js b/tools/node_modules/eslint/lib/rules/wrap-regex.js index 1816e0e9e64e19..4ecbcecbbeb0b3 100644 --- a/tools/node_modules/eslint/lib/rules/wrap-regex.js +++ b/tools/node_modules/eslint/lib/rules/wrap-regex.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require parenthesis around regex literals", category: "Stylistic Issues", @@ -19,8 +21,8 @@ module.exports = { }, schema: [], - fixable: "code", + messages: { requireParens: "Wrap the regexp literal in parens to disambiguate the slash." } diff --git a/tools/node_modules/eslint/lib/rules/yield-star-spacing.js b/tools/node_modules/eslint/lib/rules/yield-star-spacing.js index 33a37f0d991577..e7712a51dbf7e7 100644 --- a/tools/node_modules/eslint/lib/rules/yield-star-spacing.js +++ b/tools/node_modules/eslint/lib/rules/yield-star-spacing.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing around the `*` in `yield*` expressions", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/yoda.js b/tools/node_modules/eslint/lib/rules/yoda.js index 35368dd4df9780..8789c001ef933e 100644 --- a/tools/node_modules/eslint/lib/rules/yoda.js +++ b/tools/node_modules/eslint/lib/rules/yoda.js @@ -152,6 +152,8 @@ function same(a, b) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow \"Yoda\" conditions", category: "Best Practices", diff --git a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js index 922ff0c9fc9c1b..9f2447cff5cb7e 100644 --- a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js +++ b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js @@ -445,6 +445,8 @@ var SCOPE_ASYNC = 4; var SCOPE_GENERATOR = 8; var SCOPE_ARROW = 16; var SCOPE_SIMPLE_CATCH = 32; +var SCOPE_SUPER = 64; +var SCOPE_DIRECT_SUPER = 128; function functionFlags(async, generator) { return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0) @@ -540,7 +542,7 @@ var Parser = function Parser(options, input, startPos) { this.regexpState = null; }; -var prototypeAccessors = { inFunction: { configurable: true },inGenerator: { configurable: true },inAsync: { configurable: true } }; +var prototypeAccessors = { inFunction: { configurable: true },inGenerator: { configurable: true },inAsync: { configurable: true },allowSuper: { configurable: true },allowDirectSuper: { configurable: true } }; Parser.prototype.parse = function parse () { var node = this.options.program || this.startNode(); @@ -551,6 +553,11 @@ Parser.prototype.parse = function parse () { prototypeAccessors.inFunction.get = function () { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }; prototypeAccessors.inGenerator.get = function () { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 }; prototypeAccessors.inAsync.get = function () { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 }; +prototypeAccessors.allowSuper.get = function () { return (this.currentThisScope().flags & SCOPE_SUPER) > 0 }; +prototypeAccessors.allowDirectSuper.get = function () { return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0 }; + +// Switch to a getter for 7.0.0. +Parser.prototype.inNonArrowFunction = function inNonArrowFunction () { return (this.currentThisScope().flags & SCOPE_FUNCTION) > 0 }; Parser.extend = function extend () { var plugins = [], len = arguments.length; @@ -1266,7 +1273,7 @@ pp$1.parseClass = function(node, isStatement) { classBody.body = []; this.expect(types.braceL); while (!this.eat(types.braceR)) { - var element = this$1.parseClassElement(); + var element = this$1.parseClassElement(node.superClass !== null); if (element) { classBody.body.push(element); if (element.type === "MethodDefinition" && element.kind === "constructor") { @@ -1279,7 +1286,7 @@ pp$1.parseClass = function(node, isStatement) { return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") }; -pp$1.parseClassElement = function() { +pp$1.parseClassElement = function(constructorAllowsSuper) { var this$1 = this; if (this.eat(types.semi)) { return null } @@ -1315,16 +1322,18 @@ pp$1.parseClassElement = function() { } if (!method.key) { this.parsePropertyName(method); } var key = method.key; + var allowsDirectSuper = false; if (!method.computed && !method.static && (key.type === "Identifier" && key.name === "constructor" || key.type === "Literal" && key.value === "constructor")) { if (method.kind !== "method") { this.raise(key.start, "Constructor can't have get/set modifier"); } if (isGenerator) { this.raise(key.start, "Constructor can't be a generator"); } if (isAsync) { this.raise(key.start, "Constructor can't be an async method"); } method.kind = "constructor"; + allowsDirectSuper = constructorAllowsSuper; } else if (method.static && key.type === "Identifier" && key.name === "prototype") { this.raise(key.start, "Classes may not have a static property named prototype"); } - this.parseClassMethod(method, isGenerator, isAsync); + this.parseClassMethod(method, isGenerator, isAsync, allowsDirectSuper); if (method.kind === "get" && method.value.params.length !== 0) { this.raiseRecoverable(method.value.start, "getter should have no params"); } if (method.kind === "set" && method.value.params.length !== 1) @@ -1334,8 +1343,8 @@ pp$1.parseClassElement = function() { return method }; -pp$1.parseClassMethod = function(method, isGenerator, isAsync) { - method.value = this.parseMethod(isGenerator, isAsync); +pp$1.parseClassMethod = function(method, isGenerator, isAsync, allowsDirectSuper) { + method.value = this.parseMethod(isGenerator, isAsync, allowsDirectSuper); return this.finishNode(method, "MethodDefinition") }; @@ -2122,13 +2131,19 @@ pp$3.parseSubscripts = function(base, startPos, startLoc, noCalls) { // or `{}`. pp$3.parseExprAtom = function(refDestructuringErrors) { + // If a division operator appears in an expression position, the + // tokenizer got confused, and we force it to read a regexp instead. + if (this.type === types.slash) { this.readRegexp(); } + var node, canBeArrow = this.potentialArrowAt === this.start; switch (this.type) { case types._super: - if (!this.inFunction) - { this.raise(this.start, "'super' outside of function or class"); } + if (!this.allowSuper) + { this.raise(this.start, "'super' keyword outside a method"); } node = this.startNode(); this.next(); + if (this.type === types.parenL && !this.allowDirectSuper) + { this.raise(node.start, "super() call outside constructor of a subclass"); } // The `super` keyword can appear at below: // SuperProperty: // super [ Expression ] @@ -2524,7 +2539,7 @@ pp$3.initFunction = function(node) { // Parse object or class method. -pp$3.parseMethod = function(isGenerator, isAsync) { +pp$3.parseMethod = function(isGenerator, isAsync, allowDirectSuper) { var node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos; this.initFunction(node); @@ -2535,7 +2550,7 @@ pp$3.parseMethod = function(isGenerator, isAsync) { this.yieldPos = 0; this.awaitPos = 0; - this.enterScope(functionFlags(isAsync, node.generator)); + this.enterScope(functionFlags(isAsync, node.generator) | SCOPE_SUPER | (allowDirectSuper ? SCOPE_DIRECT_SUPER : 0)); this.expect(types.parenL); node.params = this.parseBindingList(types.parenR, false, this.options.ecmaVersion >= 8); @@ -2823,12 +2838,14 @@ pp$5.currentVarScope = function() { } }; -pp$5.inNonArrowFunction = function() { +// Could be useful for `this`, `new.target`, `super()`, `super.property`, and `super[property]`. +pp$5.currentThisScope = function() { var this$1 = this; - for (var i = this.scopeStack.length - 1; i >= 0; i--) - { if (this$1.scopeStack[i].flags & SCOPE_FUNCTION && !(this$1.scopeStack[i].flags & SCOPE_ARROW)) { return true } } - return false + for (var i = this.scopeStack.length - 1;; i--) { + var scope = this$1.scopeStack[i]; + if (scope.flags & SCOPE_VAR && !(scope.flags & SCOPE_ARROW)) { return scope } + } }; var Node = function Node(parser, pos, loc) { @@ -2924,7 +2941,7 @@ pp$7.braceIsBlock = function(prevType) { { return true } if (prevType === types.braceL) { return parent === types$1.b_stat } - if (prevType === types._var || prevType === types.name) + if (prevType === types._var || prevType === types._const || prevType === types.name) { return false } return !this.exprAllowed }; @@ -2986,6 +3003,7 @@ types.incDec.updateContext = function() { types._function.updateContext = types._class.updateContext = function(prevType) { if (prevType.beforeExpr && prevType !== types.semi && prevType !== types._else && + !(prevType === types._return && lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) && !((prevType === types.colon || prevType === types.braceL) && this.curContext() === types$1.b_stat)) { this.context.push(types$1.f_expr); } else @@ -5257,7 +5275,7 @@ pp$8.readWord = function() { // // [walk]: util/walk.js -var version = "6.0.2"; +var version = "6.0.4"; // The main exported interface (under `self.acorn` when in the // browser) is a `parse` function that takes a code string and diff --git a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map index 57c8681c2eac8e..9cd41ec074e110 100644 --- a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map +++ b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map @@ -1 +1 @@ -{"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\\u180e\\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","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 // th 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\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 {SCOPE_TOP, SCOPE_FUNCTION, SCOPE_ASYNC, SCOPE_GENERATOR} from \"./scopeflags\"\n\nfunction keywordRegexp(words) {\n return new RegExp(\"^(?:\" + words.replace(/ /g, \"|\") + \")$\")\n}\n\nexport class Parser {\n constructor(options, input, startPos) {\n this.options = options = getOptions(options)\n this.sourceFile = options.sourceFile\n this.keywords = keywordRegexp(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 = keywordRegexp(reserved)\n let reservedStrict = (reserved ? reserved + \" \" : \"\") + reservedWords.strict\n this.reservedWordsStrict = keywordRegexp(reservedStrict)\n this.reservedWordsStrictBind = keywordRegexp(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 = 0\n // Labels in scope.\n this.labels = []\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\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 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}\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 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() {\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 if (nextCh === 91 || nextCh === 123) return true // '{' and '['\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()) {\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 if ((context && (this.strict || context !== \"if\")) && 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)\n if (node.body.type === \"ClassDeclaration\" ||\n node.body.type === \"VariableDeclaration\" && node.body.kind !== \"var\" ||\n node.body.type === \"FunctionDeclaration\" && (this.strict || node.body.generator || node.body.async))\n this.raiseRecoverable(node.body.start, \"Invalid labeled declaration\")\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 this.exitScope()\n node.body = this.parseStatement(\"for\")\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 this.exitScope()\n node.body = this.parseStatement(\"for\")\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 decl.id = this.parseBindingAtom(kind)\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// `isStatement` parameter).\n\npp.parseFunction = function(node, statement, allowExpressionBody, isAsync) {\n this.initFunction(node)\n if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync)\n node.generator = this.eat(tt.star)\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 this.checkLVal(node.id, this.inModule && !this.inFunction ? BIND_LEXICAL : BIND_FUNCTION)\n }\n\n let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos\n this.yieldPos = 0\n this.awaitPos = 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)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\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 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()\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 return this.finishNode(node, isStatement ? \"ClassDeclaration\" : \"ClassExpression\")\n}\n\npp.parseClassElement = function() {\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 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 } 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)\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) {\n method.value = this.parseMethod(isGenerator, isAsync)\n return this.finishNode(method, \"MethodDefinition\")\n}\n\npp.parseClassId = function(node, isStatement) {\n node.id = this.type === tt.name ? this.parseIdent() : isStatement === true ? this.unexpected() : null\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, true)\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 // check for keywords used as local names\n for (let spec of node.specifiers) {\n this.checkUnreserved(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, \"Can not 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)\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, 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()\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 for (let computed;;) {\n if ((computed = this.eat(tt.bracketL)) || 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\n this.yieldPos = 0\n this.awaitPos = 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 this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\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 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 } else {\n return base\n }\n }\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 let node, canBeArrow = this.potentialArrowAt === this.start\n switch (this.type) {\n case tt._super:\n if (!this.inFunction)\n this.raise(this.start, \"'super' outside of function or class\")\n node = this.startNode()\n this.next()\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(this.type !== tt.name)\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()\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 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 this.checkUnreserved(prop.key)\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) {\n let node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos\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.enterScope(functionFlags(isAsync, node.generator))\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)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\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\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\n node.params = this.toAssignableList(params, true)\n this.parseFunctionBody(node, true)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n return this.finishNode(node, \"ArrowFunctionExpression\")\n}\n\n// Parse function body and check parameters.\n\npp.parseFunctionBody = function(node, isArrowFunction) {\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 && 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, \"Can not use 'yield' as identifier inside a generator\")\n if (this.inAsync && name === \"await\")\n this.raiseRecoverable(start, \"Can not 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, \"Can not 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) this.checkUnreserved(node)\n return node\n}\n\n// Parses yield expression inside generator.\n\npp.parseYield = function() {\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()\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_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 }\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\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.var.indexOf(name) > -1\n scope.lexical.push(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 redeclared = scope.lexical.indexOf(name) > -1\n scope.var.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) redeclared = true\n scope.var.push(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.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\npp.inNonArrowFunction = function() {\n for (let i = this.scopeStack.length - 1; i >= 0; i--)\n if (this.scopeStack[i].flags & SCOPE_FUNCTION && !(this.scopeStack[i].flags & SCOPE_ARROW)) return true\n return false\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.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.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","const data = {\n \"$LONE\": [\n \"ASCII\",\n \"ASCII_Hex_Digit\",\n \"AHex\",\n \"Alphabetic\",\n \"Alpha\",\n \"Any\",\n \"Assigned\",\n \"Bidi_Control\",\n \"Bidi_C\",\n \"Bidi_Mirrored\",\n \"Bidi_M\",\n \"Case_Ignorable\",\n \"CI\",\n \"Cased\",\n \"Changes_When_Casefolded\",\n \"CWCF\",\n \"Changes_When_Casemapped\",\n \"CWCM\",\n \"Changes_When_Lowercased\",\n \"CWL\",\n \"Changes_When_NFKC_Casefolded\",\n \"CWKCF\",\n \"Changes_When_Titlecased\",\n \"CWT\",\n \"Changes_When_Uppercased\",\n \"CWU\",\n \"Dash\",\n \"Default_Ignorable_Code_Point\",\n \"DI\",\n \"Deprecated\",\n \"Dep\",\n \"Diacritic\",\n \"Dia\",\n \"Emoji\",\n \"Emoji_Component\",\n \"Emoji_Modifier\",\n \"Emoji_Modifier_Base\",\n \"Emoji_Presentation\",\n \"Extender\",\n \"Ext\",\n \"Grapheme_Base\",\n \"Gr_Base\",\n \"Grapheme_Extend\",\n \"Gr_Ext\",\n \"Hex_Digit\",\n \"Hex\",\n \"IDS_Binary_Operator\",\n \"IDSB\",\n \"IDS_Trinary_Operator\",\n \"IDST\",\n \"ID_Continue\",\n \"IDC\",\n \"ID_Start\",\n \"IDS\",\n \"Ideographic\",\n \"Ideo\",\n \"Join_Control\",\n \"Join_C\",\n \"Logical_Order_Exception\",\n \"LOE\",\n \"Lowercase\",\n \"Lower\",\n \"Math\",\n \"Noncharacter_Code_Point\",\n \"NChar\",\n \"Pattern_Syntax\",\n \"Pat_Syn\",\n \"Pattern_White_Space\",\n \"Pat_WS\",\n \"Quotation_Mark\",\n \"QMark\",\n \"Radical\",\n \"Regional_Indicator\",\n \"RI\",\n \"Sentence_Terminal\",\n \"STerm\",\n \"Soft_Dotted\",\n \"SD\",\n \"Terminal_Punctuation\",\n \"Term\",\n \"Unified_Ideograph\",\n \"UIdeo\",\n \"Uppercase\",\n \"Upper\",\n \"Variation_Selector\",\n \"VS\",\n \"White_Space\",\n \"space\",\n \"XID_Continue\",\n \"XIDC\",\n \"XID_Start\",\n \"XIDS\"\n ],\n \"General_Category\": [\n \"Cased_Letter\",\n \"LC\",\n \"Close_Punctuation\",\n \"Pe\",\n \"Connector_Punctuation\",\n \"Pc\",\n \"Control\",\n \"Cc\",\n \"cntrl\",\n \"Currency_Symbol\",\n \"Sc\",\n \"Dash_Punctuation\",\n \"Pd\",\n \"Decimal_Number\",\n \"Nd\",\n \"digit\",\n \"Enclosing_Mark\",\n \"Me\",\n \"Final_Punctuation\",\n \"Pf\",\n \"Format\",\n \"Cf\",\n \"Initial_Punctuation\",\n \"Pi\",\n \"Letter\",\n \"L\",\n \"Letter_Number\",\n \"Nl\",\n \"Line_Separator\",\n \"Zl\",\n \"Lowercase_Letter\",\n \"Ll\",\n \"Mark\",\n \"M\",\n \"Combining_Mark\",\n \"Math_Symbol\",\n \"Sm\",\n \"Modifier_Letter\",\n \"Lm\",\n \"Modifier_Symbol\",\n \"Sk\",\n \"Nonspacing_Mark\",\n \"Mn\",\n \"Number\",\n \"N\",\n \"Open_Punctuation\",\n \"Ps\",\n \"Other\",\n \"C\",\n \"Other_Letter\",\n \"Lo\",\n \"Other_Number\",\n \"No\",\n \"Other_Punctuation\",\n \"Po\",\n \"Other_Symbol\",\n \"So\",\n \"Paragraph_Separator\",\n \"Zp\",\n \"Private_Use\",\n \"Co\",\n \"Punctuation\",\n \"P\",\n \"punct\",\n \"Separator\",\n \"Z\",\n \"Space_Separator\",\n \"Zs\",\n \"Spacing_Mark\",\n \"Mc\",\n \"Surrogate\",\n \"Cs\",\n \"Symbol\",\n \"S\",\n \"Titlecase_Letter\",\n \"Lt\",\n \"Unassigned\",\n \"Cn\",\n \"Uppercase_Letter\",\n \"Lu\"\n ],\n \"Script\": [\n \"Adlam\",\n \"Adlm\",\n \"Ahom\",\n \"Anatolian_Hieroglyphs\",\n \"Hluw\",\n \"Arabic\",\n \"Arab\",\n \"Armenian\",\n \"Armn\",\n \"Avestan\",\n \"Avst\",\n \"Balinese\",\n \"Bali\",\n \"Bamum\",\n \"Bamu\",\n \"Bassa_Vah\",\n \"Bass\",\n \"Batak\",\n \"Batk\",\n \"Bengali\",\n \"Beng\",\n \"Bhaiksuki\",\n \"Bhks\",\n \"Bopomofo\",\n \"Bopo\",\n \"Brahmi\",\n \"Brah\",\n \"Braille\",\n \"Brai\",\n \"Buginese\",\n \"Bugi\",\n \"Buhid\",\n \"Buhd\",\n \"Canadian_Aboriginal\",\n \"Cans\",\n \"Carian\",\n \"Cari\",\n \"Caucasian_Albanian\",\n \"Aghb\",\n \"Chakma\",\n \"Cakm\",\n \"Cham\",\n \"Cherokee\",\n \"Cher\",\n \"Common\",\n \"Zyyy\",\n \"Coptic\",\n \"Copt\",\n \"Qaac\",\n \"Cuneiform\",\n \"Xsux\",\n \"Cypriot\",\n \"Cprt\",\n \"Cyrillic\",\n \"Cyrl\",\n \"Deseret\",\n \"Dsrt\",\n \"Devanagari\",\n \"Deva\",\n \"Duployan\",\n \"Dupl\",\n \"Egyptian_Hieroglyphs\",\n \"Egyp\",\n \"Elbasan\",\n \"Elba\",\n \"Ethiopic\",\n \"Ethi\",\n \"Georgian\",\n \"Geor\",\n \"Glagolitic\",\n \"Glag\",\n \"Gothic\",\n \"Goth\",\n \"Grantha\",\n \"Gran\",\n \"Greek\",\n \"Grek\",\n \"Gujarati\",\n \"Gujr\",\n \"Gurmukhi\",\n \"Guru\",\n \"Han\",\n \"Hani\",\n \"Hangul\",\n \"Hang\",\n \"Hanunoo\",\n \"Hano\",\n \"Hatran\",\n \"Hatr\",\n \"Hebrew\",\n \"Hebr\",\n \"Hiragana\",\n \"Hira\",\n \"Imperial_Aramaic\",\n \"Armi\",\n \"Inherited\",\n \"Zinh\",\n \"Qaai\",\n \"Inscriptional_Pahlavi\",\n \"Phli\",\n \"Inscriptional_Parthian\",\n \"Prti\",\n \"Javanese\",\n \"Java\",\n \"Kaithi\",\n \"Kthi\",\n \"Kannada\",\n \"Knda\",\n \"Katakana\",\n \"Kana\",\n \"Kayah_Li\",\n \"Kali\",\n \"Kharoshthi\",\n \"Khar\",\n \"Khmer\",\n \"Khmr\",\n \"Khojki\",\n \"Khoj\",\n \"Khudawadi\",\n \"Sind\",\n \"Lao\",\n \"Laoo\",\n \"Latin\",\n \"Latn\",\n \"Lepcha\",\n \"Lepc\",\n \"Limbu\",\n \"Limb\",\n \"Linear_A\",\n \"Lina\",\n \"Linear_B\",\n \"Linb\",\n \"Lisu\",\n \"Lycian\",\n \"Lyci\",\n \"Lydian\",\n \"Lydi\",\n \"Mahajani\",\n \"Mahj\",\n \"Malayalam\",\n \"Mlym\",\n \"Mandaic\",\n \"Mand\",\n \"Manichaean\",\n \"Mani\",\n \"Marchen\",\n \"Marc\",\n \"Masaram_Gondi\",\n \"Gonm\",\n \"Meetei_Mayek\",\n \"Mtei\",\n \"Mende_Kikakui\",\n \"Mend\",\n \"Meroitic_Cursive\",\n \"Merc\",\n \"Meroitic_Hieroglyphs\",\n \"Mero\",\n \"Miao\",\n \"Plrd\",\n \"Modi\",\n \"Mongolian\",\n \"Mong\",\n \"Mro\",\n \"Mroo\",\n \"Multani\",\n \"Mult\",\n \"Myanmar\",\n \"Mymr\",\n \"Nabataean\",\n \"Nbat\",\n \"New_Tai_Lue\",\n \"Talu\",\n \"Newa\",\n \"Nko\",\n \"Nkoo\",\n \"Nushu\",\n \"Nshu\",\n \"Ogham\",\n \"Ogam\",\n \"Ol_Chiki\",\n \"Olck\",\n \"Old_Hungarian\",\n \"Hung\",\n \"Old_Italic\",\n \"Ital\",\n \"Old_North_Arabian\",\n \"Narb\",\n \"Old_Permic\",\n \"Perm\",\n \"Old_Persian\",\n \"Xpeo\",\n \"Old_South_Arabian\",\n \"Sarb\",\n \"Old_Turkic\",\n \"Orkh\",\n \"Oriya\",\n \"Orya\",\n \"Osage\",\n \"Osge\",\n \"Osmanya\",\n \"Osma\",\n \"Pahawh_Hmong\",\n \"Hmng\",\n \"Palmyrene\",\n \"Palm\",\n \"Pau_Cin_Hau\",\n \"Pauc\",\n \"Phags_Pa\",\n \"Phag\",\n \"Phoenician\",\n \"Phnx\",\n \"Psalter_Pahlavi\",\n \"Phlp\",\n \"Rejang\",\n \"Rjng\",\n \"Runic\",\n \"Runr\",\n \"Samaritan\",\n \"Samr\",\n \"Saurashtra\",\n \"Saur\",\n \"Sharada\",\n \"Shrd\",\n \"Shavian\",\n \"Shaw\",\n \"Siddham\",\n \"Sidd\",\n \"SignWriting\",\n \"Sgnw\",\n \"Sinhala\",\n \"Sinh\",\n \"Sora_Sompeng\",\n \"Sora\",\n \"Soyombo\",\n \"Soyo\",\n \"Sundanese\",\n \"Sund\",\n \"Syloti_Nagri\",\n \"Sylo\",\n \"Syriac\",\n \"Syrc\",\n \"Tagalog\",\n \"Tglg\",\n \"Tagbanwa\",\n \"Tagb\",\n \"Tai_Le\",\n \"Tale\",\n \"Tai_Tham\",\n \"Lana\",\n \"Tai_Viet\",\n \"Tavt\",\n \"Takri\",\n \"Takr\",\n \"Tamil\",\n \"Taml\",\n \"Tangut\",\n \"Tang\",\n \"Telugu\",\n \"Telu\",\n \"Thaana\",\n \"Thaa\",\n \"Thai\",\n \"Tibetan\",\n \"Tibt\",\n \"Tifinagh\",\n \"Tfng\",\n \"Tirhuta\",\n \"Tirh\",\n \"Ugaritic\",\n \"Ugar\",\n \"Vai\",\n \"Vaii\",\n \"Warang_Citi\",\n \"Wara\",\n \"Yi\",\n \"Yiii\",\n \"Zanabazar_Square\",\n \"Zanb\"\n ]\n}\nArray.prototype.push.apply(data.$LONE, data.General_Category)\ndata.gc = data.General_Category\ndata.sc = data.Script_Extensions = data.scx = data.Script\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\"\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.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 (!UNICODE_PROPERTY_VALUES.hasOwnProperty(name) || UNICODE_PROPERTY_VALUES[name].indexOf(value) === -1) {\n state.raise(\"Invalid property name\")\n }\n}\npp.regexp_validateUnicodePropertyNameOrValue = function(state, nameOrValue) {\n if (UNICODE_PROPERTY_VALUES.$LONE.indexOf(nameOrValue) === -1) {\n state.raise(\"Invalid property name\")\n }\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\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\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\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 // ` - - - -Implementation of function.prototype.bind - -## Example - -I mainly do this for unit tests I run on phantomjs. -PhantomJS does not have Function.prototype.bind :( - -```js -Function.prototype.bind = require("function-bind") -``` - -## Installation - -`npm install function-bind` - -## Contributors - - - Raynos - -## MIT Licenced - - [travis-svg]: https://travis-ci.org/Raynos/function-bind.svg - [travis-url]: https://travis-ci.org/Raynos/function-bind - [npm-badge-svg]: https://badge.fury.io/js/function-bind.svg - [npm-url]: https://npmjs.org/package/function-bind - [5]: https://coveralls.io/repos/Raynos/function-bind/badge.png - [6]: https://coveralls.io/r/Raynos/function-bind - [7]: https://gemnasium.com/Raynos/function-bind.png - [8]: https://gemnasium.com/Raynos/function-bind - [deps-svg]: https://david-dm.org/Raynos/function-bind.svg - [deps-url]: https://david-dm.org/Raynos/function-bind - [dev-deps-svg]: https://david-dm.org/Raynos/function-bind/dev-status.svg - [dev-deps-url]: https://david-dm.org/Raynos/function-bind#info=devDependencies - [11]: https://ci.testling.com/Raynos/function-bind.png - [12]: https://ci.testling.com/Raynos/function-bind diff --git a/tools/node_modules/eslint/node_modules/function-bind/implementation.js b/tools/node_modules/eslint/node_modules/function-bind/implementation.js deleted file mode 100644 index cc4daec1b080a1..00000000000000 --- a/tools/node_modules/eslint/node_modules/function-bind/implementation.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -/* eslint no-invalid-this: 1 */ - -var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; -var slice = Array.prototype.slice; -var toStr = Object.prototype.toString; -var funcType = '[object Function]'; - -module.exports = function bind(that) { - var target = this; - if (typeof target !== 'function' || toStr.call(target) !== funcType) { - throw new TypeError(ERROR_MESSAGE + target); - } - var args = slice.call(arguments, 1); - - var bound; - var binder = function () { - if (this instanceof bound) { - var result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return this; - } else { - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - } - }; - - var boundLength = Math.max(0, target.length - args.length); - var boundArgs = []; - for (var i = 0; i < boundLength; i++) { - boundArgs.push('$' + i); - } - - bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); - - if (target.prototype) { - var Empty = function Empty() {}; - Empty.prototype = target.prototype; - bound.prototype = new Empty(); - Empty.prototype = null; - } - - return bound; -}; diff --git a/tools/node_modules/eslint/node_modules/function-bind/index.js b/tools/node_modules/eslint/node_modules/function-bind/index.js deleted file mode 100644 index 3bb6b9609889f8..00000000000000 --- a/tools/node_modules/eslint/node_modules/function-bind/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var implementation = require('./implementation'); - -module.exports = Function.prototype.bind || implementation; diff --git a/tools/node_modules/eslint/node_modules/function-bind/package.json b/tools/node_modules/eslint/node_modules/function-bind/package.json deleted file mode 100644 index 6574255758b8bc..00000000000000 --- a/tools/node_modules/eslint/node_modules/function-bind/package.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "author": { - "name": "Raynos", - "email": "raynos2@gmail.com" - }, - "bugs": { - "url": "https://github.com/Raynos/function-bind/issues", - "email": "raynos2@gmail.com" - }, - "bundleDependencies": false, - "contributors": [ - { - "name": "Raynos" - }, - { - "name": "Jordan Harband", - "url": "https://github.com/ljharb" - } - ], - "dependencies": {}, - "deprecated": false, - "description": "Implementation of Function.prototype.bind", - "devDependencies": { - "@ljharb/eslint-config": "^12.2.1", - "covert": "^1.1.0", - "eslint": "^4.5.0", - "jscs": "^3.0.7", - "tape": "^4.8.0" - }, - "homepage": "https://github.com/Raynos/function-bind", - "keywords": [ - "function", - "bind", - "shim", - "es5" - ], - "license": "MIT", - "main": "index", - "name": "function-bind", - "repository": { - "type": "git", - "url": "git://github.com/Raynos/function-bind.git" - }, - "scripts": { - "coverage": "covert test/*.js", - "eslint": "eslint *.js */*.js", - "jscs": "jscs *.js */*.js", - "lint": "npm run jscs && npm run eslint", - "posttest": "npm run coverage -- --quiet", - "pretest": "npm run lint", - "test": "npm run tests-only", - "tests-only": "node test" - }, - "testling": { - "files": "test/index.js", - "browsers": [ - "ie/8..latest", - "firefox/16..latest", - "firefox/nightly", - "chrome/22..latest", - "chrome/canary", - "opera/12..latest", - "opera/next", - "safari/5.1..latest", - "ipad/6.0..latest", - "iphone/6.0..latest", - "android-browser/4.2..latest" - ] - }, - "version": "1.1.1" -} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/globby/index.js b/tools/node_modules/eslint/node_modules/globby/index.js index 39da9f64d1ee42..587a0fdd1cc0fb 100644 --- a/tools/node_modules/eslint/node_modules/globby/index.js +++ b/tools/node_modules/eslint/node_modules/globby/index.js @@ -3,7 +3,6 @@ var Promise = require('pinkie-promise'); var arrayUnion = require('array-union'); var objectAssign = require('object-assign'); var glob = require('glob'); -var arrify = require('arrify'); var pify = require('pify'); var globP = pify(glob, Promise).bind(glob); @@ -12,10 +11,22 @@ function isNegative(pattern) { return pattern[0] === '!'; } +function isString(value) { + return typeof value === 'string'; +} + +function assertPatternsInput(patterns) { + if (!patterns.every(isString)) { + throw new TypeError('patterns must be a string or an array of strings'); + } +} + function generateGlobTasks(patterns, opts) { + patterns = [].concat(patterns); + assertPatternsInput(patterns); + var globTasks = []; - patterns = arrify(patterns); opts = objectAssign({ cache: Object.create(null), statCache: Object.create(null), @@ -45,7 +56,13 @@ function generateGlobTasks(patterns, opts) { } module.exports = function (patterns, opts) { - var globTasks = generateGlobTasks(patterns, opts); + var globTasks; + + try { + globTasks = generateGlobTasks(patterns, opts); + } catch (err) { + return Promise.reject(err); + } return Promise.all(globTasks.map(function (task) { return globP(task.pattern, task.opts); @@ -63,3 +80,9 @@ module.exports.sync = function (patterns, opts) { }; module.exports.generateGlobTasks = generateGlobTasks; + +module.exports.hasMagic = function (patterns, opts) { + return [].concat(patterns).some(function (pattern) { + return glob.hasMagic(pattern, opts); + }); +}; diff --git a/tools/node_modules/eslint/node_modules/globby/node_modules/pify/index.js b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/index.js new file mode 100644 index 00000000000000..7c720ebee88727 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/index.js @@ -0,0 +1,68 @@ +'use strict'; + +var processFn = function (fn, P, opts) { + return function () { + var that = this; + var args = new Array(arguments.length); + + for (var i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; + } + + return new P(function (resolve, reject) { + args.push(function (err, result) { + if (err) { + reject(err); + } else if (opts.multiArgs) { + var results = new Array(arguments.length - 1); + + for (var i = 1; i < arguments.length; i++) { + results[i - 1] = arguments[i]; + } + + resolve(results); + } else { + resolve(result); + } + }); + + fn.apply(that, args); + }); + }; +}; + +var pify = module.exports = function (obj, P, opts) { + if (typeof P !== 'function') { + opts = P; + P = Promise; + } + + opts = opts || {}; + opts.exclude = opts.exclude || [/.+Sync$/]; + + var filter = function (key) { + var match = function (pattern) { + return typeof pattern === 'string' ? key === pattern : pattern.test(key); + }; + + return opts.include ? opts.include.some(match) : !opts.exclude.some(match); + }; + + var ret = typeof obj === 'function' ? function () { + if (opts.excludeMain) { + return obj.apply(this, arguments); + } + + return processFn(obj, P, opts).apply(this, arguments); + } : {}; + + return Object.keys(obj).reduce(function (ret, key) { + var x = obj[key]; + + ret[key] = typeof x === 'function' && filter(key) ? processFn(x, P, opts) : x; + + return ret; + }, ret); +}; + +pify.all = pify; diff --git a/tools/node_modules/eslint/node_modules/arrify/license b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/license similarity index 100% rename from tools/node_modules/eslint/node_modules/arrify/license rename to tools/node_modules/eslint/node_modules/globby/node_modules/pify/license diff --git a/tools/node_modules/eslint/node_modules/globby/node_modules/pify/package.json b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/package.json new file mode 100644 index 00000000000000..40780115cf1d0a --- /dev/null +++ b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/package.json @@ -0,0 +1,57 @@ +{ + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/sindresorhus/pify/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Promisify a callback-style function", + "devDependencies": { + "ava": "*", + "pinkie-promise": "^1.0.0", + "v8-natives": "0.0.2", + "xo": "*" + }, + "engines": { + "node": ">=0.10.0" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/sindresorhus/pify#readme", + "keywords": [ + "promise", + "promises", + "promisify", + "denodify", + "denodeify", + "callback", + "cb", + "node", + "then", + "thenify", + "convert", + "transform", + "wrap", + "wrapper", + "bind", + "to", + "async", + "es2015" + ], + "license": "MIT", + "name": "pify", + "repository": { + "type": "git", + "url": "git+https://github.com/sindresorhus/pify.git" + }, + "scripts": { + "optimization-test": "node --allow-natives-syntax optimization-test.js", + "test": "xo && ava && npm run optimization-test" + }, + "version": "2.3.0" +} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/globby/node_modules/pify/readme.md b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/readme.md new file mode 100644 index 00000000000000..97aeeb628b0897 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/readme.md @@ -0,0 +1,119 @@ +# pify [![Build Status](https://travis-ci.org/sindresorhus/pify.svg?branch=master)](https://travis-ci.org/sindresorhus/pify) + +> Promisify a callback-style function + + +## Install + +``` +$ npm install --save pify +``` + + +## Usage + +```js +const fs = require('fs'); +const pify = require('pify'); + +// promisify a single function + +pify(fs.readFile)('package.json', 'utf8').then(data => { + console.log(JSON.parse(data).name); + //=> 'pify' +}); + +// or promisify all methods in a module + +pify(fs).readFile('package.json', 'utf8').then(data => { + console.log(JSON.parse(data).name); + //=> 'pify' +}); +``` + + +## API + +### pify(input, [promiseModule], [options]) + +Returns a promise wrapped version of the supplied function or module. + +#### input + +Type: `function`, `object` + +Callback-style function or module whose methods you want to promisify. + +#### promiseModule + +Type: `function` + +Custom promise module to use instead of the native one. + +Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill. + +#### options + +##### multiArgs + +Type: `boolean` +Default: `false` + +By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. + +```js +const request = require('request'); +const pify = require('pify'); + +pify(request, {multiArgs: true})('https://sindresorhus.com').then(result => { + const [httpResponse, body] = result; +}); +``` + +##### include + +Type: `array` of (`string`|`regex`) + +Methods in a module to promisify. Remaining methods will be left untouched. + +##### exclude + +Type: `array` of (`string`|`regex`) +Default: `[/.+Sync$/]` + +Methods in a module **not** to promisify. Methods with names ending with `'Sync'` are excluded by default. + +##### excludeMain + +Type: `boolean` +Default: `false` + +By default, if given module is a function itself, this function will be promisified. Turn this option on if you want to promisify only methods of the module. + +```js +const pify = require('pify'); + +function fn() { + return true; +} + +fn.method = (data, callback) => { + setImmediate(() => { + callback(data, null); + }); +}; + +// promisify methods but not fn() +const promiseFn = pify(fn, {excludeMain: true}); + +if (promiseFn()) { + promiseFn.method('hi').then(data => { + console.log(data); + }); +} +``` + + +## License + +MIT © [Sindre Sorhus](http://sindresorhus.com) diff --git a/tools/node_modules/eslint/node_modules/globby/package.json b/tools/node_modules/eslint/node_modules/globby/package.json index 34b15123bb0008..fad7fc179674cb 100644 --- a/tools/node_modules/eslint/node_modules/globby/package.json +++ b/tools/node_modules/eslint/node_modules/globby/package.json @@ -10,7 +10,6 @@ "bundleDependencies": false, "dependencies": { "array-union": "^1.0.1", - "arrify": "^1.0.0", "glob": "^7.0.3", "object-assign": "^4.0.1", "pify": "^2.0.0", @@ -20,11 +19,11 @@ "description": "Extends `glob` with support for multiple patterns and exposes a Promise API", "devDependencies": { "ava": "*", - "glob-stream": "github:wearefractal/glob-stream#master", + "glob-stream": "github:gulpjs/glob-stream#master", "globby": "github:sindresorhus/globby#master", "matcha": "^0.7.0", "rimraf": "^2.2.8", - "xo": "*" + "xo": "^0.16.0" }, "engines": { "node": ">=0.10.0" @@ -72,8 +71,8 @@ "url": "git+https://github.com/sindresorhus/globby.git" }, "scripts": { - "bench": "npm update globby glob-stream && matcha bench.js", + "bench": "npm update glob-stream && matcha bench.js", "test": "xo && ava" }, - "version": "5.0.0" + "version": "6.1.0" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/globby/readme.md b/tools/node_modules/eslint/node_modules/globby/readme.md index aad991d020b1b5..e10a48868f9e29 100644 --- a/tools/node_modules/eslint/node_modules/globby/readme.md +++ b/tools/node_modules/eslint/node_modules/globby/readme.md @@ -42,11 +42,17 @@ Returns an array of matching paths. Returns an array of objects in the format `{ pattern: string, opts: Object }`, which can be passed as arguments to [`node-glob`](https://github.com/isaacs/node-glob). This is useful for other globbing-related packages. -Note that you should avoid running the same tasks multiple times as they contain a file system cache. Instead, create a new tasks list to ensure that file system changes are taken in consideration. +Note that you should avoid running the same tasks multiple times as they contain a file system cache. Instead, run this method each time to ensure file system changes are taken into consideration. + +### globby.hasMagic(patterns, [options]) + +Returns a `boolean` of whether there are any special glob characters in the `patterns`. + +Note that the options affect the results. If `noext: true` is set, then `+(a|b)` will not be considered a magic pattern. If the pattern has a brace expansion, like `a/{b/c,x/y}`, then that is considered magical, unless `nobrace: true` is set. #### patterns -Type: `string`, `Array` +Type: `string` `Array` See supported `minimatch` [patterns](https://github.com/isaacs/minimatch#usage). diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/fs.js b/tools/node_modules/eslint/node_modules/graceful-fs/clone.js similarity index 88% rename from tools/node_modules/eslint/node_modules/graceful-fs/fs.js rename to tools/node_modules/eslint/node_modules/graceful-fs/clone.js index 8ad4a383965b7b..028356c96ed536 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/fs.js +++ b/tools/node_modules/eslint/node_modules/graceful-fs/clone.js @@ -1,8 +1,6 @@ 'use strict' -var fs = require('fs') - -module.exports = clone(fs) +module.exports = clone function clone (obj) { if (obj === null || typeof obj !== 'object') diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js b/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js index 33b30d2e986eba..ac206757e63c5a 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js +++ b/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js @@ -1,6 +1,8 @@ var fs = require('fs') var polyfills = require('./polyfills.js') var legacy = require('./legacy-streams.js') +var clone = require('./clone.js') + var queue = [] var util = require('util') @@ -24,17 +26,17 @@ if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { }) } -module.exports = patch(require('./fs.js')) -if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH) { - module.exports = patch(fs) +module.exports = patch(clone(fs)) +if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { + module.exports = patch(fs) + fs.__patched = true; } // Always patch fs.close/closeSync, because we want to // retry() whenever a close happens *anywhere* in the program. // This is essential when multiple graceful-fs instances are // in play at the same time. -module.exports.close = -fs.close = (function (fs$close) { return function (fd, cb) { +module.exports.close = (function (fs$close) { return function (fd, cb) { return fs$close.call(fs, fd, function (err) { if (!err) retry() @@ -44,8 +46,7 @@ fs.close = (function (fs$close) { return function (fd, cb) { }) }})(fs.close) -module.exports.closeSync = -fs.closeSync = (function (fs$closeSync) { return function (fd) { +module.exports.closeSync = (function (fs$closeSync) { return function (fd) { // Note that graceful-fs also retries when fs.closeSync() fails. // Looks like a bug to me, although it's probably a harmless one. var rval = fs$closeSync.apply(fs, arguments) @@ -53,6 +54,17 @@ fs.closeSync = (function (fs$closeSync) { return function (fd) { return rval }})(fs.closeSync) +// Only patch fs once, otherwise we'll run into a memory leak if +// graceful-fs is loaded multiple times, such as in test environments that +// reset the loaded modules between tests. +// We look for the string `graceful-fs` from the comment above. This +// way we are not adding any extra properties and it will detect if older +// versions of graceful-fs are installed. +if (!/\bgraceful-fs\b/.test(fs.closeSync.toString())) { + fs.closeSync = module.exports.closeSync; + fs.close = module.exports.close; +} + function patch (fs) { // Everything that references the open() function needs to be in here polyfills(fs) @@ -144,6 +156,7 @@ function patch (fs) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$readdir, [args]]) + else { if (typeof cb === 'function') cb.apply(this, arguments) @@ -163,12 +176,16 @@ function patch (fs) { } var fs$ReadStream = fs.ReadStream - ReadStream.prototype = Object.create(fs$ReadStream.prototype) - ReadStream.prototype.open = ReadStream$open + if (fs$ReadStream) { + ReadStream.prototype = Object.create(fs$ReadStream.prototype) + ReadStream.prototype.open = ReadStream$open + } var fs$WriteStream = fs.WriteStream - WriteStream.prototype = Object.create(fs$WriteStream.prototype) - WriteStream.prototype.open = WriteStream$open + if (fs$WriteStream) { + WriteStream.prototype = Object.create(fs$WriteStream.prototype) + WriteStream.prototype.open = WriteStream$open + } fs.ReadStream = ReadStream fs.WriteStream = WriteStream diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/package.json b/tools/node_modules/eslint/node_modules/graceful-fs/package.json index ea35fce0aa2359..b585bfe22fd54f 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/package.json +++ b/tools/node_modules/eslint/node_modules/graceful-fs/package.json @@ -6,21 +6,20 @@ "deprecated": false, "description": "A drop-in replacement for fs, making various improvements.", "devDependencies": { + "import-fresh": "^2.0.0", "mkdirp": "^0.5.0", "rimraf": "^2.2.8", - "tap": "^5.4.2" + "tap": "^12.0.1" }, "directories": { "test": "test" }, - "engines": { - "node": ">=0.4.0" - }, "files": [ "fs.js", "graceful-fs.js", "legacy-streams.js", - "polyfills.js" + "polyfills.js", + "clone.js" ], "homepage": "https://github.com/isaacs/node-graceful-fs#readme", "keywords": [ @@ -47,7 +46,10 @@ "url": "git+https://github.com/isaacs/node-graceful-fs.git" }, "scripts": { + "postpublish": "git push origin --all; git push origin --tags", + "postversion": "npm publish", + "preversion": "npm test", "test": "node test.js | tap -" }, - "version": "4.1.11" + "version": "4.1.15" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js b/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js index 4c6aca78a3dc8b..b964ed0806ceeb 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js +++ b/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js @@ -1,4 +1,3 @@ -var fs = require('./fs.js') var constants = require('constants') var origCwd = process.cwd @@ -145,73 +144,36 @@ function patch (fs) { } } }})(fs.readSync) -} - -function patchLchmod (fs) { - fs.lchmod = function (path, mode, callback) { - fs.open( path - , constants.O_WRONLY | constants.O_SYMLINK - , mode - , function (err, fd) { - if (err) { - if (callback) callback(err) - return - } - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - fs.fchmod(fd, mode, function (err) { - fs.close(fd, function(err2) { - if (callback) callback(err || err2) - }) - }) - }) - } - - fs.lchmodSync = function (path, mode) { - var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) - - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - var threw = true - var ret - try { - ret = fs.fchmodSync(fd, mode) - threw = false - } finally { - if (threw) { - try { - fs.closeSync(fd) - } catch (er) {} - } else { - fs.closeSync(fd) - } - } - return ret - } -} -function patchLutimes (fs) { - if (constants.hasOwnProperty("O_SYMLINK")) { - fs.lutimes = function (path, at, mt, cb) { - fs.open(path, constants.O_SYMLINK, function (er, fd) { - if (er) { - if (cb) cb(er) + function patchLchmod (fs) { + fs.lchmod = function (path, mode, callback) { + fs.open( path + , constants.O_WRONLY | constants.O_SYMLINK + , mode + , function (err, fd) { + if (err) { + if (callback) callback(err) return } - fs.futimes(fd, at, mt, function (er) { - fs.close(fd, function (er2) { - if (cb) cb(er || er2) + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + fs.fchmod(fd, mode, function (err) { + fs.close(fd, function(err2) { + if (callback) callback(err || err2) }) }) }) } - fs.lutimesSync = function (path, at, mt) { - var fd = fs.openSync(path, constants.O_SYMLINK) - var ret + fs.lchmodSync = function (path, mode) { + var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) + + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. var threw = true + var ret try { - ret = fs.futimesSync(fd, at, mt) + ret = fs.fchmodSync(fd, mode) threw = false } finally { if (threw) { @@ -224,107 +186,144 @@ function patchLutimes (fs) { } return ret } + } + + function patchLutimes (fs) { + if (constants.hasOwnProperty("O_SYMLINK")) { + fs.lutimes = function (path, at, mt, cb) { + fs.open(path, constants.O_SYMLINK, function (er, fd) { + if (er) { + if (cb) cb(er) + return + } + fs.futimes(fd, at, mt, function (er) { + fs.close(fd, function (er2) { + if (cb) cb(er || er2) + }) + }) + }) + } + + fs.lutimesSync = function (path, at, mt) { + var fd = fs.openSync(path, constants.O_SYMLINK) + var ret + var threw = true + try { + ret = fs.futimesSync(fd, at, mt) + threw = false + } finally { + if (threw) { + try { + fs.closeSync(fd) + } catch (er) {} + } else { + fs.closeSync(fd) + } + } + return ret + } - } else { - fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } - fs.lutimesSync = function () {} + } else { + fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } + fs.lutimesSync = function () {} + } } -} -function chmodFix (orig) { - if (!orig) return orig - return function (target, mode, cb) { - return orig.call(fs, target, mode, function (er) { - if (chownErOk(er)) er = null - if (cb) cb.apply(this, arguments) - }) + function chmodFix (orig) { + if (!orig) return orig + return function (target, mode, cb) { + return orig.call(fs, target, mode, function (er) { + if (chownErOk(er)) er = null + if (cb) cb.apply(this, arguments) + }) + } } -} -function chmodFixSync (orig) { - if (!orig) return orig - return function (target, mode) { - try { - return orig.call(fs, target, mode) - } catch (er) { - if (!chownErOk(er)) throw er + function chmodFixSync (orig) { + if (!orig) return orig + return function (target, mode) { + try { + return orig.call(fs, target, mode) + } catch (er) { + if (!chownErOk(er)) throw er + } } } -} -function chownFix (orig) { - if (!orig) return orig - return function (target, uid, gid, cb) { - return orig.call(fs, target, uid, gid, function (er) { - if (chownErOk(er)) er = null - if (cb) cb.apply(this, arguments) - }) + function chownFix (orig) { + if (!orig) return orig + return function (target, uid, gid, cb) { + return orig.call(fs, target, uid, gid, function (er) { + if (chownErOk(er)) er = null + if (cb) cb.apply(this, arguments) + }) + } } -} -function chownFixSync (orig) { - if (!orig) return orig - return function (target, uid, gid) { - try { - return orig.call(fs, target, uid, gid) - } catch (er) { - if (!chownErOk(er)) throw er + function chownFixSync (orig) { + if (!orig) return orig + return function (target, uid, gid) { + try { + return orig.call(fs, target, uid, gid) + } catch (er) { + if (!chownErOk(er)) throw er + } } } -} -function statFix (orig) { - if (!orig) return orig - // Older versions of Node erroneously returned signed integers for - // uid + gid. - return function (target, cb) { - return orig.call(fs, target, function (er, stats) { - if (!stats) return cb.apply(this, arguments) + function statFix (orig) { + if (!orig) return orig + // Older versions of Node erroneously returned signed integers for + // uid + gid. + return function (target, cb) { + return orig.call(fs, target, function (er, stats) { + if (!stats) return cb.apply(this, arguments) + if (stats.uid < 0) stats.uid += 0x100000000 + if (stats.gid < 0) stats.gid += 0x100000000 + if (cb) cb.apply(this, arguments) + }) + } + } + + function statFixSync (orig) { + if (!orig) return orig + // Older versions of Node erroneously returned signed integers for + // uid + gid. + return function (target) { + var stats = orig.call(fs, target) if (stats.uid < 0) stats.uid += 0x100000000 if (stats.gid < 0) stats.gid += 0x100000000 - if (cb) cb.apply(this, arguments) - }) + return stats; + } } -} -function statFixSync (orig) { - if (!orig) return orig - // Older versions of Node erroneously returned signed integers for - // uid + gid. - return function (target) { - var stats = orig.call(fs, target) - if (stats.uid < 0) stats.uid += 0x100000000 - if (stats.gid < 0) stats.gid += 0x100000000 - return stats; - } -} + // ENOSYS means that the fs doesn't support the op. Just ignore + // that, because it doesn't matter. + // + // if there's no getuid, or if getuid() is something other + // than 0, and the error is EINVAL or EPERM, then just ignore + // it. + // + // This specific case is a silent failure in cp, install, tar, + // and most other unix tools that manage permissions. + // + // When running as root, or if other types of errors are + // encountered, then it's strict. + function chownErOk (er) { + if (!er) + return true -// ENOSYS means that the fs doesn't support the op. Just ignore -// that, because it doesn't matter. -// -// if there's no getuid, or if getuid() is something other -// than 0, and the error is EINVAL or EPERM, then just ignore -// it. -// -// This specific case is a silent failure in cp, install, tar, -// and most other unix tools that manage permissions. -// -// When running as root, or if other types of errors are -// encountered, then it's strict. -function chownErOk (er) { - if (!er) - return true - - if (er.code === "ENOSYS") - return true - - var nonroot = !process.getuid || process.getuid() !== 0 - if (nonroot) { - if (er.code === "EINVAL" || er.code === "EPERM") + if (er.code === "ENOSYS") return true - } - return false + var nonroot = !process.getuid || process.getuid() !== 0 + if (nonroot) { + if (er.code === "EINVAL" || er.code === "EPERM") + return true + } + + return false + } } diff --git a/tools/node_modules/eslint/node_modules/has/LICENSE-MIT b/tools/node_modules/eslint/node_modules/has/LICENSE-MIT deleted file mode 100644 index ae7014d385df3d..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 Thiago de Arruda - -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/tools/node_modules/eslint/node_modules/has/README.md b/tools/node_modules/eslint/node_modules/has/README.md deleted file mode 100644 index 635e3a4baab00b..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# has - -> Object.prototype.hasOwnProperty.call shortcut - -## Installation - -```sh -npm install --save has -``` - -## Usage - -```js -var has = require('has'); - -has({}, 'hasOwnProperty'); // false -has(Object.prototype, 'hasOwnProperty'); // true -``` diff --git a/tools/node_modules/eslint/node_modules/has/package.json b/tools/node_modules/eslint/node_modules/has/package.json deleted file mode 100644 index 4b061b0e838104..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "author": { - "name": "Thiago de Arruda", - "email": "tpadilha84@gmail.com" - }, - "bugs": { - "url": "https://github.com/tarruda/has/issues" - }, - "bundleDependencies": false, - "contributors": [ - { - "name": "Jordan Harband", - "email": "ljharb@gmail.com", - "url": "http://ljharb.codes" - } - ], - "dependencies": { - "function-bind": "^1.1.1" - }, - "deprecated": false, - "description": "Object.prototype.hasOwnProperty.call shortcut", - "devDependencies": { - "@ljharb/eslint-config": "^12.2.1", - "eslint": "^4.19.1", - "tape": "^4.9.0" - }, - "engines": { - "node": ">= 0.4.0" - }, - "homepage": "https://github.com/tarruda/has", - "license": "MIT", - "licenses": [ - { - "type": "MIT", - "url": "https://github.com/tarruda/has/blob/master/LICENSE-MIT" - } - ], - "main": "./src", - "name": "has", - "repository": { - "type": "git", - "url": "git://github.com/tarruda/has.git" - }, - "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", - "test": "tape test" - }, - "version": "1.0.3" -} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/has/src/index.js b/tools/node_modules/eslint/node_modules/has/src/index.js deleted file mode 100644 index dd92dd9094edb0..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var bind = require('function-bind'); - -module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty); diff --git a/tools/node_modules/eslint/node_modules/p-map/index.js b/tools/node_modules/eslint/node_modules/p-map/index.js new file mode 100644 index 00000000000000..f91477e1f5b3f3 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/index.js @@ -0,0 +1,67 @@ +'use strict'; +module.exports = (iterable, mapper, opts) => new Promise((resolve, reject) => { + opts = Object.assign({ + concurrency: Infinity + }, opts); + + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } + + const concurrency = opts.concurrency; + + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } + + const ret = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let iterableDone = false; + let resolvingCount = 0; + let currentIdx = 0; + + const next = () => { + if (isRejected) { + return; + } + + const nextItem = iterator.next(); + const i = currentIdx; + currentIdx++; + + if (nextItem.done) { + iterableDone = true; + + if (resolvingCount === 0) { + resolve(ret); + } + + return; + } + + resolvingCount++; + + Promise.resolve(nextItem.value) + .then(el => mapper(el, i)) + .then( + val => { + ret[i] = val; + resolvingCount--; + next(); + }, + err => { + isRejected = true; + reject(err); + } + ); + }; + + for (let i = 0; i < concurrency; i++) { + next(); + + if (iterableDone) { + break; + } + } +}); diff --git a/tools/node_modules/eslint/node_modules/p-map/license b/tools/node_modules/eslint/node_modules/p-map/license new file mode 100644 index 00000000000000..e7af2f77107d73 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +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/tools/node_modules/eslint/node_modules/p-map/package.json b/tools/node_modules/eslint/node_modules/p-map/package.json new file mode 100644 index 00000000000000..455e05c8bf2ebf --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/package.json @@ -0,0 +1,56 @@ +{ + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/sindresorhus/p-map/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Map over promises concurrently", + "devDependencies": { + "ava": "*", + "delay": "^2.0.0", + "in-range": "^1.0.0", + "random-int": "^1.0.0", + "time-span": "^2.0.0", + "xo": "*" + }, + "engines": { + "node": ">=4" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/sindresorhus/p-map#readme", + "keywords": [ + "promise", + "map", + "resolved", + "wait", + "collection", + "iterable", + "iterator", + "race", + "fulfilled", + "async", + "await", + "promises", + "concurrently", + "concurrency", + "parallel", + "bluebird" + ], + "license": "MIT", + "name": "p-map", + "repository": { + "type": "git", + "url": "git+https://github.com/sindresorhus/p-map.git" + }, + "scripts": { + "test": "xo && ava" + }, + "version": "1.2.0" +} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/p-map/readme.md b/tools/node_modules/eslint/node_modules/p-map/readme.md new file mode 100644 index 00000000000000..7727581a0e578c --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/readme.md @@ -0,0 +1,81 @@ +# p-map [![Build Status](https://travis-ci.org/sindresorhus/p-map.svg?branch=master)](https://travis-ci.org/sindresorhus/p-map) + +> Map over promises concurrently + +Useful when you need to run promise-returning & async functions multiple times with different inputs concurrently. + + +## Install + +``` +$ npm install p-map +``` + + +## Usage + +```js +const pMap = require('p-map'); +const got = require('got'); + +const sites = [ + getWebsiteFromUsername('sindresorhus'), //=> Promise + 'ava.li', + 'todomvc.com', + 'github.com' +]; + +const mapper = el => got.head(el).then(res => res.requestUrl); + +pMap(sites, mapper, {concurrency: 2}).then(result => { + console.log(result); + //=> ['http://sindresorhus.com/', 'http://ava.li/', 'http://todomvc.com/', 'http://github.com/'] +}); +``` + + +## API + +### pMap(input, mapper, [options]) + +Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled, or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned from `mapper` in `input` order. + +#### input + +Type: `Iterable` + +Iterated over concurrently in the `mapper` function. + +#### mapper(element, index) + +Type: `Function` + +Expected to return a `Promise` or value. + +#### options + +Type: `Object` + +##### concurrency + +Type: `number`
+Default: `Infinity`
+Minimum: `1` + +Number of concurrently pending promises returned by `mapper`. + + +## Related + +- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency +- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently +- [p-times](https://github.com/sindresorhus/p-times) - Run promise-returning & async functions a specific number of times concurrently +- [p-props](https://github.com/sindresorhus/p-props) - Like `Promise.all()` but for `Map` and `Object` +- [p-map-series](https://github.com/sindresorhus/p-map-series) - Map over promises serially +- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control +- [More…](https://github.com/sindresorhus/promise-fun) + + +## License + +MIT © [Sindre Sorhus](https://sindresorhus.com) diff --git a/tools/node_modules/eslint/node_modules/pify/index.js b/tools/node_modules/eslint/node_modules/pify/index.js index 7c720ebee88727..1dee43ad08f62b 100644 --- a/tools/node_modules/eslint/node_modules/pify/index.js +++ b/tools/node_modules/eslint/node_modules/pify/index.js @@ -1,68 +1,84 @@ 'use strict'; -var processFn = function (fn, P, opts) { - return function () { - var that = this; - var args = new Array(arguments.length); +const processFn = (fn, opts) => function () { + const P = opts.promiseModule; + const args = new Array(arguments.length); - for (var i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } + for (let i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; + } - return new P(function (resolve, reject) { + return new P((resolve, reject) => { + if (opts.errorFirst) { args.push(function (err, result) { - if (err) { - reject(err); - } else if (opts.multiArgs) { - var results = new Array(arguments.length - 1); + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); - for (var i = 1; i < arguments.length; i++) { + for (let i = 1; i < arguments.length; i++) { results[i - 1] = arguments[i]; } - resolve(results); + if (err) { + results.unshift(err); + reject(results); + } else { + resolve(results); + } + } else if (err) { + reject(err); } else { resolve(result); } }); + } else { + args.push(function (result) { + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); - fn.apply(that, args); - }); - }; -}; + for (let i = 0; i < arguments.length; i++) { + results[i] = arguments[i]; + } -var pify = module.exports = function (obj, P, opts) { - if (typeof P !== 'function') { - opts = P; - P = Promise; - } + resolve(results); + } else { + resolve(result); + } + }); + } - opts = opts || {}; - opts.exclude = opts.exclude || [/.+Sync$/]; + fn.apply(this, args); + }); +}; - var filter = function (key) { - var match = function (pattern) { - return typeof pattern === 'string' ? key === pattern : pattern.test(key); - }; +module.exports = (obj, opts) => { + opts = Object.assign({ + exclude: [/.+(Sync|Stream)$/], + errorFirst: true, + promiseModule: Promise + }, opts); + const filter = key => { + const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); return opts.include ? opts.include.some(match) : !opts.exclude.some(match); }; - var ret = typeof obj === 'function' ? function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, P, opts).apply(this, arguments); - } : {}; + let ret; + if (typeof obj === 'function') { + ret = function () { + if (opts.excludeMain) { + return obj.apply(this, arguments); + } - return Object.keys(obj).reduce(function (ret, key) { - var x = obj[key]; + return processFn(obj, opts).apply(this, arguments); + }; + } else { + ret = Object.create(Object.getPrototypeOf(obj)); + } - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, P, opts) : x; + for (const key in obj) { // eslint-disable-line guard-for-in + const x = obj[key]; + ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; + } - return ret; - }, ret); + return ret; }; - -pify.all = pify; diff --git a/tools/node_modules/eslint/node_modules/pify/license b/tools/node_modules/eslint/node_modules/pify/license index 654d0bfe943437..e7af2f77107d73 100644 --- a/tools/node_modules/eslint/node_modules/pify/license +++ b/tools/node_modules/eslint/node_modules/pify/license @@ -1,21 +1,9 @@ -The MIT License (MIT) +MIT License Copyright (c) Sindre Sorhus (sindresorhus.com) -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: +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 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. +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/tools/node_modules/eslint/node_modules/pify/package.json b/tools/node_modules/eslint/node_modules/pify/package.json index 40780115cf1d0a..37d6bd41a0aeb6 100644 --- a/tools/node_modules/eslint/node_modules/pify/package.json +++ b/tools/node_modules/eslint/node_modules/pify/package.json @@ -12,12 +12,12 @@ "description": "Promisify a callback-style function", "devDependencies": { "ava": "*", - "pinkie-promise": "^1.0.0", - "v8-natives": "0.0.2", + "pinkie-promise": "^2.0.0", + "v8-natives": "^1.0.0", "xo": "*" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" }, "files": [ "index.js" @@ -27,6 +27,7 @@ "promise", "promises", "promisify", + "all", "denodify", "denodeify", "callback", @@ -41,7 +42,9 @@ "bind", "to", "async", - "es2015" + "await", + "es2015", + "bluebird" ], "license": "MIT", "name": "pify", @@ -53,5 +56,5 @@ "optimization-test": "node --allow-natives-syntax optimization-test.js", "test": "xo && ava && npm run optimization-test" }, - "version": "2.3.0" + "version": "3.0.0" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/pify/readme.md b/tools/node_modules/eslint/node_modules/pify/readme.md index c79ca8bf643927..376ca4e59d74c4 100644 --- a/tools/node_modules/eslint/node_modules/pify/readme.md +++ b/tools/node_modules/eslint/node_modules/pify/readme.md @@ -16,15 +16,13 @@ $ npm install --save pify const fs = require('fs'); const pify = require('pify'); -// promisify a single function - +// Promisify a single function pify(fs.readFile)('package.json', 'utf8').then(data => { console.log(JSON.parse(data).name); //=> 'pify' }); -// or promisify all methods in a module - +// Promisify all methods in a module pify(fs).readFile('package.json', 'utf8').then(data => { console.log(JSON.parse(data).name); //=> 'pify' @@ -34,32 +32,24 @@ pify(fs).readFile('package.json', 'utf8').then(data => { ## API -### pify(input, [promiseModule], [options]) +### pify(input, [options]) -Returns a promise wrapped version of the supplied function or module. +Returns a `Promise` wrapped version of the supplied function or module. #### input -Type: `function`, `object` +Type: `Function` `Object` Callback-style function or module whose methods you want to promisify. -#### promiseModule - -Type: `function` - -Custom promise module to use instead of the native one. - -Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill. - #### options ##### multiArgs -Type: `boolean` +Type: `boolean`
Default: `false` -By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. +By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. This also applies to rejections, where it returns an array of all the callback arguments, including the error. ```js const request = require('request'); @@ -72,23 +62,23 @@ pify(request, {multiArgs: true})('https://sindresorhus.com').then(result => { ##### include -Type: `array` of (`string`|`regex`) +Type: `string[]` `RegExp[]` Methods in a module to promisify. Remaining methods will be left untouched. ##### exclude -Type: `array` of (`string`|`regex`) -Default: `[/.+Sync$/]` +Type: `string[]` `RegExp[]`
+Default: `[/.+(Sync|Stream)$/]` Methods in a module **not** to promisify. Methods with names ending with `'Sync'` are excluded by default. ##### excludeMain -Type: `boolean` +Type: `boolean`
Default: `false` -By default, if given module is a function itself, this function will be promisified. Turn this option on if you want to promisify only methods of the module. +If given module is a function itself, it will be promisified. Turn this option on if you want to promisify only methods of the module. ```js const pify = require('pify'); @@ -99,11 +89,11 @@ function fn() { fn.method = (data, callback) => { setImmediate(() => { - callback(data, null); + callback(null, data); }); }; -// promisify methods but not fn() +// Promisify methods but not `fn()` const promiseFn = pify(fn, {excludeMain: true}); if (promiseFn()) { @@ -113,7 +103,29 @@ if (promiseFn()) { } ``` +##### errorFirst + +Type: `boolean`
+Default: `true` + +Whether the callback has an error as the first argument. You'll want to set this to `false` if you're dealing with an API that doesn't have an error as the first argument, like `fs.exists()`, some browser APIs, Chrome Extension APIs, etc. + +##### promiseModule + +Type: `Function` + +Custom promise module to use instead of the native one. + +Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill. + + +## Related + +- [p-event](https://github.com/sindresorhus/p-event) - Promisify an event by waiting for it to be emitted +- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently +- [More…](https://github.com/sindresorhus/promise-fun) + ## License -MIT © [Sindre Sorhus](http://sindresorhus.com) +MIT © [Sindre Sorhus](https://sindresorhus.com) diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js index 75116385eed36c..fd45b729d069e1 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js @@ -1,13 +1,6 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:decode - * @fileoverview Decode entities. - */ - 'use strict'; +var xtend = require('xtend'); var entities = require('parse-entities'); module.exports = factory; @@ -62,10 +55,10 @@ function factory(ctx) { } /* Decode `value` (at `position`) into a string. */ - function decodeRaw(value, position) { - return entities(value, { + function decodeRaw(value, position, options) { + return entities(value, xtend(options, { position: normalize(position), warning: handleWarning - }); + })); } } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js index ccb3fabd485901..37846f3930a35a 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js @@ -1,21 +1,10 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:defaults - * @fileoverview Default options for `parse`. - */ - 'use strict'; -/* Expose. */ module.exports = { position: true, gfm: true, - yaml: true, commonmark: false, footnotes: false, pedantic: false, - blocks: require('./block-elements'), - breaks: false + blocks: require('./block-elements.json') }; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js index b5550e10076605..295bdc9855126e 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:break - * @fileoverview Locate a break. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js index 010e74dcec4b00..981c81698254fe 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:code-inline - * @fileoverview Locate inline code. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js index 1a892e1be7716e..d208aef2fff386 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:delete - * @fileoverview Locate strikethrough. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js index 270daad0f9e00c..6a1f24227d05bb 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:emphasis - * @fileoverview Locate italics / emphasis. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js index 45f9b449a7873c..f6c63715827ef3 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:escape - * @fileoverview Locate an escape. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js index dab2a3c54f1774..0f16fd8016bd36 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:link - * @fileoverview Locate a link. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js index 717259f36eae22..da1cac0a499f2e 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:strong - * @fileoverview Locate bold / strong / importance. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js index 56e2d49e564587..3c5534268abe1d 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:tag - * @fileoverview Locate a tag. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js index 53b239241c104a..59b63e2563693e 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:url - * @fileoverview Locate a URL. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js index 53a50b181e67d4..5a8d8119556792 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:parse - * @fileoverview Parse the document - */ - 'use strict'; var xtend = require('xtend'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js index 8fe982b661c41c..9291109f16f3ec 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse - * @fileoverview Markdown parser. - */ - 'use strict'; var xtend = require('xtend'); @@ -17,7 +9,6 @@ var tokenizer = require('./tokenizer'); module.exports = Parser; -/* Construct a new parser. */ function Parser(doc, file) { this.file = file; this.offset = {}; @@ -34,7 +25,6 @@ function Parser(doc, file) { this.decode = decode(this); } -/* Prototype. */ var proto = Parser.prototype; /* Expose core. */ @@ -80,6 +70,7 @@ proto.interruptParagraph = [ * In the above example, the thematic break “interupts” * the list. */ proto.interruptList = [ + ['atxHeading', {pedantic: false}], ['fencedCode', {pedantic: false}], ['thematicBreak', {pedantic: false}], ['definition', {commonmark: false}], @@ -109,7 +100,6 @@ proto.interruptBlockquote = [ /* Handlers. */ proto.blockTokenizers = { - yamlFrontMatter: require('./tokenize/yaml'), newline: require('./tokenize/newline'), indentedCode: require('./tokenize/code-indented'), fencedCode: require('./tokenize/code-fenced'), diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js index 3f9abad7c49a06..c55f7f32f31def 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse - * @fileoverview Markdown parser. - */ - 'use strict'; var xtend = require('xtend'); @@ -14,7 +6,6 @@ var defaults = require('./defaults'); module.exports = setOptions; -/* Set options. */ function setOptions(options) { var self = this; var current = self.options; @@ -43,10 +34,7 @@ function setOptions(options) { (key !== 'blocks' && typeof value !== 'boolean') || (key === 'blocks' && typeof value !== 'object') ) { - throw new Error( - 'Invalid value `' + value + '` ' + - 'for setting `options.' + key + '`' - ); + throw new Error('Invalid value `' + value + '` for setting `options.' + key + '`'); } options[key] = value; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js index 3861b48a14aead..c945a2c1f88f58 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js @@ -1,13 +1,6 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:auto-link - * @fileoverview Tokenise an auto-link. - */ - 'use strict'; +var whitespace = require('is-whitespace-character'); var decode = require('parse-entities'); var locate = require('../locate/tag'); @@ -34,7 +27,7 @@ function autoLink(eat, value, silent) { var link; var now; var content; - var tokenize; + var tokenizers; var exit; if (value.charAt(0) !== C_LT) { @@ -56,7 +49,7 @@ function autoLink(eat, value, silent) { character = value.charAt(index); if ( - character === ' ' || + whitespace(character) || character === C_GT || character === C_AT_SIGN || (character === ':' && value.charAt(index + 1) === C_SLASH) @@ -96,7 +89,7 @@ function autoLink(eat, value, silent) { while (index < length) { character = value.charAt(index); - if (character === ' ' || character === C_GT) { + if (whitespace(character) || character === C_GT) { break; } @@ -132,20 +125,21 @@ function autoLink(eat, value, silent) { } } - /* Temporarily remove support for escapes in autolinks. */ - tokenize = self.inlineTokenizers.escape; - self.inlineTokenizers.escape = null; + /* Temporarily remove all tokenizers except text in autolinks. */ + tokenizers = self.inlineTokenizers; + self.inlineTokenizers = {text: tokenizers.text}; + exit = self.enterLink(); content = self.tokenizeInline(content, now); - self.inlineTokenizers.escape = tokenize; + self.inlineTokenizers = tokenizers; exit(); return eat(subvalue)({ type: 'link', title: null, - url: decode(link), + url: decode(link, {nonTerminated: false}), children: content }); } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js index 764e0aa010392c..bd700d6a6c8276 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:blockquote - * @fileoverview Tokenise blockquote. - */ - 'use strict'; var trim = require('trim'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js index 6d2d0dcff9552b..eb531342bfebcb 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:break - * @fileoverview Tokenise a break. - */ - 'use strict'; var locate = require('../locate/break'); @@ -15,10 +7,7 @@ hardBreak.locator = locate; var MIN_BREAK_LENGTH = 2; -/* Tokenise a break. */ function hardBreak(eat, value, silent) { - var self = this; - var breaks = self.options.breaks; var length = value.length; var index = -1; var queue = ''; @@ -28,7 +17,7 @@ function hardBreak(eat, value, silent) { character = value.charAt(index); if (character === '\n') { - if (!breaks && index < MIN_BREAK_LENGTH) { + if (index < MIN_BREAK_LENGTH) { return; } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js index f2577405b26587..65f2bc73273ab3 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:code-fenced - * @fileoverview Tokenise fenced code. - */ - 'use strict'; var trim = require('trim-trailing-lines'); @@ -21,7 +13,6 @@ var C_TICK = '`'; var MIN_FENCE_COUNT = 3; var CODE_INDENT_COUNT = 4; -/* Tokenise fenced code. */ function fencedCode(eat, value, silent) { var self = this; var settings = self.options; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js index 50c581fe26e2e4..c73849d9ad8bf2 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:code-indented - * @fileoverview Tokenise indented code. - */ - 'use strict'; var repeat = require('repeat-string'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js index 9157412753ad1a..c0a496b49255ba 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:code-inline - * @fileoverview Tokenise inline code. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js index 3f7345a2c901c8..1cce274cfbdd71 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:definition - * @fileoverview Tokenise a definition. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -29,7 +21,6 @@ var C_COLON = ':'; var C_LT = '<'; var C_GT = '>'; -/* Tokenise a definition. */ function definition(eat, value, silent) { var self = this; var commonmark = self.options.commonmark; @@ -254,7 +245,7 @@ function definition(eat, value, silent) { } beforeURL = eat(beforeURL).test().end; - url = self.decode.raw(self.unescape(url), beforeURL); + url = self.decode.raw(self.unescape(url), beforeURL, {nonTerminated: false}); if (title) { beforeTitle = eat(beforeTitle).test().end; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js index 60ae9c4936c61f..ca7c68a8c5c1be 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:delete - * @fileoverview Tokenise strikethrough. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -17,7 +9,6 @@ strikethrough.locator = locate; var C_TILDE = '~'; var DOUBLE = '~~'; -/* Tokenise strikethrough. */ function strikethrough(eat, value, silent) { var self = this; var character = ''; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js index 46249369224bc5..b2c87b4497de38 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:emphasis - * @fileoverview Tokenise emphasis. - */ - 'use strict'; var trim = require('trim'); @@ -19,7 +11,6 @@ emphasis.locator = locate; var C_ASTERISK = '*'; var C_UNDERSCORE = '_'; -/* Tokenise emphasis. */ function emphasis(eat, value, silent) { var self = this; var index = 0; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js index 3e41a4cec5e6ea..d6f99bcc10381d 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:escape - * @fileoverview Tokenise an escape. - */ - 'use strict'; var locate = require('../locate/escape'); @@ -13,7 +5,6 @@ var locate = require('../locate/escape'); module.exports = escape; escape.locator = locate; -/* Tokenise an escape. */ function escape(eat, value, silent) { var self = this; var character; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js index 3537ccb6115017..f48ff9bb7eb187 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:footnote-definition - * @fileoverview Tokenise footnote definition. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -26,7 +18,6 @@ var C_COLON = ':'; var EXPRESSION_INITIAL_TAB = /^( {4}|\t)?/gm; -/* Tokenise a footnote definition. */ function footnoteDefinition(eat, value, silent) { var self = this; var offsets = self.offset; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js index e5fdedc537ad0b..aafeabb54910f6 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:heading-atx - * @fileoverview Tokenise an ATX-style heading. - */ - 'use strict'; module.exports = atxHeading; @@ -17,7 +9,6 @@ var C_HASH = '#'; var MAX_ATX_COUNT = 6; -/* Tokenise an ATX-style heading. */ function atxHeading(eat, value, silent) { var self = this; var settings = self.options; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js index db8bbcfb73c2c9..96c6130da744e1 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:heading-setext - * @fileoverview Tokenise an setext-style heading. - */ - 'use strict'; module.exports = setextHeading; @@ -25,7 +17,6 @@ var SETEXT_MARKERS = {}; SETEXT_MARKERS[C_EQUALS] = 1; SETEXT_MARKERS[C_DASH] = 2; -/* Tokenise an setext-style heading. */ function setextHeading(eat, value, silent) { var self = this; var now = eat.now(); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js index dc861b53c3a37b..6e81eb290a3993 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:html-block - * @fileoverview Tokenise block HTML. - */ - 'use strict'; var openCloseTag = require('../util/html').openCloseTag; @@ -17,7 +9,6 @@ var C_SPACE = ' '; var C_NEWLINE = '\n'; var C_LT = '<'; -/* Tokenise block HTML. */ function blockHTML(eat, value, silent) { var self = this; var blocks = self.options.blocks; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js index d8c0b9ab21829a..c204e962b15ae8 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:html-inline - * @fileoverview Tokenise inline HTML. - */ - 'use strict'; var alphabetical = require('is-alphabetical'); @@ -18,7 +10,6 @@ inlineHTML.locator = locate; var EXPRESSION_HTML_LINK_OPEN = /^/i; -/* Tokenise inline HTML. */ function inlineHTML(eat, value, silent) { var self = this; var length = value.length; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js index fb11c5099054df..3ef5e1ba312d75 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js @@ -1,20 +1,13 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:link - * @fileoverview Tokenise a link. - */ - 'use strict'; -var has = require('has'); var whitespace = require('is-whitespace-character'); var locate = require('../locate/link'); module.exports = link; link.locator = locate; +var own = {}.hasOwnProperty; + var C_BACKSLASH = '\\'; var C_BRACKET_OPEN = '['; var C_BRACKET_CLOSE = ']'; @@ -41,12 +34,12 @@ COMMONMARK_LINK_MARKERS[C_DOUBLE_QUOTE] = C_DOUBLE_QUOTE; COMMONMARK_LINK_MARKERS[C_SINGLE_QUOTE] = C_SINGLE_QUOTE; COMMONMARK_LINK_MARKERS[C_PAREN_OPEN] = C_PAREN_CLOSE; -/* Tokenise a link. */ function link(eat, value, silent) { var self = this; var subvalue = ''; var index = 0; var character = value.charAt(0); + var pedantic = self.options.pedantic; var commonmark = self.options.commonmark; var gfm = self.options.gfm; var closed; @@ -134,7 +127,7 @@ function link(eat, value, silent) { } else { /* Allow white-space between content and * url in GFM mode. */ - if (gfm) { + if (!pedantic) { while (index < length) { character = value.charAt(index + 1); @@ -224,12 +217,12 @@ function link(eat, value, silent) { while (index < length) { character = value.charAt(index); - if (subqueue && has(markers, character)) { + if (subqueue && own.call(markers, character)) { break; } if (whitespace(character)) { - if (commonmark) { + if (!pedantic) { break; } @@ -282,7 +275,7 @@ function link(eat, value, silent) { subvalue += queue; /* Eat the title. */ - if (queue && has(markers, character)) { + if (queue && own.call(markers, character)) { index++; subvalue += character; queue = ''; @@ -374,7 +367,7 @@ function link(eat, value, silent) { subvalue += C_PAREN_CLOSE; - url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end); + url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end, {nonTerminated: false}); if (title) { beforeTitle = eat(beforeTitle).test().end; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js index da8002e574196c..9164c8167f8dc1 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:list - * @fileoverview Tokenise a list. - */ - 'use strict'; /* eslint-disable max-params */ @@ -58,7 +50,6 @@ var LIST_ORDERED_COMMONMARK_MARKERS = {}; LIST_ORDERED_COMMONMARK_MARKERS[C_DOT] = true; LIST_ORDERED_COMMONMARK_MARKERS[C_PAREN_CLOSE] = true; -/* Tokenise a list. */ function list(eat, value, silent) { var self = this; var commonmark = self.options.commonmark; @@ -371,17 +362,6 @@ function list(eat, value, silent) { return node; } -/** - * Create a list-item node. - * - * @example - * listItem('- _foo_', now()); - * - * @param {Object} ctx - Parser. - * @param {Object} value - List-item. - * @param {Object} position - List-item location. - * @return {Object} - `listItem` node. - */ function listItem(ctx, value, position) { var offsets = ctx.offset; var fn = ctx.options.pedantic ? pedanticListItem : normalListItem; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js index f710e0ef976603..6008670cc5e742 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:newline - * @fileoverview Tokenise a newline. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js index 7d064522ffecbd..1492a027e78237 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:paragraph - * @fileoverview Tokenise a paragraph. - */ - 'use strict'; var trim = require('trim'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js index 1fa150d9e6b958..50713f1ccfc8fa 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:reference - * @fileoverview Tokenise a reference. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -26,7 +18,6 @@ var C_BACKSLASH = '\\'; var C_BRACKET_OPEN = '['; var C_BRACKET_CLOSE = ']'; -/* Tokenise a reference. */ function reference(eat, value, silent) { var self = this; var character = value.charAt(0); @@ -61,11 +52,13 @@ function reference(eat, value, silent) { queue = ''; /* Check whether we’re eating a footnote. */ - if ( - self.options.footnotes && - type === T_LINK && - value.charAt(index) === C_CARET - ) { + if (self.options.footnotes && value.charAt(index) === C_CARET) { + /* Exit if `![^` is found, so the `!` will be seen as text after this, + * and we’ll enter this function again when `[^` is found. */ + if (type === T_IMAGE) { + return; + } + intro += C_CARET; index++; type = T_FOOTNOTE; @@ -122,7 +115,8 @@ function reference(eat, value, silent) { character = value.charAt(index); - if (character === C_BRACKET_OPEN) { + /* Inline footnotes cannot have an identifier. */ + if (type !== T_FOOTNOTE && character === C_BRACKET_OPEN) { identifier = ''; queue += character; index++; @@ -168,13 +162,6 @@ function reference(eat, value, silent) { return; } - /* Inline footnotes cannot have an identifier. */ - if (type === T_FOOTNOTE && referenceType !== REFERENCE_TYPE_SHORTCUT) { - type = T_LINK; - intro = C_BRACKET_OPEN + C_CARET; - content = C_CARET + content; - } - subvalue = intro + subvalue; if (type === T_LINK && self.inLink) { diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js index 765993fa0bd4b3..12d5785bc64a74 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:strong - * @fileoverview Tokenise strong. - */ - 'use strict'; var trim = require('trim'); @@ -18,7 +10,6 @@ strong.locator = locate; var C_ASTERISK = '*'; var C_UNDERSCORE = '_'; -/* Tokenise strong. */ function strong(eat, value, silent) { var self = this; var index = 0; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js index c440067e1011d7..ce93b1d22f0f31 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js @@ -1,17 +1,8 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:table - * @fileoverview Tokenise a table. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); module.exports = table; -table.notInList = true; var C_BACKSLASH = '\\'; var C_TICK = '`'; @@ -30,7 +21,6 @@ var TABLE_ALIGN_CENTER = 'center'; var TABLE_ALIGN_RIGHT = 'right'; var TABLE_ALIGN_NONE = null; -/* Tokenise a table. */ function table(eat, value, silent) { var self = this; var index; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js index ef6d3f2879d46e..4aedfa90d5d9b8 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js @@ -1,16 +1,7 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:text - * @fileoverview Tokenise text. - */ - 'use strict'; module.exports = text; -/* Tokenise text. */ function text(eat, value, silent) { var self = this; var methods; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js index a580d09fe09c0b..2391e3f592cb25 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:thematic-break - * @fileoverview Tokenise a thematic break. - */ - 'use strict'; module.exports = thematicBreak; @@ -19,7 +11,6 @@ var C_DASH = '-'; var THEMATIC_BREAK_MARKER_COUNT = 3; -/* Tokenise a thematic break. */ function thematicBreak(eat, value, silent) { var index = -1; var length = value.length + 1; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js index fd2debd32f35fe..297940bf4ab922 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:url - * @fileoverview Tokenise a URL. - */ - 'use strict'; var decode = require('parse-entities'); @@ -35,7 +27,6 @@ var PROTOCOLS = [ var PROTOCOLS_LENGTH = PROTOCOLS.length; -/* Tokenise a URL. */ function url(eat, value, silent) { var self = this; var subvalue; @@ -147,7 +138,7 @@ function url(eat, value, silent) { return eat(subvalue)({ type: 'link', title: null, - url: decode(subvalue), + url: decode(subvalue, {nonTerminated: false}), children: content }); } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/yaml.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/yaml.js deleted file mode 100644 index 78dec31a0f9eb8..00000000000000 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/yaml.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:yaml - * @fileoverview Tokenise YAML. - */ - -'use strict'; - -module.exports = yaml; -yaml.onlyAtStart = true; - -var FENCE = '---'; -var C_DASH = '-'; -var C_NEWLINE = '\n'; - -/* Tokenise YAML. */ -function yaml(eat, value, silent) { - var self = this; - var subvalue; - var content; - var index; - var length; - var character; - var queue; - - if ( - !self.options.yaml || - value.charAt(0) !== C_DASH || - value.charAt(1) !== C_DASH || - value.charAt(2) !== C_DASH || - value.charAt(3) !== C_NEWLINE - ) { - return; - } - - subvalue = FENCE + C_NEWLINE; - content = ''; - queue = ''; - index = 3; - length = value.length; - - while (++index < length) { - character = value.charAt(index); - - if ( - character === C_DASH && - (queue || !content) && - value.charAt(index + 1) === C_DASH && - value.charAt(index + 2) === C_DASH - ) { - /* istanbul ignore if - never used (yet) */ - if (silent) { - return true; - } - - subvalue += queue + FENCE; - - return eat(subvalue)({ - type: 'yaml', - value: content - }); - } - - if (character === C_NEWLINE) { - queue += character; - } else { - subvalue += queue + character; - content += queue + character; - queue = ''; - } - } -} diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js index aefe551fc37993..498ef22ad949af 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenizer - * @fileoverview Markdown tokenizer. - */ - 'use strict'; module.exports = factory; @@ -101,7 +93,7 @@ function factory(type) { if ( method && - (!method.onlyAtStart || self.atStart) && + /* istanbul ignore next */ (!method.onlyAtStart || self.atStart) && (!method.notInList || !self.inList) && (!method.notInBlock || !self.inBlock) && (!method.notInLink || !self.inLink) @@ -128,15 +120,8 @@ function factory(type) { return tokens; - /** - * Update line, column, and offset based on - * `value`. - * - * @example - * updatePosition('foo'); - * - * @param {string} subvalue - Subvalue to eat. - */ + /* Update line, column, and offset based on + * `value`. */ function updatePosition(subvalue) { var lastIndex = -1; var index = subvalue.indexOf('\n'); @@ -162,23 +147,14 @@ function factory(type) { } } - /** - * Get offset. Called before the first character is - * eaten to retrieve the range's offsets. - * - * @return {Function} - `done`, to be called when - * the last character is eaten. - */ + /* Get offset. Called before the first character is + * eaten to retrieve the range's offsets. */ function getOffset() { var indentation = []; var pos = line + 1; - /** - * Done. Called when the last character is - * eaten to retrieve the range’s offsets. - * - * @return {Array.} - Offset. - */ + /* Done. Called when the last character is + * eaten to retrieve the range’s offsets. */ return function () { var last = line + 1; @@ -192,14 +168,7 @@ function factory(type) { }; } - /** - * Get the current position. - * - * @example - * position = now(); // {line: 1, column: 1, offset: 0} - * - * @return {Object} - Current Position. - */ + /* Get the current position. */ function now() { var pos = {line: line, column: column}; @@ -208,41 +177,15 @@ function factory(type) { return pos; } - /** - * Store position information for a node. - * - * @example - * start = now(); - * updatePosition('foo'); - * location = new Position(start); - * // { - * // start: {line: 1, column: 1, offset: 0}, - * // end: {line: 1, column: 3, offset: 2} - * // } - * - * @param {Object} start - Starting position. - */ + /* Store position information for a node. */ function Position(start) { this.start = start; this.end = now(); } - /** - * Throw when a value is incorrectly eaten. + /* Throw when a value is incorrectly eaten. * This shouldn’t happen but will throw on new, - * incorrect rules. - * - * @example - * // When the current value is set to `foo bar`. - * validateEat('foo'); - * eat('foo'); - * - * validateEat('bar'); - * // throws, because the space is not eaten. - * - * @param {string} subvalue - Value to be eaten. - * @throws {Error} - When `subvalue` cannot be eaten. - */ + * incorrect rules. */ function validateEat(subvalue) { /* istanbul ignore if */ if (value.substring(0, subvalue.length) !== subvalue) { @@ -257,39 +200,13 @@ function factory(type) { } } - /** - * Mark position and patch `node.position`. - * - * @example - * var update = position(); - * updatePosition('foo'); - * update({}); - * // { - * // position: { - * // start: {line: 1, column: 1, offset: 0}, - * // end: {line: 1, column: 3, offset: 2} - * // } - * // } - * - * @returns {Function} - Updater. - */ + /* Mark position and patch `node.position`. */ function position() { var before = now(); return update; - /** - * Add the position to a node. - * - * @example - * update({type: 'text', value: 'foo'}); - * - * @param {Node} node - Node to attach position - * on. - * @param {Array} [indent] - Indentation for - * `node`. - * @return {Node} - `node`. - */ + /* Add the position to a node. */ function update(node, indent) { var prev = node.position; var start = prev ? prev.start : before; @@ -327,19 +244,8 @@ function factory(type) { } } - /** - * Add `node` to `parent`s children or to `tokens`. - * Performs merges where possible. - * - * @example - * add({}); - * - * add({}, {children: []}); - * - * @param {Object} node - Node to add. - * @param {Object} [parent] - Parent to insert into. - * @return {Object} - Added or merged into node. - */ + /* Add `node` to `parent`s children or to `tokens`. + * Performs merges where possible. */ function add(node, parent) { var children = parent ? parent.children : tokens; var prev = children[children.length - 1]; @@ -365,18 +271,8 @@ function factory(type) { return node; } - /** - * Remove `subvalue` from `value`. - * `subvalue` must be at the start of `value`. - * - * @example - * eat('foo')({type: 'text', value: 'foo'}); - * - * @param {string} subvalue - Removed from `value`, - * and passed to `updatePosition`. - * @return {Function} - Wrapper around `add`, which - * also adds `position` to node. - */ + /* Remove `subvalue` from `value`. + * `subvalue` must be at the start of `value`. */ function eat(subvalue) { var indent = getOffset(); var pos = position(); @@ -396,31 +292,19 @@ function factory(type) { return apply; - /** - * Add the given arguments, add `position` to - * the returned node, and return the node. - * - * @param {Object} node - Node to add. - * @param {Object} [parent] - Node to insert into. - * @return {Node} - Added node. - */ + /* Add the given arguments, add `position` to + * the returned node, and return the node. */ function apply(node, parent) { return pos(add(pos(node), parent), indent); } - /** - * Functions just like apply, but resets the + /* Functions just like apply, but resets the * content: the line and column are reversed, * and the eaten value is re-added. - * * This is useful for nodes with a single * type of content, such as lists and tables. - * * See `apply` above for what parameters are - * expected. - * - * @return {Node} - Added node. - */ + * expected. */ function reset() { var node = apply.apply(null, arguments); @@ -431,12 +315,8 @@ function factory(type) { return node; } - /** - * Test the position, after eating, and reverse - * to a not-eaten state. - * - * @return {Position} - Position after eating `subvalue`. - */ + /* Test the position, after eating, and reverse + * to a not-eaten state. */ function test() { var result = pos({}); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js index dc83486126112c..321900e7eacd73 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js @@ -1,14 +1,5 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:unescape - * @fileoverview Unescape escapes. - */ - 'use strict'; -/* Expose. */ module.exports = factory; /* Factory to de-escape a value, based on a list at `key` diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js index eebd40c94ac26b..3e09e1411ed67c 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js @@ -1,26 +1,12 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:get-indentation - * @fileoverview Get indentation. - */ - 'use strict'; -/* Expose. */ module.exports = indentation; /* Map of characters, and their column length, * which can be used as indentation. */ var characters = {' ': 1, '\t': 4}; -/** - * Gets indentation information for a line. - * - * @param {string} value - Indented line. - * @return {Object} - Indetation information. - */ +/* Gets indentation information for a line. */ function indentation(value) { var index = 0; var indent = 0; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js index 234ba342e1d3fa..5f211f13f8f534 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:html - * @fileoverview HTML regexes. - */ - 'use strict'; var attributeName = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js index b8dc2305501db1..e3178ab45c60df 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:get-indentation - * @fileoverview Get indentation. - */ - 'use strict'; module.exports = interrupt; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js index 3602a18f788317..846ceeecac5ade 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js @@ -1,29 +1,11 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:normalize - * @fileoverview Normalize an identifier. - */ - 'use strict'; -/* Dependencies. */ var collapseWhiteSpace = require('collapse-white-space'); -/* Expose. */ module.exports = normalize; -/** - * Normalize an identifier. Collapses multiple white space - * characters into a single space, and removes casing. - * - * @example - * normalizeIdentifier('FOO\t bar'); // 'foo bar' - * - * @param {string} value - Content to normalize. - * @return {string} - Normalized content. - */ +/* Normalize an identifier. Collapses multiple white space + * characters into a single space, and removes casing. */ function normalize(value) { return collapseWhiteSpace(value).toLowerCase(); } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js index d56db0bad4b735..20f18be74087eb 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js @@ -1,42 +1,18 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:remove-indentation - * @fileoverview Remove indentation. - */ - 'use strict'; -/* Dependencies. */ var trim = require('trim'); var repeat = require('repeat-string'); var getIndent = require('./get-indentation'); -/* Expose. */ module.exports = indentation; -/* Characters. */ var C_SPACE = ' '; var C_NEWLINE = '\n'; var C_TAB = '\t'; -/** - * Remove the minimum indent from every line in `value`. +/* Remove the minimum indent from every line in `value`. * Supports both tab, spaced, and mixed indentation (as - * well as possible). - * - * @example - * removeIndentation(' foo'); // 'foo' - * removeIndentation(' foo', 2); // ' foo' - * removeIndentation('\tfoo', 2); // ' foo' - * removeIndentation(' foo\n bar'); // ' foo\n bar' - * - * @param {string} value - Value to trim. - * @param {number?} [maximum] - Maximum indentation - * to remove. - * @return {string} - Unindented `value`. - */ + * well as possible). */ function indentation(value, maximum) { var values = value.split(C_NEWLINE); var position = values.length + 1; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/package.json b/tools/node_modules/eslint/node_modules/remark-parse/package.json index fcecf978cd74e0..b47866c95b256b 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/package.json +++ b/tools/node_modules/eslint/node_modules/remark-parse/package.json @@ -5,7 +5,7 @@ "url": "http://wooorm.com" }, "bugs": { - "url": "https://github.com/wooorm/remark/issues" + "url": "https://github.com/remarkjs/remark/issues" }, "bundleDependencies": false, "contributors": [ @@ -21,13 +21,12 @@ ], "dependencies": { "collapse-white-space": "^1.0.2", - "has": "^1.0.1", "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0", "is-whitespace-character": "^1.0.0", "is-word-character": "^1.0.0", "markdown-escapes": "^1.0.0", - "parse-entities": "^1.0.2", + "parse-entities": "^1.1.0", "repeat-string": "^1.5.4", "state-toggle": "^1.0.0", "trim": "0.0.1", @@ -56,8 +55,8 @@ "name": "remark-parse", "repository": { "type": "git", - "url": "https://github.com/wooorm/remark/tree/master/packages/remark-parse" + "url": "https://github.com/remarkjs/remark/tree/master/packages/remark-parse" }, - "version": "3.0.1", + "version": "5.0.0", "xo": false } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/remark-parse/readme.md b/tools/node_modules/eslint/node_modules/remark-parse/readme.md index 53426f41eee224..ecaa6c093c0ab2 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/readme.md +++ b/tools/node_modules/eslint/node_modules/remark-parse/readme.md @@ -33,7 +33,7 @@ process.stdin ## Table of Contents * [API](#api) - * [processor.use(parse)](#processoruseparse) + * [processor.use(parse\[, options\])](#processoruseparse-options) * [parse.Parser](#parseparser) * [Extending the Parser](#extending-the-parser) * [Parser#blockTokenizers](#parserblocktokenizers) @@ -46,29 +46,19 @@ process.stdin * [add(node\[, parent\])](#addnode-parent) * [add.test()](#addtest) * [add.reset(node\[, parent\])](#addresetnode-parent) + * [Turning off a tokenizer](#turning-off-a-tokenizer) * [License](#license) ## API -### `processor.use(parse)` +### `processor.use(parse[, options])` Configure the `processor` to read markdown as input and process an [**MDAST**][mdast] syntax tree. -#### `options` +##### `options` -Options are passed later through [`processor.parse()`][parse], -[`processor.process()`][process], or [`processor.pipe()`][pipe]. -The following settings are supported: - -* [`gfm`][options-gfm] (`boolean`, default: `true`) -* [`yaml`][options-yaml] (`boolean`, default: `true`) -* [`commonmark`][options-commonmark] (`boolean`, default: `false`) -* [`footnotes`][options-footnotes] (`boolean`, default: `false`) -* [`pedantic`][options-pedantic] (`boolean`, default: `false`) -* [`breaks`][options-breaks] (`boolean`, default: `false`) -* [`blocks`][options-blocks] (`Array.`, default: list of block HTML - elements) +Options are passed directly, or passed later through [`processor.data()`][data]. ##### `options.gfm` @@ -76,7 +66,7 @@ The following settings are supported: hello ~~hi~~ world ``` -GFM mode (default: `true`) turns on: +GFM mode (`boolean`, default: `true`) turns on: * [Fenced code blocks](https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks) * [Autolinking of URLs](https://help.github.com/articles/github-flavored-markdown/#url-autolinking) @@ -84,19 +74,6 @@ GFM mode (default: `true`) turns on: * [Task lists](https://help.github.com/articles/writing-on-github/#task-lists) * [Tables](https://help.github.com/articles/github-flavored-markdown/#tables) -##### `options.yaml` - -```md ---- -title: YAML is Cool ---- - -# YAML is Cool -``` - -YAML mode (default: `true`) enables raw YAML front matter to be detected -at the top. - ##### `options.commonmark` ```md @@ -104,7 +81,7 @@ This is a paragraph and this is also part of the preceding paragraph. ``` -CommonMark mode (default: `false`) allows: +CommonMark mode (`boolean`, default: `false`) allows: * Empty lines to split blockquotes * Parentheses (`(` and `)`) around for link and image titles @@ -136,20 +113,10 @@ And something else[^1]. * ...and a list ``` -Footnotes mode (default: `false`) enables reference footnotes and inline -footnotes. Both are wrapped in square brackets and preceded by a caret +Footnotes mode (`boolean`, default: `false`) enables reference footnotes and +inline footnotes. Both are wrapped in square brackets and preceded by a caret (`^`), and can be referenced from inside other footnotes. -##### `options.breaks` - -```md -This is a -paragraph. -``` - -Breaks mode (default: `false`) exposes newline characters inside -paragraphs as breaks. - ##### `options.blocks` ```md @@ -157,8 +124,8 @@ paragraphs as breaks. ``` -Blocks (default: a list of HTML block elements) exposes -let’s users define block-level HTML elements. +Blocks (`Array.`, default: list of [block HTML elements][blocks]) +exposes let’s users define block-level HTML elements. ##### `options.pedantic` @@ -166,7 +133,7 @@ let’s users define block-level HTML elements. Check out some_file_name.txt ``` -Pedantic mode (default: `false`) turns on: +Pedantic mode (`boolean`, default: `false`) turns on: * Emphasis (`_alpha_`) and importance (`__bravo__`) with underscores in words @@ -187,11 +154,11 @@ the desired output. Sometimes, mainly when introducing new syntactic entities with a certain level of precedence, interfacing with the parser is necessary. -If this plug-in is used, it adds a [`Parser`][parser] constructor to -the `processor`. Other plug-ins can add tokenizers to the parser’s -prototype to change how markdown is parsed. +If the `remark-parse` plugin is used, it adds a [`Parser`][parser] constructor +to the `processor`. Other plugins can add tokenizers to the parser’s prototype +to change how markdown is parsed. -The below plug-in adds a [tokenizer][] for at-mentions. +The below plugin adds a [tokenizer][] for at-mentions. ```js module.exports = mentions; @@ -215,22 +182,63 @@ An object mapping tokenizer names to [tokenizer][]s. These tokenizers (for example: `fencedCode`, `table`, and `paragraph`) eat from the start of a value to a line ending. +See `#blockMethods` below for a list of methods that are included by +default. + ### `Parser#blockMethods` Array of `blockTokenizers` names (`string`) specifying the order in which they run. + + +* `newline` +* `indentedCode` +* `fencedCode` +* `blockquote` +* `atxHeading` +* `thematicBreak` +* `list` +* `setextHeading` +* `html` +* `footnote` +* `definition` +* `table` +* `paragraph` + + + ### `Parser#inlineTokenizers` An object mapping tokenizer names to [tokenizer][]s. These tokenizers (for example: `url`, `reference`, and `emphasis`) eat from the start of a value. To increase performance, they depend on [locator][]s. +See `#inlineMethods` below for a list of methods that are included by +default. + ### `Parser#inlineMethods` Array of `inlineTokenizers` names (`string`) specifying the order in which they run. + + +* `escape` +* `autoLink` +* `url` +* `html` +* `link` +* `reference` +* `strong` +* `emphasis` +* `deletion` +* `code` +* `break` +* `text` + + + ### `function tokenizer(eat, value, silent)` ```js @@ -379,63 +387,58 @@ for list items The given `node`. +### Turning off a tokenizer + +In rare situations, you may want to turn off a tokenizer to avoid parsing +that syntactic feature. This can be done by deleting the tokenizer from +your Parser’s `blockTokenizers` (or `blockMethods`) or `inlineTokenizers` +(or `inlineMethods`). + +The following example turns off indented code blocks: + +```js +delete remarkParse.Parser.prototype.blockTokenizers.indentedCode; +``` + ## License [MIT][license] © [Titus Wormer][author] -[build-badge]: https://img.shields.io/travis/wooorm/remark.svg +[build-badge]: https://img.shields.io/travis/remarkjs/remark.svg -[build-status]: https://travis-ci.org/wooorm/remark +[build-status]: https://travis-ci.org/remarkjs/remark -[coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/remark.svg +[coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark.svg -[coverage-status]: https://codecov.io/github/wooorm/remark +[coverage-status]: https://codecov.io/github/remarkjs/remark -[chat-badge]: https://img.shields.io/gitter/room/wooorm/remark.svg +[chat-badge]: https://img.shields.io/gitter/room/remarkjs/Lobby.svg -[chat]: https://gitter.im/wooorm/remark +[chat]: https://gitter.im/remarkjs/Lobby -[license]: https://github.com/wooorm/remark/blob/master/LICENSE +[license]: https://github.com/remarkjs/remark/blob/master/LICENSE [author]: http://wooorm.com [npm]: https://docs.npmjs.com/cli/install -[unified]: https://github.com/wooorm/unified - -[parse]: https://github.com/wooorm/unified#processorparsefilevalue-options +[unified]: https://github.com/unifiedjs/unified -[process]: https://github.com/wooorm/unified#processorprocessfilevalue-options-done +[data]: https://github.com/unifiedjs/unified#processordatakey-value -[pipe]: https://github.com/wooorm/unified#processorpipestream-options +[processor]: https://github.com/unifiedjs/remark/blob/master/packages/remark -[processor]: https://github.com/wooorm/remark/blob/master/packages/remark - -[mdast]: https://github.com/wooorm/mdast +[mdast]: https://github.com/syntax-tree/mdast [escapes]: http://spec.commonmark.org/0.25/#backslash-escapes -[node]: https://github.com/wooorm/unist#node - -[location]: https://github.com/wooorm/unist#location - -[options-gfm]: #optionsgfm - -[options-yaml]: #optionsyaml - -[options-commonmark]: #optionscommonmark +[node]: https://github.com/syntax-tree/unist#node -[options-footnotes]: #optionsfootnotes +[location]: https://github.com/syntax-tree/unist#location -[options-pedantic]: #optionspedantic - -[options-breaks]: #optionsbreaks - -[options-blocks]: #optionsblocks - -[parser]: https://github.com/wooorm/unified#processorparser +[parser]: https://github.com/unifiedjs/unified#processorparser [extend]: #extending-the-parser @@ -446,3 +449,5 @@ The given `node`. [eat]: #eatsubvalue [add]: #addnode-parent + +[blocks]: https://github.com/remarkjs/remark/blob/master/packages/remark-parse/lib/block-elements.json diff --git a/tools/node_modules/eslint/package.json b/tools/node_modules/eslint/package.json index 7b47dbd691f1ce..f35659fc8a1c23 100644 --- a/tools/node_modules/eslint/package.json +++ b/tools/node_modules/eslint/package.json @@ -17,7 +17,7 @@ "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^2.1.0", - "eslint-plugin-markdown": "^1.0.0-beta.8", + "eslint-plugin-markdown": "^1.0.0-rc.1", "eslint-scope": "^4.0.0", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", @@ -66,8 +66,8 @@ "coveralls": "^3.0.1", "dateformat": "^3.0.3", "ejs": "^2.6.1", - "eslint-plugin-eslint-plugin": "^1.2.0", - "eslint-plugin-node": "^7.0.1", + "eslint-plugin-eslint-plugin": "^1.4.1", + "eslint-plugin-node": "^8.0.0", "eslint-plugin-rulesdir": "^0.1.0", "eslint-release": "^1.0.0", "eslint-rule-composer": "^0.3.0", @@ -135,5 +135,5 @@ "publish-release": "node Makefile.js publishRelease", "test": "node Makefile.js test" }, - "version": "5.8.0" + "version": "5.9.0" } \ No newline at end of file diff --git a/tools/test.py b/tools/test.py index 3d0ba43beca8b5..3a464be61da1b3 100755 --- a/tools/test.py +++ b/tools/test.py @@ -1498,7 +1498,7 @@ def PrintCrashed(code): IGNORED_SUITES = [ 'addons', 'addons-napi', - 'code-cache', + 'benchmark', 'doctool', 'internet', 'pummel', diff --git a/vcbuild.bat b/vcbuild.bat index 1e31440cc29857..a22c756200bf17 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -83,6 +83,7 @@ if /i "%1"=="build-addons" set build_addons=1&goto arg-ok if /i "%1"=="build-addons-napi" set build_addons_napi=1&goto arg-ok if /i "%1"=="test-addons" set test_args=%test_args% addons&set build_addons=1&goto arg-ok if /i "%1"=="test-addons-napi" set test_args=%test_args% addons-napi&set build_addons_napi=1&goto arg-ok +if /i "%1"=="test-benchmark" set test_args=%test_args% benchmark&goto arg-ok if /i "%1"=="test-simple" set test_args=%test_args% sequential parallel -J&goto arg-ok if /i "%1"=="test-message" set test_args=%test_args% message&goto arg-ok if /i "%1"=="test-tick-processor" set test_args=%test_args% tick-processor&goto arg-ok @@ -634,7 +635,7 @@ del .used_configure_flags goto exit :help -echo vcbuild.bat [debug/release] [msi] [doc] [test/test-ci/test-all/test-addons/test-addons-napi/test-internet/test-pummel/test-simple/test-message/test-tick-processor/test-known-issues/test-node-inspect/test-check-deopts/test-npm/test-async-hooks/test-v8/test-v8-intl/test-v8-benchmarks/test-v8-all] [ignore-flaky] [static/dll] [noprojgen] [projgen] [small-icu/full-icu/without-intl] [nobuild] [nosnapshot] [noetw] [ltcg] [nopch] [licensetf] [sign] [ia32/x86/x64] [vs2017] [download-all] [enable-vtune] [lint/lint-ci/lint-js/lint-js-ci/lint-md] [lint-md-build] [package] [build-release] [upload] [no-NODE-OPTIONS] [link-module path-to-module] [debug-http2] [debug-nghttp2] [clean] [no-cctest] [openssl-no-asm] +echo vcbuild.bat [debug/release] [msi] [doc] [test/test-ci/test-all/test-addons/test-addons-napi/test-benchmark/test-internet/test-pummel/test-simple/test-message/test-tick-processor/test-known-issues/test-node-inspect/test-check-deopts/test-npm/test-async-hooks/test-v8/test-v8-intl/test-v8-benchmarks/test-v8-all] [ignore-flaky] [static/dll] [noprojgen] [projgen] [small-icu/full-icu/without-intl] [nobuild] [nosnapshot] [noetw] [ltcg] [nopch] [licensetf] [sign] [ia32/x86/x64] [vs2017] [download-all] [enable-vtune] [lint/lint-ci/lint-js/lint-js-ci/lint-md] [lint-md-build] [package] [build-release] [upload] [no-NODE-OPTIONS] [link-module path-to-module] [debug-http2] [debug-nghttp2] [clean] [no-cctest] [openssl-no-asm] echo Examples: echo vcbuild.bat : builds release build echo vcbuild.bat debug : builds debug build