diff --git a/.eslintrc.yaml b/.eslintrc.yaml
index 0e7e9ccfcb73b8..99489d2e7d8589 100644
--- a/.eslintrc.yaml
+++ b/.eslintrc.yaml
@@ -137,8 +137,11 @@ rules:
no-mixed-spaces-and-tabs: error
no-multiple-empty-lines: [error, {max: 2, maxEOF: 0, maxBOF: 0}]
no-restricted-syntax: [error, {
+ selector: "CallExpression[callee.object.name='assert'][callee.property.name='doesNotThrow']",
+ message: "Please replace `assert.doesNotThrow()` and add a comment next to the code instead."
+ }, {
selector: "CallExpression[callee.object.name='assert'][callee.property.name='throws'][arguments.1.type='Literal']:not([arguments.1.regex])",
- message: "use a regular expression for second argument of assert.throws()"
+ message: "Use a regular expression for second argument of assert.throws()"
}, {
selector: "CallExpression[callee.object.name='assert'][callee.property.name='throws'][arguments.length<2]",
message: "assert.throws() must be invoked with at least two arguments."
@@ -154,6 +157,7 @@ rules:
}]
no-tabs: error
no-trailing-spaces: error
+ no-unsafe-finally: error
object-curly-spacing: [error, always]
one-var-declaration-per-line: error
operator-linebreak: [error, after]
diff --git a/BUILDING.md b/BUILDING.md
index 74b5903ed22cd0..eda74fb70f41bc 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -39,7 +39,8 @@ in production.
| System | Support type | Version | Architectures | Notes |
|--------------|--------------|----------------------------------|----------------------|------------------|
-| GNU/Linux | Tier 1 | kernel >= 2.6.32, glibc >= 2.12 | x64, arm, arm64 | |
+| GNU/Linux | Tier 1 | kernel >= 2.6.32, glibc >= 2.12 | x64, arm | |
+| GNU/Linux | Tier 1 | kernel >= 3.10, glibc >= 2.17 | arm64 | |
| macOS | Tier 1 | >= 10.10 | x64 | |
| Windows | Tier 1 | >= Windows 7/2008 R2 | x86, x64 | vs2017 |
| SmartOS | Tier 2 | >= 15 < 16.4 | x86, x64 | see note1 |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ace79efd98eb37..74b83c56eb87f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,7 +29,8 @@ release.
-9.8.0
+9.9.0
+9.8.0 9.7.1 9.7.0 9.6.1
diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md
index e08c84e77cbc11..973e9c3681f981 100644
--- a/COLLABORATOR_GUIDE.md
+++ b/COLLABORATOR_GUIDE.md
@@ -469,10 +469,11 @@ $ npm install -g node-core-utils
$ git node land $PRID
```
-If it's the first time you ever use `node-core-utils`, you will be prompted
-to type the password of your GitHub account in the console so the tool can
-create the GitHub access token for you. If you do not want to do that, follow
-[the guide of `node-core-utils`][node-core-utils-credentials]
+If it's the first time you have used `node-core-utils`, you will be prompted
+to type the password of your GitHub account and the two-factor authentication
+code in the console so the tool can create the GitHub access token for you.
+If you do not want to do that, follow
+[the `node-core-utils` guide][node-core-utils-credentials]
to set up your credentials manually.
### Technical HOWTO
diff --git a/README.md b/README.md
index 1e6be9a38cbe1b..4bab46ef3d54c9 100644
--- a/README.md
+++ b/README.md
@@ -291,8 +291,6 @@ For more information about the governance of the Node.js project, see
### Collaborators
-* [abouthiroppy](https://github.com/abouthiroppy) -
-**Yuta Hiroto** <hello@about-hiroppy.com> (he/him)
* [addaleax](https://github.com/addaleax) -
**Anna Henningsen** <anna@addaleax.net> (she/her)
* [ak239](https://github.com/ak239) -
@@ -367,6 +365,8 @@ For more information about the governance of the Node.js project, see
**Guy Bedford** <guybedford@gmail.com> (he/him)
* [hashseed](https://github.com/hashseed) -
**Yang Guo** <yangguo@chromium.org> (he/him)
+* [hiroppy](https://github.com/hiroppy) -
+**Yuta Hiroto** <hello@hiroppy.me> (he/him)
* [iarna](https://github.com/iarna) -
**Rebecca Turner** <me@re-becca.org>
* [imran-iq](https://github.com/imran-iq) -
@@ -509,6 +509,8 @@ For more information about the governance of the Node.js project, see
**Vse Mozhet Byt** <vsemozhetbyt@gmail.com> (he/him)
* [watilde](https://github.com/watilde) -
**Daijiro Wachi** <daijiro.wachi@gmail.com> (he/him)
+* [watson](https://github.com/watson) -
+**Thomas Watson** <w@tson.dk>
* [whitlockjc](https://github.com/whitlockjc) -
**Jeremy Whitlock** <jwhitlock@apache.org>
* [XadillaX](https://github.com/XadillaX) -
diff --git a/benchmark/assert/throws.js b/benchmark/assert/throws.js
index bffde7cbc1fd94..2409d19206e353 100644
--- a/benchmark/assert/throws.js
+++ b/benchmark/assert/throws.js
@@ -26,6 +26,7 @@ function main({ n, method }) {
case 'doesNotThrow':
bench.start();
for (i = 0; i < n; ++i) {
+ // eslint-disable-next-line no-restricted-syntax
assert.doesNotThrow(doesNotThrow);
}
bench.end(n);
diff --git a/benchmark/http/_chunky_http_client.js b/benchmark/http/_chunky_http_client.js
index a90535e489f4c9..7728a5d06c60aa 100644
--- a/benchmark/http/_chunky_http_client.js
+++ b/benchmark/http/_chunky_http_client.js
@@ -5,8 +5,8 @@ const common = require('../common.js');
const net = require('net');
const bench = common.createBenchmark(main, {
- len: [1, 4, 8, 16, 32, 64, 128],
- n: [5, 50, 500, 2000],
+ len: [1, 4, 8, 16, 32, 64, 128],
+ n: [5, 50, 500, 2000],
type: ['send'],
});
diff --git a/benchmark/querystring/querystring-stringify.js b/benchmark/querystring/querystring-stringify.js
index cd1debd4df622d..9f025c922ad4e8 100644
--- a/benchmark/querystring/querystring-stringify.js
+++ b/benchmark/querystring/querystring-stringify.js
@@ -17,7 +17,7 @@ function main({ type, n }) {
encodemany: {
'\u0080\u0083\u0089': 'bar',
'\u008C\u008E\u0099': 'quux',
- xyzzy: '\u00A5q\u00A3r'
+ 'xyzzy': '\u00A5q\u00A3r'
},
encodelast: {
foo: 'bar',
diff --git a/benchmark/tls/tls-connect.js b/benchmark/tls/tls-connect.js
index da0f5e08d5e6db..524d7468d000a1 100644
--- a/benchmark/tls/tls-connect.js
+++ b/benchmark/tls/tls-connect.js
@@ -1,7 +1,7 @@
'use strict';
-var fs = require('fs'),
- path = require('path'),
- tls = require('tls');
+const fs = require('fs');
+const path = require('path');
+const tls = require('tls');
const common = require('../common.js');
const bench = common.createBenchmark(main, {
diff --git a/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js b/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js
index e915ceb54f917f..6b054d0b2a1f1a 100644
--- a/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js
+++ b/benchmark/url/legacy-vs-whatwg-url-searchparams-parse.js
@@ -2,10 +2,10 @@
const common = require('../common.js');
const { URLSearchParams } = require('url');
const querystring = require('querystring');
-const inputs = require('../fixtures/url-inputs.js').searchParams;
+const searchParams = require('../fixtures/url-inputs.js').searchParams;
const bench = common.createBenchmark(main, {
- type: Object.keys(inputs),
+ searchParam: Object.keys(searchParams),
method: ['legacy', 'whatwg'],
n: [1e6]
});
@@ -19,27 +19,27 @@ function useLegacy(n, input) {
bench.end(n);
}
-function useWHATWG(n, input) {
- new URLSearchParams(input);
+function useWHATWG(n, param) {
+ new URLSearchParams(param);
bench.start();
for (var i = 0; i < n; i += 1) {
- new URLSearchParams(input);
+ new URLSearchParams(param);
}
bench.end(n);
}
-function main({ type, n, method }) {
- const input = inputs[type];
- if (!input) {
- throw new Error(`Unknown input type "${type}"`);
+function main({ searchParam, n, method }) {
+ const param = searchParams[searchParam];
+ if (!param) {
+ throw new Error(`Unknown search parameter type "${searchParam}"`);
}
switch (method) {
case 'legacy':
- useLegacy(n, input);
+ useLegacy(n, param);
break;
case 'whatwg':
- useWHATWG(n, input);
+ useWHATWG(n, param);
break;
default:
throw new Error(`Unknown method ${method}`);
diff --git a/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js b/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js
index 8fe3e546f0780d..54fdd956544886 100644
--- a/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js
+++ b/benchmark/url/legacy-vs-whatwg-url-searchparams-serialize.js
@@ -2,10 +2,10 @@
const common = require('../common.js');
const { URLSearchParams } = require('url');
const querystring = require('querystring');
-const inputs = require('../fixtures/url-inputs.js').searchParams;
+const searchParams = require('../fixtures/url-inputs.js').searchParams;
const bench = common.createBenchmark(main, {
- type: Object.keys(inputs),
+ searchParam: Object.keys(searchParams),
method: ['legacy', 'whatwg'],
n: [1e6]
});
@@ -20,8 +20,8 @@ function useLegacy(n, input, prop) {
bench.end(n);
}
-function useWHATWG(n, input, prop) {
- const obj = new URLSearchParams(input);
+function useWHATWG(n, param, prop) {
+ const obj = new URLSearchParams(param);
obj.toString();
bench.start();
for (var i = 0; i < n; i += 1) {
@@ -30,18 +30,18 @@ function useWHATWG(n, input, prop) {
bench.end(n);
}
-function main({ type, n, method }) {
- const input = inputs[type];
- if (!input) {
- throw new Error(`Unknown input type "${type}"`);
+function main({ searchParam, n, method }) {
+ const param = searchParams[searchParam];
+ if (!param) {
+ throw new Error(`Unknown search parameter type "${searchParam}"`);
}
switch (method) {
case 'legacy':
- useLegacy(n, input);
+ useLegacy(n, param);
break;
case 'whatwg':
- useWHATWG(n, input);
+ useWHATWG(n, param);
break;
default:
throw new Error(`Unknown method ${method}`);
diff --git a/benchmark/url/url-searchparams-iteration.js b/benchmark/url/url-searchparams-iteration.js
index cae2ef5df61956..244c95502bfffb 100644
--- a/benchmark/url/url-searchparams-iteration.js
+++ b/benchmark/url/url-searchparams-iteration.js
@@ -4,7 +4,7 @@ const assert = require('assert');
const { URLSearchParams } = require('url');
const bench = common.createBenchmark(main, {
- method: ['forEach', 'iterator'],
+ loopMethod: ['forEach', 'iterator'],
n: [1e6]
});
@@ -44,8 +44,8 @@ function iterator(n) {
assert.strictEqual(noDead[1], '3rd');
}
-function main({ method, n }) {
- switch (method) {
+function main({ loopMethod, n }) {
+ switch (loopMethod) {
case 'forEach':
forEach(n);
break;
@@ -53,6 +53,6 @@ function main({ method, n }) {
iterator(n);
break;
default:
- throw new Error(`Unknown method ${method}`);
+ throw new Error(`Unknown method ${loopMethod}`);
}
}
diff --git a/benchmark/url/url-searchparams-read.js b/benchmark/url/url-searchparams-read.js
index 0cf66dabbc36dc..2eb0a4f21350dc 100644
--- a/benchmark/url/url-searchparams-read.js
+++ b/benchmark/url/url-searchparams-read.js
@@ -3,21 +3,20 @@ const common = require('../common.js');
const { URLSearchParams } = require('url');
const bench = common.createBenchmark(main, {
- method: ['get', 'getAll', 'has'],
+ accessMethod: ['get', 'getAll', 'has'],
param: ['one', 'two', 'three', 'nonexistent'],
n: [2e7]
});
const str = 'one=single&two=first&three=first&two=2nd&three=2nd&three=3rd';
-function main({ method, param, n }) {
+function main({ accessMethod, param, n }) {
const params = new URLSearchParams(str);
- const fn = params[method];
- if (!fn)
- throw new Error(`Unknown method ${method}`);
+ if (!params[accessMethod])
+ throw new Error(`Unknown method ${accessMethod}`);
bench.start();
for (var i = 0; i < n; i += 1)
- fn(param);
+ params[accessMethod](param);
bench.end(n);
}
diff --git a/benchmark/url/whatwg-url-idna.js b/benchmark/url/whatwg-url-idna.js
index c1e3d4a0b85cec..b67a08da7a88e0 100644
--- a/benchmark/url/whatwg-url-idna.js
+++ b/benchmark/url/whatwg-url-idna.js
@@ -2,7 +2,7 @@
const common = require('../common.js');
const { domainToASCII, domainToUnicode } = require('url');
-const inputs = {
+const domains = {
empty: {
ascii: '',
unicode: ''
@@ -26,13 +26,13 @@ const inputs = {
};
const bench = common.createBenchmark(main, {
- input: Object.keys(inputs),
+ domain: Object.keys(domains),
to: ['ascii', 'unicode'],
n: [5e6]
});
-function main({ n, to, input }) {
- const value = inputs[input][to];
+function main({ n, to, domain }) {
+ const value = domains[domain][to];
const method = to === 'ascii' ? domainToASCII : domainToUnicode;
bench.start();
diff --git a/common.gypi b/common.gypi
index aaae133e1ac188..5a5409cb0c610f 100644
--- a/common.gypi
+++ b/common.gypi
@@ -27,7 +27,7 @@
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
- 'v8_embedder_string': '-node.21',
+ 'v8_embedder_string': '-node.22',
# Enable disassembler for `--print-code` v8 options
'v8_enable_disassembler': 1,
diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc
index 93a21a7b3adf5c..21b36ba49c9149 100644
--- a/deps/v8/src/deoptimizer.cc
+++ b/deps/v8/src/deoptimizer.cc
@@ -144,6 +144,50 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
generator.Generate();
}
+namespace {
+class ActivationsFinder : public ThreadVisitor {
+ public:
+ explicit ActivationsFinder(std::set* codes,
+ Code* topmost_optimized_code,
+ bool safe_to_deopt_topmost_optimized_code)
+ : codes_(codes) {
+#ifdef DEBUG
+ topmost_ = topmost_optimized_code;
+ safe_to_deopt_ = safe_to_deopt_topmost_optimized_code;
+#endif
+ }
+
+ // Find the frames with activations of codes marked for deoptimization, search
+ // for the trampoline to the deoptimizer call respective to each code, and use
+ // it to replace the current pc on the stack.
+ void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
+ for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
+ if (it.frame()->type() == StackFrame::OPTIMIZED) {
+ Code* code = it.frame()->LookupCode();
+ if (code->kind() == Code::OPTIMIZED_FUNCTION &&
+ code->marked_for_deoptimization()) {
+ codes_->erase(code);
+ // Obtain the trampoline to the deoptimizer call.
+ SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
+ int trampoline_pc = safepoint.trampoline_pc();
+ DCHECK_IMPLIES(code == topmost_, safe_to_deopt_);
+ // Replace the current pc on the stack with the trampoline.
+ it.frame()->set_pc(code->instruction_start() + trampoline_pc);
+ }
+ }
+ }
+ }
+
+ private:
+ std::set* codes_;
+
+#ifdef DEBUG
+ Code* topmost_;
+ bool safe_to_deopt_;
+#endif
+};
+} // namespace
+
void Deoptimizer::VisitAllOptimizedFunctionsForContext(
Context* context, OptimizedFunctionVisitor* visitor) {
DisallowHeapAllocation no_allocation;
@@ -264,9 +308,9 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
VisitAllOptimizedFunctionsForContext(context, &unlinker);
Isolate* isolate = context->GetHeap()->isolate();
-#ifdef DEBUG
Code* topmost_optimized_code = NULL;
bool safe_to_deopt_topmost_optimized_code = false;
+#ifdef DEBUG
// Make sure all activations of optimized code can deopt at their current PC.
// The topmost optimized code has special handling because it cannot be
// deoptimized due to weak object dependency.
@@ -304,6 +348,10 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
}
#endif
+ // We will use this set to mark those Code objects that are marked for
+ // deoptimization and have not been found in stack frames.
+ std::set codes;
+
// Move marked code from the optimized code list to the deoptimized
// code list.
// Walk over all optimized code objects in this native context.
@@ -335,25 +383,14 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
element = next;
}
- // Finds the with activations of codes marked for deoptimization, search for
- // the trampoline to the deoptimizer call respective to each code, and use it
- // to replace the current pc on the stack.
- for (StackFrameIterator it(isolate, isolate->thread_local_top()); !it.done();
- it.Advance()) {
- if (it.frame()->type() == StackFrame::OPTIMIZED) {
- Code* code = it.frame()->LookupCode();
- if (code->kind() == Code::OPTIMIZED_FUNCTION &&
- code->marked_for_deoptimization()) {
- // Obtain the trampoline to the deoptimizer call.
- SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
- int trampoline_pc = safepoint.trampoline_pc();
- DCHECK_IMPLIES(code == topmost_optimized_code,
- safe_to_deopt_topmost_optimized_code);
- // Replace the current pc on the stack with the trampoline.
- it.frame()->set_pc(code->instruction_start() + trampoline_pc);
- }
- }
- }
+ ActivationsFinder visitor(&codes, topmost_optimized_code,
+ safe_to_deopt_topmost_optimized_code);
+ // Iterate over the stack of this thread.
+ visitor.VisitThread(isolate, isolate->thread_local_top());
+ // In addition to iterate over the stack of this thread, we also
+ // need to consider all the other threads as they may also use
+ // the code currently beings deoptimized.
+ isolate->thread_manager()->IterateArchivedThreads(&visitor);
}
diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc
index 80d488f12c527f..1be42952d795a5 100644
--- a/deps/v8/src/profiler/cpu-profiler.cc
+++ b/deps/v8/src/profiler/cpu-profiler.cc
@@ -162,13 +162,16 @@ void ProfilerEventsProcessor::Run() {
if (nextSampleTime > now) {
#if V8_OS_WIN
- // Do not use Sleep on Windows as it is very imprecise.
- // Could be up to 16ms jitter, which is unacceptable for the purpose.
- while (base::TimeTicks::HighResolutionNow() < nextSampleTime) {
- }
-#else
- base::OS::Sleep(nextSampleTime - now);
+ if (nextSampleTime - now < base::TimeDelta::FromMilliseconds(100)) {
+ // Do not use Sleep on Windows as it is very imprecise, with up to 16ms
+ // jitter, which is unacceptable for short profile intervals.
+ while (base::TimeTicks::HighResolutionNow() < nextSampleTime) {
+ }
+ } else // NOLINT
#endif
+ {
+ base::OS::Sleep(nextSampleTime - now);
+ }
}
// Schedule next sample. sampler_ is NULL in tests.
diff --git a/deps/v8/test/cctest/test-lockers.cc b/deps/v8/test/cctest/test-lockers.cc
index a310bfd68456c4..36a9f11ee27773 100644
--- a/deps/v8/test/cctest/test-lockers.cc
+++ b/deps/v8/test/cctest/test-lockers.cc
@@ -55,6 +55,244 @@ using ::v8::Value;
using ::v8::V8;
+namespace {
+
+class DeoptimizeCodeThread : public v8::base::Thread {
+ public:
+ DeoptimizeCodeThread(v8::Isolate* isolate, v8::Local context,
+ const char* trigger)
+ : Thread(Options("DeoptimizeCodeThread")),
+ isolate_(isolate),
+ context_(isolate, context),
+ source_(trigger) {}
+
+ void Run() {
+ v8::Locker locker(isolate_);
+ isolate_->Enter();
+ v8::HandleScope handle_scope(isolate_);
+ v8::Local context =
+ v8::Local::New(isolate_, context_);
+ v8::Context::Scope context_scope(context);
+ CHECK_EQ(isolate_, v8::Isolate::GetCurrent());
+ // This code triggers deoptimization of some function that will be
+ // used in a different thread.
+ CompileRun(source_);
+ isolate_->Exit();
+ }
+
+ private:
+ v8::Isolate* isolate_;
+ Persistent context_;
+ // The code that triggers the deoptimization.
+ const char* source_;
+};
+
+void UnlockForDeoptimization(const v8::FunctionCallbackInfo& args) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ // Gets the pointer to the thread that will trigger the deoptimization of the
+ // code.
+ DeoptimizeCodeThread* deoptimizer =
+ reinterpret_cast(isolate->GetData(0));
+ {
+ // Exits and unlocks the isolate.
+ isolate->Exit();
+ v8::Unlocker unlocker(isolate);
+ // Starts the deoptimizing thread.
+ deoptimizer->Start();
+ // Waits for deoptimization to finish.
+ deoptimizer->Join();
+ }
+ // The deoptimizing thread has finished its work, and the isolate
+ // will now be used by the current thread.
+ isolate->Enter();
+}
+
+void UnlockForDeoptimizationIfReady(
+ const v8::FunctionCallbackInfo& args) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ bool* ready_to_deoptimize = reinterpret_cast(isolate->GetData(1));
+ if (*ready_to_deoptimize) {
+ // The test should enter here only once, so put the flag back to false.
+ *ready_to_deoptimize = false;
+ // Gets the pointer to the thread that will trigger the deoptimization of
+ // the code.
+ DeoptimizeCodeThread* deoptimizer =
+ reinterpret_cast(isolate->GetData(0));
+ {
+ // Exits and unlocks the thread.
+ isolate->Exit();
+ v8::Unlocker unlocker(isolate);
+ // Starts the thread that deoptimizes the function.
+ deoptimizer->Start();
+ // Waits for the deoptimizing thread to finish.
+ deoptimizer->Join();
+ }
+ // The deoptimizing thread has finished its work, and the isolate
+ // will now be used by the current thread.
+ isolate->Enter();
+ }
+}
+} // namespace
+
+TEST(LazyDeoptimizationMultithread) {
+ i::FLAG_allow_natives_syntax = true;
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
+ {
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope scope(isolate);
+ v8::Local context = v8::Context::New(isolate);
+ const char* trigger_deopt = "obj = { y: 0, x: 1 };";
+
+ // We use the isolate to pass arguments to the UnlockForDeoptimization
+ // function. Namely, we pass a pointer to the deoptimizing thread.
+ DeoptimizeCodeThread deoptimize_thread(isolate, context, trigger_deopt);
+ isolate->SetData(0, &deoptimize_thread);
+ v8::Context::Scope context_scope(context);
+
+ // Create the function templace for C++ code that is invoked from
+ // JavaScript code.
+ Local fun_templ =
+ v8::FunctionTemplate::New(isolate, UnlockForDeoptimization);
+ Local fun = fun_templ->GetFunction(context).ToLocalChecked();
+ CHECK(context->Global()
+ ->Set(context, v8_str("unlock_for_deoptimization"), fun)
+ .FromJust());
+
+ // Optimizes a function f, which will be deoptimized in another
+ // thread.
+ CompileRun(
+ "var b = false; var obj = { x: 1 };"
+ "function f() { g(); return obj.x; }"
+ "function g() { if (b) { unlock_for_deoptimization(); } }"
+ "%NeverOptimizeFunction(g);"
+ "f(); f(); %OptimizeFunctionOnNextCall(f);"
+ "f();");
+
+ // Trigger the unlocking.
+ Local v = CompileRun("b = true; f();");
+
+ // Once the isolate has been unlocked, the thread will wait for the
+ // other thread to finish its task. Once this happens, this thread
+ // continues with its execution, that is, with the execution of the
+ // function g, which then returns to f. The function f should have
+ // also been deoptimized. If the replacement did not happen on this
+ // thread's stack, then the test will fail here.
+ CHECK(v->IsNumber());
+ CHECK_EQ(1, static_cast(v->NumberValue(context).FromJust()));
+ }
+ isolate->Dispose();
+}
+
+TEST(LazyDeoptimizationMultithreadWithNatives) {
+ i::FLAG_allow_natives_syntax = true;
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
+ {
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope scope(isolate);
+ v8::Local context = v8::Context::New(isolate);
+ const char* trigger_deopt = "%DeoptimizeFunction(f);";
+
+ // We use the isolate to pass arguments to the UnlockForDeoptimization
+ // function. Namely, we pass a pointer to the deoptimizing thread.
+ DeoptimizeCodeThread deoptimize_thread(isolate, context, trigger_deopt);
+ isolate->SetData(0, &deoptimize_thread);
+ bool ready_to_deopt = false;
+ isolate->SetData(1, &ready_to_deopt);
+ v8::Context::Scope context_scope(context);
+
+ // Create the function templace for C++ code that is invoked from
+ // JavaScript code.
+ Local fun_templ =
+ v8::FunctionTemplate::New(isolate, UnlockForDeoptimizationIfReady);
+ Local fun = fun_templ->GetFunction(context).ToLocalChecked();
+ CHECK(context->Global()
+ ->Set(context, v8_str("unlock_for_deoptimization"), fun)
+ .FromJust());
+
+ // Optimizes a function f, which will be deoptimized in another
+ // thread.
+ CompileRun(
+ "var obj = { x: 1 };"
+ "function f() { g(); return obj.x;}"
+ "function g() { "
+ " unlock_for_deoptimization(); }"
+ "%NeverOptimizeFunction(g);"
+ "f(); f(); %OptimizeFunctionOnNextCall(f);");
+
+ // Trigger the unlocking.
+ ready_to_deopt = true;
+ isolate->SetData(1, &ready_to_deopt);
+ Local v = CompileRun("f();");
+
+ // Once the isolate has been unlocked, the thread will wait for the
+ // other thread to finish its task. Once this happens, this thread
+ // continues with its execution, that is, with the execution of the
+ // function g, which then returns to f. The function f should have
+ // also been deoptimized. Otherwise, the test will fail here.
+ CHECK(v->IsNumber());
+ CHECK_EQ(1, static_cast(v->NumberValue(context).FromJust()));
+ }
+ isolate->Dispose();
+}
+
+TEST(EagerDeoptimizationMultithread) {
+ i::FLAG_allow_natives_syntax = true;
+ v8::Isolate::CreateParams create_params;
+ create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+ v8::Isolate* isolate = v8::Isolate::New(create_params);
+ {
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope scope(isolate);
+ v8::Local context = v8::Context::New(isolate);
+ const char* trigger_deopt = "f({y: 0, x: 1});";
+
+ // We use the isolate to pass arguments to the UnlockForDeoptimization
+ // function. Namely, we pass a pointer to the deoptimizing thread.
+ DeoptimizeCodeThread deoptimize_thread(isolate, context, trigger_deopt);
+ isolate->SetData(0, &deoptimize_thread);
+ bool ready_to_deopt = false;
+ isolate->SetData(1, &ready_to_deopt);
+ v8::Context::Scope context_scope(context);
+
+ // Create the function templace for C++ code that is invoked from
+ // JavaScript code.
+ Local fun_templ =
+ v8::FunctionTemplate::New(isolate, UnlockForDeoptimizationIfReady);
+ Local fun = fun_templ->GetFunction(context).ToLocalChecked();
+ CHECK(context->Global()
+ ->Set(context, v8_str("unlock_for_deoptimization"), fun)
+ .FromJust());
+
+ // Optimizes a function f, which will be deoptimized by another thread.
+ CompileRun(
+ "function f(obj) { unlock_for_deoptimization(); return obj.x; }"
+ "f({x: 1}); f({x: 1});"
+ "%OptimizeFunctionOnNextCall(f);"
+ "f({x: 1});");
+
+ // Trigger the unlocking.
+ ready_to_deopt = true;
+ isolate->SetData(1, &ready_to_deopt);
+ Local v = CompileRun("f({x: 1});");
+
+ // Once the isolate has been unlocked, the thread will wait for the
+ // other thread to finish its task. Once this happens, this thread
+ // continues with its execution, that is, with the execution of the
+ // function g, which then returns to f. The function f should have
+ // also been deoptimized. Otherwise, the test will fail here.
+ CHECK(v->IsNumber());
+ CHECK_EQ(1, static_cast(v->NumberValue(context).FromJust()));
+ }
+ isolate->Dispose();
+}
+
// Migrating an isolate
class KangarooThread : public v8::base::Thread {
public:
diff --git a/doc/.eslintrc.yaml b/doc/.eslintrc.yaml
index c8c1612e3a100b..7b38afec10276a 100644
--- a/doc/.eslintrc.yaml
+++ b/doc/.eslintrc.yaml
@@ -12,6 +12,7 @@ rules:
no-var: error
prefer-const: error
prefer-rest-params: error
+ prefer-template: error
# Stylistic Issues
no-multiple-empty-lines: [error, {max: 1, maxEOF: 0, maxBOF: 0}]
diff --git a/doc/STYLE_GUIDE.md b/doc/STYLE_GUIDE.md
index 7fc2d6e0b1bb13..009b0ee2b5ec4b 100644
--- a/doc/STYLE_GUIDE.md
+++ b/doc/STYLE_GUIDE.md
@@ -13,12 +13,10 @@
* American English spelling is preferred. "Capitalize" vs. "Capitalise",
"color" vs. "colour", etc.
* Use [serial commas][].
-* Generally avoid personal pronouns in reference documentation ("I", "you",
- "we").
- * Pronouns are acceptable in more colloquial documentation, like guides.
- * Use gender-neutral pronouns and mass nouns. Non-comprehensive
- examples:
- * OK: "they", "their", "them", "folks", "people", "developers", "cats"
+* Avoid personal pronouns in reference documentation ("I", "you", "we").
+ * Personal pronouns are acceptable in colloquial documentation such as guides.
+ * Use gender-neutral pronouns and gender-neutral plural nouns.
+ * OK: "they", "their", "them", "folks", "people", "developers"
* NOT OK: "his", "hers", "him", "her", "guys", "dudes"
* When combining wrapping elements (parentheses and quotes), terminal
punctuation should be placed:
diff --git a/doc/api/assert.md b/doc/api/assert.md
index 6935a9db4bda64..2ecf628e4aa80a 100644
--- a/doc/api/assert.md
+++ b/doc/api/assert.md
@@ -7,6 +7,93 @@
The `assert` module provides a simple set of assertion tests that can be used to
test invariants.
+A `strict` and a `legacy` mode exist, while it is recommended to only use
+[`strict mode`][].
+
+For more information about the used equality comparisons see
+[MDN's guide on equality comparisons and sameness][mdn-equality-guide].
+
+## Strict mode
+
+
+When using the `strict mode`, any `assert` function will use the equality used in
+the strict function mode. So [`assert.deepEqual()`][] will, for example, work the
+same as [`assert.deepStrictEqual()`][].
+
+On top of that, error messages which involve objects produce an error diff
+instead of displaying both objects. That is not the case for the legacy mode.
+
+It can be accessed using:
+
+```js
+const assert = require('assert').strict;
+```
+
+Example error diff (the `expected`, `actual`, and `Lines skipped` will be on a
+single row):
+
+```js
+const assert = require('assert').strict;
+
+assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
+```
+
+```diff
+AssertionError [ERR_ASSERTION]: Input A expected to deepStrictEqual input B:
++ expected
+- actual
+... Lines skipped
+
+ [
+ [
+...
+ 2,
+- 3
++ '3'
+ ],
+...
+ 5
+ ]
+```
+
+To deactivate the colors, use the `NODE_DISABLE_COLORS` environment variable.
+Please note that this will also deactivate the colors in the REPL.
+
+## Legacy mode
+
+> Stability: 0 - Deprecated: Use strict mode instead.
+
+When accessing `assert` directly instead of using the `strict` property, the
+[Abstract Equality Comparison][] will be used for any function without a
+"strict" in its name (e.g. [`assert.deepEqual()`][]).
+
+It can be accessed using:
+
+```js
+const assert = require('assert');
+```
+
+It is recommended to use the [`strict mode`][] instead as the
+[Abstract Equality Comparison][] can often have surprising results. Especially
+in case of [`assert.deepEqual()`][] as the used comparison rules there are very
+lax.
+
+E.g.
+
+```js
+// WARNING: This does not throw an AssertionError!
+assert.deepEqual(/a/gi, new Date());
+```
+
## assert(value[, message])
```js
assert.doesNotThrow(
() => {
@@ -246,6 +359,7 @@ assert.doesNotThrow(
However, the following will result in an `AssertionError` with the message
'Got unwanted exception (TypeError)..':
+
```js
assert.doesNotThrow(
() => {
@@ -259,6 +373,7 @@ If an `AssertionError` is thrown and a value is provided for the `message`
parameter, the value of `message` will be appended to the `AssertionError`
message:
+
```js
assert.doesNotThrow(
() => {
@@ -278,6 +393,14 @@ added: v0.1.21
* `expected` {any}
* `message` {any}
+**Strict mode**
+
+An alias of [`assert.strictEqual()`][].
+
+**Legacy mode**
+
+> Stability: 0 - Deprecated: Use [`assert.strictEqual()`][] instead.
+
Tests shallow, coercive equality between the `actual` and `expected` parameters
using the [Abstract Equality Comparison][] ( `==` ).
@@ -298,7 +421,7 @@ assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
If the values are not equal, an `AssertionError` is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
-parameter is an instance of an `Error` then it will be thrown instead of the
+parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.
## assert.fail([message])
@@ -314,7 +437,7 @@ added: v0.1.21
Throws an `AssertionError`. If `message` is falsy, the error message is set as
the values of `actual` and `expected` separated by the provided `operator`. If
-the `message` parameter is an instance of an `Error` then it will be thrown
+the `message` parameter is an instance of an [`Error`][] then it will be thrown
instead of the `AssertionError`. If just the two `actual` and `expected`
arguments are provided, `operator` will default to `'!='`. If `message` is
provided only it will be used as the error message, the other arguments will be
@@ -324,7 +447,7 @@ all stack frames above that function will be removed from stacktrace (see
`Failed` will be used.
```js
-const assert = require('assert');
+const assert = require('assert').strict;
assert.fail(1, 2, undefined, '>');
// AssertionError [ERR_ASSERTION]: 1 > 2
@@ -375,7 +498,7 @@ Throws `value` if `value` is truthy. This is useful when testing the `error`
argument in callbacks.
```js
-const assert = require('assert');
+const assert = require('assert').strict;
assert.ifError(null);
// OK
@@ -413,6 +536,14 @@ changes:
* `expected` {any}
* `message` {any}
+**Strict mode**
+
+An alias of [`assert.notDeepStrictEqual()`][].
+
+**Legacy mode**
+
+> Stability: 0 - Deprecated: Use [`assert.notDeepStrictEqual()`][] instead.
+
Tests for any deep inequality. Opposite of [`assert.deepEqual()`][].
```js
@@ -451,7 +582,7 @@ assert.notDeepEqual(obj1, obj4);
If the values are deeply equal, an `AssertionError` is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
-parameter is an instance of an `Error` then it will be thrown instead of the
+parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.
## assert.notDeepStrictEqual(actual, expected[, message])
@@ -489,10 +620,7 @@ changes:
Tests for deep strict inequality. Opposite of [`assert.deepStrictEqual()`][].
```js
-const assert = require('assert');
-
-assert.notDeepEqual({ a: 1 }, { a: '1' });
-// AssertionError: { a: 1 } notDeepEqual { a: '1' }
+const assert = require('assert').strict;
assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// OK
@@ -501,8 +629,8 @@ assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
If the values are deeply and strictly equal, an `AssertionError` is thrown with
a `message` property set equal to the value of the `message` parameter. If the
`message` parameter is undefined, a default error message is assigned. If the
-`message` parameter is an instance of an `Error` then it will be thrown instead
-of the `AssertionError`.
+`message` parameter is an instance of an [`Error`][] then it will be thrown
+instead of the `AssertionError`.
## assert.notEqual(actual, expected[, message])
* `block` {Function}
-* `error` {RegExp|Function}
+* `error` {RegExp|Function|object}
* `message` {any}
Expects the function `block` to throw an error.
-If specified, `error` can be a constructor, [`RegExp`][], or validation
-function.
+If specified, `error` can be a constructor, [`RegExp`][], a validation
+function, or an object where each property will be tested for.
If specified, `message` will be the message provided by the `AssertionError` if
the block fails to throw.
@@ -658,12 +797,15 @@ assert.throws(
Validate error message using [`RegExp`][]:
+Using a regular expression runs `.toString` on the error object, and will
+therefore also include the error name.
+
```js
assert.throws(
() => {
throw new Error('Wrong value');
},
- /value/
+ /^Error: Wrong value$/
);
```
@@ -683,19 +825,61 @@ assert.throws(
);
```
+Custom error object / error instance:
+
+```js
+assert.throws(
+ () => {
+ const err = new TypeError('Wrong value');
+ err.code = 404;
+ throw err;
+ },
+ {
+ name: 'TypeError',
+ message: 'Wrong value'
+ // Note that only properties on the error object will be tested!
+ }
+);
+```
+
Note that `error` can not be a string. If a string is provided as the second
argument, then `error` is assumed to be omitted and the string will be used for
-`message` instead. This can lead to easy-to-miss mistakes:
+`message` instead. This can lead to easy-to-miss mistakes. Please read the
+example below carefully if using a string as the second argument gets
+considered:
```js
-// THIS IS A MISTAKE! DO NOT DO THIS!
-assert.throws(myFunction, 'missing foo', 'did not throw with expected message');
-
-// Do this instead.
-assert.throws(myFunction, /missing foo/, 'did not throw with expected message');
+function throwingFirst() {
+ throw new Error('First');
+}
+function throwingSecond() {
+ throw new Error('Second');
+}
+function notThrowing() {}
+
+// The second argument is a string and the input function threw an Error.
+// In that case both cases do not throw as neither is going to try to
+// match for the error message thrown by the input function!
+assert.throws(throwingFirst, 'Second');
+assert.throws(throwingSecond, 'Second');
+
+// The string is only used (as message) in case the function does not throw:
+assert.throws(notThrowing, 'Second');
+// AssertionError [ERR_ASSERTION]: Missing expected exception: Second
+
+// If it was intended to match for the error message do this instead:
+assert.throws(throwingSecond, /Second$/);
+// Does not throw because the error messages match.
+assert.throws(throwingFirst, /Second$/);
+// Throws a error:
+// Error: First
+// at throwingFirst (repl:2:9)
```
+Due to the confusing notation, it is recommended not to use a string as the
+second argument. This might lead to difficult-to-spot errors.
+
## Caveats
For the following cases, consider using ES2015 [`Object.is()`][],
@@ -729,15 +913,21 @@ For more information, see
[`Set`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
[`Symbol`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
[`TypeError`]: errors.html#errors_class_typeerror
+[`WeakMap`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
+[`WeakSet`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/WeakSet
[`assert.deepEqual()`]: #assert_assert_deepequal_actual_expected_message
[`assert.deepStrictEqual()`]: #assert_assert_deepstrictequal_actual_expected_message
+[`assert.notDeepStrictEqual()`]: #assert_assert_notdeepstrictequal_actual_expected_message
+[`assert.notStrictEqual()`]: #assert_assert_notstrictequal_actual_expected_message
[`assert.ok()`]: #assert_assert_ok_value_message
+[`assert.strictEqual()`]: #assert_assert_strictequal_actual_expected_message
[`assert.throws()`]: #assert_assert_throws_block_error_message
+[`strict mode`]: #assert_strict_mode
[Abstract Equality Comparison]: https://tc39.github.io/ecma262/#sec-abstract-equality-comparison
[Object.prototype.toString()]: https://tc39.github.io/ecma262/#sec-object.prototype.tostring
[SameValueZero]: https://tc39.github.io/ecma262/#sec-samevaluezero
+[SameValue Comparison]: https://tc39.github.io/ecma262/#sec-samevalue
[Strict Equality Comparison]: https://tc39.github.io/ecma262/#sec-strict-equality-comparison
-[caveats]: #assert_caveats
[enumerable "own" properties]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
[mdn-equality-guide]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
[prototype-spec]: https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots
diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md
index 15bdf56e365de9..1a162a038a6831 100644
--- a/doc/api/async_hooks.md
+++ b/doc/api/async_hooks.md
@@ -147,10 +147,10 @@ unintentional side effects.
Because printing to the console is an asynchronous operation, `console.log()`
will cause the AsyncHooks callbacks to be called. Using `console.log()` or
similar asynchronous operations inside an AsyncHooks callback function will thus
-cause an infinite recursion. An easily solution to this when debugging is
-to use a synchronous logging operation such as `fs.writeSync(1, msg)`. This
-will print to stdout because `1` is the file descriptor for stdout and will
-not invoke AsyncHooks recursively because it is synchronous.
+cause an infinite recursion. An easy solution to this when debugging is to use a
+synchronous logging operation such as `fs.writeSync(1, msg)`. This will print to
+stdout because `1` is the file descriptor for stdout and will not invoke
+AsyncHooks recursively because it is synchronous.
```js
const fs = require('fs');
@@ -587,8 +587,8 @@ JavaScript API so that all the appropriate callbacks are called.
### `class AsyncResource()`
-The class `AsyncResource` was designed to be extended by the embedder's async
-resources. Using this users can easily trigger the lifetime events of their
+The class `AsyncResource` is designed to be extended by the embedder's async
+resources. Using this, users can easily trigger the lifetime events of their
own resources.
The `init` hook will trigger when an `AsyncResource` is instantiated.
diff --git a/doc/api/buffer.md b/doc/api/buffer.md
index 2b0ce95afa2f76..da46fa7c2e4341 100644
--- a/doc/api/buffer.md
+++ b/doc/api/buffer.md
@@ -22,8 +22,6 @@ resized.
The `Buffer` class is a global within Node.js, making it unlikely that one
would need to ever use `require('buffer').Buffer`.
-Examples:
-
```js
// Creates a zero-filled Buffer of length 10.
const buf1 = Buffer.alloc(10);
@@ -163,11 +161,10 @@ Example:
```js
const buf = Buffer.from('hello world', 'ascii');
-// Prints: 68656c6c6f20776f726c64
console.log(buf.toString('hex'));
-
-// Prints: aGVsbG8gd29ybGQ=
+// Prints: 68656c6c6f20776f726c64
console.log(buf.toString('base64'));
+// Prints: aGVsbG8gd29ybGQ=
```
The character encodings currently supported by Node.js include:
@@ -241,23 +238,20 @@ arr[1] = 4000;
// Copies the contents of `arr`
const buf1 = Buffer.from(arr);
-
// Shares memory with `arr`
const buf2 = Buffer.from(arr.buffer);
-// Prints:
console.log(buf1);
-
-// Prints:
+// Prints:
console.log(buf2);
+// Prints:
arr[1] = 6000;
-// Prints:
console.log(buf1);
-
-// Prints:
+// Prints:
console.log(buf2);
+// Prints:
```
Note that when creating a `Buffer` using a [`TypedArray`]'s `.buffer`, it is
@@ -270,8 +264,8 @@ Example:
const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);
-// Prints: 16
console.log(buf.length);
+// Prints: 16
```
The `Buffer.from()` and [`TypedArray.from()`] have different signatures and
@@ -386,14 +380,14 @@ arr[1] = 4000;
// Shares memory with `arr`
const buf = new Buffer(arr.buffer);
-// Prints:
console.log(buf);
+// Prints:
// Changing the original Uint16Array changes the Buffer also
arr[1] = 6000;
-// Prints:
console.log(buf);
+// Prints:
```
### new Buffer(buffer)
@@ -422,11 +416,10 @@ const buf2 = new Buffer(buf1);
buf1[0] = 0x61;
-// Prints: auffer
console.log(buf1.toString());
-
-// Prints: buffer
+// Prints: auffer
console.log(buf2.toString());
+// Prints: buffer
```
### new Buffer(size)
@@ -464,8 +457,8 @@ Example:
```js
const buf = new Buffer(10);
-// Prints:
console.log(buf);
+// Prints:
```
### new Buffer(string[, encoding])
@@ -489,21 +482,16 @@ changes:
Creates a new `Buffer` containing the given JavaScript string `string`. If
provided, the `encoding` parameter identifies the character encoding of `string`.
-Examples:
-
```js
const buf1 = new Buffer('this is a tést');
-
-// Prints: this is a tést
-console.log(buf1.toString());
-
-// Prints: this is a tC)st
-console.log(buf1.toString('ascii'));
-
const buf2 = new Buffer('7468697320697320612074c3a97374', 'hex');
+console.log(buf1.toString());
// Prints: this is a tést
console.log(buf2.toString());
+// Prints: this is a tést
+console.log(buf1.toString('ascii'));
+// Prints: this is a tC)st
```
### Class Method: Buffer.alloc(size[, fill[, encoding]])
@@ -530,8 +518,8 @@ Example:
```js
const buf = Buffer.alloc(5);
-// Prints:
console.log(buf);
+// Prints:
```
Allocates a new `Buffer` of `size` bytes. If the `size` is larger than
@@ -546,8 +534,8 @@ Example:
```js
const buf = Buffer.alloc(5, 'a');
-// Prints:
console.log(buf);
+// Prints:
```
If both `fill` and `encoding` are specified, the allocated `Buffer` will be
@@ -558,8 +546,8 @@ Example:
```js
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
-// Prints:
console.log(buf);
+// Prints:
```
Calling [`Buffer.alloc()`] can be significantly slower than the alternative
@@ -593,13 +581,13 @@ Example:
```js
const buf = Buffer.allocUnsafe(10);
-// Prints: (contents may vary):
console.log(buf);
+// Prints: (contents may vary):
buf.fill(0);
-// Prints:
console.log(buf);
+// Prints:
```
A `TypeError` will be thrown if `size` is not a number.
@@ -702,9 +690,9 @@ Example:
```js
const str = '\u00bd + \u00bc = \u00be';
-// Prints: ½ + ¼ = ¾: 9 characters, 12 bytes
console.log(`${str}: ${str.length} characters, ` +
`${Buffer.byteLength(str, 'utf8')} bytes`);
+// Prints: ½ + ¼ = ¾: 9 characters, 12 bytes
```
When `string` is a `Buffer`/[`DataView`]/[`TypedArray`]/[`ArrayBuffer`]/
@@ -734,9 +722,9 @@ const buf1 = Buffer.from('1234');
const buf2 = Buffer.from('0123');
const arr = [buf1, buf2];
+console.log(arr.sort(Buffer.compare));
// Prints: [ , ]
// (This result is equal to: [buf2, buf1])
-console.log(arr.sort(Buffer.compare));
```
### Class Method: Buffer.concat(list[, totalLength])
@@ -776,16 +764,15 @@ const buf2 = Buffer.alloc(14);
const buf3 = Buffer.alloc(18);
const totalLength = buf1.length + buf2.length + buf3.length;
-// Prints: 42
console.log(totalLength);
+// Prints: 42
const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
-// Prints:
console.log(bufA);
-
-// Prints: 42
+// Prints:
console.log(bufA.length);
+// Prints: 42
```
### Class Method: Buffer.from(array)
@@ -833,14 +820,14 @@ arr[1] = 4000;
// Shares memory with `arr`
const buf = Buffer.from(arr.buffer);
-// Prints:
console.log(buf);
+// Prints:
// Changing the original Uint16Array changes the Buffer also
arr[1] = 6000;
-// Prints:
console.log(buf);
+// Prints:
```
The optional `byteOffset` and `length` arguments specify a memory range within
@@ -852,8 +839,8 @@ Example:
const ab = new ArrayBuffer(10);
const buf = Buffer.from(ab, 0, 2);
-// Prints: 2
console.log(buf.length);
+// Prints: 2
```
A `TypeError` will be thrown if `arrayBuffer` is not an [`ArrayBuffer`] or a
@@ -876,11 +863,10 @@ const buf2 = Buffer.from(buf1);
buf1[0] = 0x61;
-// Prints: auffer
console.log(buf1.toString());
-
-// Prints: buffer
+// Prints: auffer
console.log(buf2.toString());
+// Prints: buffer
```
A `TypeError` will be thrown if `buffer` is not a `Buffer`.
@@ -896,21 +882,16 @@ added: v5.10.0
Creates a new `Buffer` containing the given JavaScript string `string`. If
provided, the `encoding` parameter identifies the character encoding of `string`.
-Examples:
-
```js
const buf1 = Buffer.from('this is a tést');
-
-// Prints: this is a tést
-console.log(buf1.toString());
-
-// Prints: this is a tC)st
-console.log(buf1.toString('ascii'));
-
const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
+console.log(buf1.toString());
// Prints: this is a tést
console.log(buf2.toString());
+// Prints: this is a tést
+console.log(buf1.toString('ascii'));
+// Prints: this is a tC)st
```
A `TypeError` will be thrown if `string` is not a string.
@@ -932,7 +913,7 @@ For objects whose `valueOf()` function returns a value not strictly equal to
```js
const buf = Buffer.from(new String('this is a test'));
-//
+// Prints:
```
For objects that support `Symbol.toPrimitive`, returns
@@ -946,7 +927,7 @@ class Foo {
}
const buf = Buffer.from(new Foo(), 'utf8');
-//
+// Prints:
```
### Class Method: Buffer.isBuffer(obj)
@@ -1004,8 +985,8 @@ for (let i = 0; i < str.length; i++) {
buf[i] = str.charCodeAt(i);
}
-// Prints: Node.js
console.log(buf.toString('ascii'));
+// Prints: Node.js
```
### buf.buffer
@@ -1052,51 +1033,40 @@ Comparison is based on the actual sequence of bytes in each `Buffer`.
* `1` is returned if `target` should come *before* `buf` when sorted.
* `-1` is returned if `target` should come *after* `buf` when sorted.
-Examples:
-
```js
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('BCD');
const buf3 = Buffer.from('ABCD');
-// Prints: 0
console.log(buf1.compare(buf1));
-
-// Prints: -1
+// Prints: 0
console.log(buf1.compare(buf2));
-
// Prints: -1
console.log(buf1.compare(buf3));
-
-// Prints: 1
+// Prints: -1
console.log(buf2.compare(buf1));
-
// Prints: 1
console.log(buf2.compare(buf3));
-
+// Prints: 1
+console.log([buf1, buf2, buf3].sort(Buffer.compare));
// Prints: [ , , ]
// (This result is equal to: [buf1, buf3, buf2])
-console.log([buf1, buf2, buf3].sort(Buffer.compare));
```
The optional `targetStart`, `targetEnd`, `sourceStart`, and `sourceEnd`
arguments can be used to limit the comparison to specific ranges within `target`
and `buf` respectively.
-Examples:
-
```js
const buf1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
const buf2 = Buffer.from([5, 6, 7, 8, 9, 1, 2, 3, 4]);
-// Prints: 0
console.log(buf1.compare(buf2, 5, 9, 0, 4));
-
-// Prints: -1
+// Prints: 0
console.log(buf1.compare(buf2, 0, 6, 4));
-
-// Prints: 1
+// Prints: -1
console.log(buf1.compare(buf2, 5, 6, 5));
+// Prints: 1
```
A `RangeError` will be thrown if: `targetStart < 0`, `sourceStart < 0`,
@@ -1133,8 +1103,8 @@ for (let i = 0; i < 26; i++) {
buf1.copy(buf2, 8, 16, 20);
-// Prints: !!!!!!!!qrst!!!!!!!!!!!!!
console.log(buf2.toString('ascii', 0, 25));
+// Prints: !!!!!!!!qrst!!!!!!!!!!!!!
```
Example: Create a single `Buffer` and copy data from one region to an
@@ -1150,8 +1120,8 @@ for (let i = 0; i < 26; i++) {
buf.copy(buf, 0, 4, 10);
-// Prints: efghijghijklmnopqrstuvwxyz
console.log(buf.toString());
+// Prints: efghijghijklmnopqrstuvwxyz
```
### buf.entries()
@@ -1169,6 +1139,9 @@ Example: Log the entire contents of a `Buffer`
```js
const buf = Buffer.from('buffer');
+for (const pair of buf.entries()) {
+ console.log(pair);
+}
// Prints:
// [0, 98]
// [1, 117]
@@ -1176,9 +1149,6 @@ const buf = Buffer.from('buffer');
// [3, 102]
// [4, 101]
// [5, 114]
-for (const pair of buf.entries()) {
- console.log(pair);
-}
```
### buf.equals(otherBuffer)
@@ -1196,18 +1166,15 @@ changes:
Returns `true` if both `buf` and `otherBuffer` have exactly the same bytes,
`false` otherwise.
-Examples:
-
```js
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('414243', 'hex');
const buf3 = Buffer.from('ABCD');
-// Prints: true
console.log(buf1.equals(buf2));
-
-// Prints: false
+// Prints: true
console.log(buf1.equals(buf3));
+// Prints: false
```
### buf.fill(value[, offset[, end]][, encoding])
@@ -1235,8 +1202,8 @@ Example: Fill a `Buffer` with the ASCII character `'h'`
```js
const b = Buffer.allocUnsafe(50).fill('h');
-// Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
console.log(b.toString());
+// Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
```
`value` is coerced to a `uint32` value if it is not a String or Integer.
@@ -1247,8 +1214,8 @@ then only the first bytes of that character that fit into `buf` are written.
Example: Fill a `Buffer` with a two-byte character
```js
-// Prints:
console.log(Buffer.allocUnsafe(3).fill('\u0222'));
+// Prints:
```
If `value` contains invalid characters, it is truncated; if no valid
@@ -1256,12 +1223,13 @@ fill data remains, no filling is performed:
```js
const buf = Buffer.allocUnsafe(5);
-// Prints:
+
console.log(buf.fill('a'));
-// Prints:
+// Prints:
console.log(buf.fill('aazz', 'hex'));
// Prints:
console.log(buf.fill('zz', 'hex'));
+// Throws an exception.
```
### buf.includes(value[, byteOffset][, encoding])
@@ -1277,32 +1245,23 @@ added: v5.3.0
Equivalent to [`buf.indexOf() !== -1`][`buf.indexOf()`].
-Examples:
-
```js
const buf = Buffer.from('this is a buffer');
-// Prints: true
console.log(buf.includes('this'));
-
// Prints: true
console.log(buf.includes('is'));
-
// Prints: true
console.log(buf.includes(Buffer.from('a buffer')));
-
// Prints: true
-// (97 is the decimal ASCII value for 'a')
console.log(buf.includes(97));
-
-// Prints: false
+// Prints: true (97 is the decimal ASCII value for 'a')
console.log(buf.includes(Buffer.from('a buffer example')));
-
-// Prints: true
-console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
-
// Prints: false
+console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
+// Prints: true
console.log(buf.includes('this', 4));
+// Prints: false
```
### buf.indexOf(value[, byteOffset][, encoding])
@@ -1334,37 +1293,28 @@ If `value` is:
* a number, `value` will be interpreted as an unsigned 8-bit integer
value between `0` and `255`.
-Examples:
-
```js
const buf = Buffer.from('this is a buffer');
-// Prints: 0
console.log(buf.indexOf('this'));
-
-// Prints: 2
+// Prints: 0
console.log(buf.indexOf('is'));
-
-// Prints: 8
+// Prints: 2
console.log(buf.indexOf(Buffer.from('a buffer')));
-
// Prints: 8
-// (97 is the decimal ASCII value for 'a')
console.log(buf.indexOf(97));
-
-// Prints: -1
+// Prints: 8 (97 is the decimal ASCII value for 'a')
console.log(buf.indexOf(Buffer.from('a buffer example')));
-
-// Prints: 8
+// Prints: -1
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
+// Prints: 8
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
-// Prints: 4
console.log(utf16Buffer.indexOf('\u03a3', 0, 'ucs2'));
-
-// Prints: 6
+// Prints: 4
console.log(utf16Buffer.indexOf('\u03a3', -4, 'ucs2'));
+// Prints: 6
```
If `value` is not a string, number, or `Buffer`, this method will throw a
@@ -1409,6 +1359,9 @@ Example:
```js
const buf = Buffer.from('buffer');
+for (const key of buf.keys()) {
+ console.log(key);
+}
// Prints:
// 0
// 1
@@ -1416,9 +1369,6 @@ const buf = Buffer.from('buffer');
// 3
// 4
// 5
-for (const key of buf.keys()) {
- console.log(key);
-}
```
### buf.lastIndexOf(value[, byteOffset][, encoding])
@@ -1441,40 +1391,30 @@ changes:
Identical to [`buf.indexOf()`], except `buf` is searched from back to front
instead of front to back.
-Examples:
-
```js
const buf = Buffer.from('this buffer is a buffer');
-// Prints: 0
console.log(buf.lastIndexOf('this'));
-
-// Prints: 17
+// Prints: 0
console.log(buf.lastIndexOf('buffer'));
-
// Prints: 17
console.log(buf.lastIndexOf(Buffer.from('buffer')));
-
-// Prints: 15
-// (97 is the decimal ASCII value for 'a')
+// Prints: 17
console.log(buf.lastIndexOf(97));
-
-// Prints: -1
+// Prints: 15 (97 is the decimal ASCII value for 'a')
console.log(buf.lastIndexOf(Buffer.from('yolo')));
-
-// Prints: 5
-console.log(buf.lastIndexOf('buffer', 5));
-
// Prints: -1
+console.log(buf.lastIndexOf('buffer', 5));
+// Prints: 5
console.log(buf.lastIndexOf('buffer', 4));
+// Prints: -1
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');
-// Prints: 6
console.log(utf16Buffer.lastIndexOf('\u03a3', undefined, 'ucs2'));
-
-// Prints: 4
+// Prints: 6
console.log(utf16Buffer.lastIndexOf('\u03a3', -5, 'ucs2'));
+// Prints: 4
```
If `value` is not a string, number, or `Buffer`, this method will throw a
@@ -1521,13 +1461,13 @@ Example: Create a `Buffer` and write a shorter ASCII string to it
```js
const buf = Buffer.alloc(1234);
-// Prints: 1234
console.log(buf.length);
+// Prints: 1234
buf.write('some string', 0, 'ascii');
-// Prints: 1234
console.log(buf.length);
+// Prints: 1234
```
While the `length` property is not immutable, changing the value of `length`
@@ -1535,20 +1475,18 @@ can result in undefined and inconsistent behavior. Applications that wish to
modify the length of a `Buffer` should therefore treat `length` as read-only and
use [`buf.slice()`] to create a new `Buffer`.
-Examples:
-
```js
let buf = Buffer.allocUnsafe(10);
buf.write('abcdefghj', 0, 'ascii');
-// Prints: 10
console.log(buf.length);
+// Prints: 10
buf = buf.slice(0, 5);
-// Prints: 5
console.log(buf.length);
+// Prints: 5
```
### buf.parent
@@ -1577,23 +1515,18 @@ little endian).
Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but
the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
-// Prints: 8.20788039913184e-304
console.log(buf.readDoubleBE());
-
-// Prints: 5.447603722011605e-270
+// Prints: 8.20788039913184e-304
console.log(buf.readDoubleLE());
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 5.447603722011605e-270
console.log(buf.readDoubleLE(1));
-
+// Throws an exception: RangeError: Index out of range
+console.log(buf.readDoubleLE(1, true));
// Warning: reads passed end of buffer!
// This will result in a segmentation fault! Don't do this!
-console.log(buf.readDoubleLE(1, true));
```
### buf.readFloatBE(offset[, noAssert])
@@ -1613,23 +1546,18 @@ little endian).
Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but
the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.from([1, 2, 3, 4]);
-// Prints: 2.387939260590663e-38
console.log(buf.readFloatBE());
-
-// Prints: 1.539989614439558e-36
+// Prints: 2.387939260590663e-38
console.log(buf.readFloatLE());
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 1.539989614439558e-36
console.log(buf.readFloatLE(1));
-
+// Throws an exception: RangeError: Index out of range
+console.log(buf.readFloatLE(1, true));
// Warning: reads passed end of buffer!
// This will result in a segmentation fault! Don't do this!
-console.log(buf.readFloatLE(1, true));
```
### buf.readInt8(offset[, noAssert])
@@ -1648,19 +1576,15 @@ the resulting behavior is undefined.
Integers read from a `Buffer` are interpreted as two's complement signed values.
-Examples:
-
```js
const buf = Buffer.from([-1, 5]);
-// Prints: -1
console.log(buf.readInt8(0));
-
-// Prints: 5
+// Prints: -1
console.log(buf.readInt8(1));
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 5
console.log(buf.readInt8(2));
+// Throws an exception: RangeError: Index out of range
```
### buf.readInt16BE(offset[, noAssert])
@@ -1682,19 +1606,15 @@ the resulting behavior is undefined.
Integers read from a `Buffer` are interpreted as two's complement signed values.
-Examples:
-
```js
const buf = Buffer.from([0, 5]);
-// Prints: 5
console.log(buf.readInt16BE());
-
-// Prints: 1280
+// Prints: 5
console.log(buf.readInt16LE());
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 1280
console.log(buf.readInt16LE(1));
+// Throws an exception: RangeError: Index out of range
```
### buf.readInt32BE(offset[, noAssert])
@@ -1716,19 +1636,15 @@ the resulting behavior is undefined.
Integers read from a `Buffer` are interpreted as two's complement signed values.
-Examples:
-
```js
const buf = Buffer.from([0, 0, 0, 5]);
-// Prints: 5
console.log(buf.readInt32BE());
-
-// Prints: 83886080
+// Prints: 5
console.log(buf.readInt32LE());
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 83886080
console.log(buf.readInt32LE(1));
+// Throws an exception: RangeError: Index out of range
```
### buf.readIntBE(offset, byteLength[, noAssert])
@@ -1749,19 +1665,15 @@ bits of accuracy.
Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but
the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
-// Prints: -546f87a9cbee
console.log(buf.readIntLE(0, 6).toString(16));
-
-// Prints: 1234567890ab
+// Prints: -546f87a9cbee
console.log(buf.readIntBE(0, 6).toString(16));
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 1234567890ab
console.log(buf.readIntBE(1, 6).toString(16));
+// Throws: RangeError [ERR_INDEX_OUT_OF_RANGE]: Index out of range
```
### buf.readUInt8(offset[, noAssert])
@@ -1778,19 +1690,15 @@ Reads an unsigned 8-bit integer from `buf` at the specified `offset`.
Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but
the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.from([1, -2]);
-// Prints: 1
console.log(buf.readUInt8(0));
-
-// Prints: 254
+// Prints: 1
console.log(buf.readUInt8(1));
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 254
console.log(buf.readUInt8(2));
+// Throws an exception: RangeError: Index out of range
```
### buf.readUInt16BE(offset[, noAssert])
@@ -1810,25 +1718,19 @@ returns little endian).
Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but
the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.from([0x12, 0x34, 0x56]);
-// Prints: 1234
console.log(buf.readUInt16BE(0).toString(16));
-
-// Prints: 3412
+// Prints: 1234
console.log(buf.readUInt16LE(0).toString(16));
-
-// Prints: 3456
+// Prints: 3412
console.log(buf.readUInt16BE(1).toString(16));
-
-// Prints: 5634
+// Prints: 3456
console.log(buf.readUInt16LE(1).toString(16));
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 5634
console.log(buf.readUInt16LE(2).toString(16));
+// Throws an exception: RangeError: Index out of range
```
### buf.readUInt32BE(offset[, noAssert])
@@ -1848,19 +1750,15 @@ specified endian format (`readUInt32BE()` returns big endian,
Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but
the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);
-// Prints: 12345678
console.log(buf.readUInt32BE(0).toString(16));
-
-// Prints: 78563412
+// Prints: 12345678
console.log(buf.readUInt32LE(0).toString(16));
-
-// Throws an exception: RangeError: Index out of range
+// Prints: 78563412
console.log(buf.readUInt32LE(1).toString(16));
+// Throws an exception: RangeError: Index out of range
```
### buf.readUIntBE(offset, byteLength[, noAssert])
@@ -1881,19 +1779,15 @@ bits of accuracy.
Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but
the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
-// Prints: 1234567890ab
console.log(buf.readUIntBE(0, 6).toString(16));
-
-// Prints: ab9078563412
+// Prints: 1234567890ab
console.log(buf.readUIntLE(0, 6).toString(16));
-
-// Throws an exception: RangeError: Index out of range
+// Prints: ab9078563412
console.log(buf.readUIntBE(1, 6).toString(16));
+// Throws an exception: RangeError: Index out of range
```
### buf.slice([start[, end]])
@@ -1937,34 +1831,32 @@ for (let i = 0; i < 26; i++) {
const buf2 = buf1.slice(0, 3);
-// Prints: abc
console.log(buf2.toString('ascii', 0, buf2.length));
+// Prints: abc
buf1[0] = 33;
-// Prints: !bc
console.log(buf2.toString('ascii', 0, buf2.length));
+// Prints: !bc
```
Specifying negative indexes causes the slice to be generated relative to the
end of `buf` rather than the beginning.
-Examples:
-
```js
const buf = Buffer.from('buffer');
+console.log(buf.slice(-6, -1).toString());
// Prints: buffe
// (Equivalent to buf.slice(0, 5))
-console.log(buf.slice(-6, -1).toString());
+console.log(buf.slice(-6, -2).toString());
// Prints: buff
// (Equivalent to buf.slice(0, 4))
-console.log(buf.slice(-6, -2).toString());
+console.log(buf.slice(-5, -2).toString());
// Prints: uff
// (Equivalent to buf.slice(1, 4))
-console.log(buf.slice(-5, -2).toString());
```
### buf.swap16()
@@ -1977,23 +1869,21 @@ added: v5.10.0
Interprets `buf` as an array of unsigned 16-bit integers and swaps the byte-order
*in-place*. Throws a `RangeError` if [`buf.length`] is not a multiple of 2.
-Examples:
-
```js
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
-// Prints:
console.log(buf1);
+// Prints:
buf1.swap16();
-// Prints:
console.log(buf1);
+// Prints:
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
-// Throws an exception: RangeError: Buffer size must be a multiple of 16-bits
buf2.swap16();
+// Throws an exception: RangeError: Buffer size must be a multiple of 16-bits
```
### buf.swap32()
@@ -2006,23 +1896,21 @@ added: v5.10.0
Interprets `buf` as an array of unsigned 32-bit integers and swaps the byte-order
*in-place*. Throws a `RangeError` if [`buf.length`] is not a multiple of 4.
-Examples:
-
```js
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
-// Prints:
console.log(buf1);
+// Prints:
buf1.swap32();
-// Prints:
console.log(buf1);
+// Prints:
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
-// Throws an exception: RangeError: Buffer size must be a multiple of 32-bits
buf2.swap32();
+// Throws an exception: RangeError: Buffer size must be a multiple of 32-bits
```
### buf.swap64()
@@ -2035,23 +1923,21 @@ added: v6.3.0
Interprets `buf` as an array of 64-bit numbers and swaps the byte-order *in-place*.
Throws a `RangeError` if [`buf.length`] is not a multiple of 8.
-Examples:
-
```js
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
-// Prints:
console.log(buf1);
+// Prints:
buf1.swap64();
-// Prints:
console.log(buf1);
+// Prints:
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
-// Throws an exception: RangeError: Buffer size must be a multiple of 64-bits
buf2.swap64();
+// Throws an exception: RangeError: Buffer size must be a multiple of 64-bits
```
Note that JavaScript cannot encode 64-bit integers. This method is intended
@@ -2073,8 +1959,8 @@ Example:
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
-// Prints: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);
+// Prints: {"type":"Buffer","data":[1,2,3,4,5]}
const copy = JSON.parse(json, (key, value) => {
return value && value.type === 'Buffer' ?
@@ -2082,8 +1968,8 @@ const copy = JSON.parse(json, (key, value) => {
value;
});
-// Prints:
console.log(copy);
+// Prints:
```
### buf.toString([encoding[, start[, end]]])
@@ -2103,8 +1989,6 @@ Decodes `buf` to a string according to the specified character encoding in
The maximum length of a string instance (in UTF-16 code units) is available
as [`buffer.constants.MAX_STRING_LENGTH`][].
-Examples:
-
```js
const buf1 = Buffer.allocUnsafe(26);
@@ -2113,22 +1997,19 @@ for (let i = 0; i < 26; i++) {
buf1[i] = i + 97;
}
-// Prints: abcdefghijklmnopqrstuvwxyz
console.log(buf1.toString('ascii'));
-
-// Prints: abcde
+// Prints: abcdefghijklmnopqrstuvwxyz
console.log(buf1.toString('ascii', 0, 5));
+// Prints: abcde
const buf2 = Buffer.from('tést');
-// Prints: 74c3a97374
console.log(buf2.toString('hex'));
-
-// Prints: té
+// Prints: 74c3a97374
console.log(buf2.toString('utf8', 0, 3));
-
// Prints: té
console.log(buf2.toString(undefined, 0, 3));
+// Prints: té
```
### buf.values()
@@ -2141,11 +2022,12 @@ added: v1.1.0
Creates and returns an [iterator] for `buf` values (bytes). This function is
called automatically when a `Buffer` is used in a `for..of` statement.
-Examples:
-
```js
const buf = Buffer.from('buffer');
+for (const value of buf.values()) {
+ console.log(value);
+}
// Prints:
// 98
// 117
@@ -2153,10 +2035,10 @@ const buf = Buffer.from('buffer');
// 102
// 101
// 114
-for (const value of buf.values()) {
+
+for (const value of buf) {
console.log(value);
}
-
// Prints:
// 98
// 117
@@ -2164,9 +2046,6 @@ for (const value of buf.values()) {
// 102
// 101
// 114
-for (const value of buf) {
- console.log(value);
-}
```
### buf.write(string[, offset[, length]][, encoding])
@@ -2192,8 +2071,8 @@ const buf = Buffer.allocUnsafe(256);
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
-// Prints: 12 bytes: ½ + ¼ = ¾
console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
+// Prints: 12 bytes: ½ + ¼ = ¾
```
### buf.writeDoubleBE(value, offset[, noAssert])
@@ -2215,20 +2094,18 @@ endian). `value` *should* be a valid 64-bit double. Behavior is undefined when
Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond
the end of `buf`, but the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(8);
buf.writeDoubleBE(0xdeadbeefcafebabe, 0);
-// Prints:
console.log(buf);
+// Prints:
buf.writeDoubleLE(0xdeadbeefcafebabe, 0);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeFloatBE(value, offset[, noAssert])
@@ -2250,20 +2127,18 @@ endian). `value` *should* be a valid 32-bit float. Behavior is undefined when
Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond
the end of `buf`, but the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(4);
buf.writeFloatBE(0xcafebabe, 0);
-// Prints:
console.log(buf);
+// Prints:
buf.writeFloatLE(0xcafebabe, 0);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeInt8(value, offset[, noAssert])
@@ -2285,16 +2160,14 @@ the end of `buf`, but the resulting behavior is undefined.
`value` is interpreted and written as a two's complement signed integer.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(2);
buf.writeInt8(2, 0);
buf.writeInt8(-2, 1);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeInt16BE(value, offset[, noAssert])
@@ -2318,16 +2191,14 @@ the end of `buf`, but the resulting behavior is undefined.
`value` is interpreted and written as a two's complement signed integer.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(4);
buf.writeInt16BE(0x0102, 0);
buf.writeInt16LE(0x0304, 2);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeInt32BE(value, offset[, noAssert])
@@ -2351,16 +2222,14 @@ the end of `buf`, but the resulting behavior is undefined.
`value` is interpreted and written as a two's complement signed integer.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(8);
buf.writeInt32BE(0x01020304, 0);
buf.writeInt32LE(0x05060708, 4);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeIntBE(value, offset, byteLength[, noAssert])
@@ -2383,20 +2252,18 @@ anything other than a signed integer.
Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond
the end of `buf`, but the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(6);
buf.writeIntBE(0x1234567890ab, 0, 6);
-// Prints:
console.log(buf);
+// Prints:
buf.writeIntLE(0x1234567890ab, 0, 6);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeUInt8(value, offset[, noAssert])
@@ -2416,8 +2283,6 @@ other than an unsigned 8-bit integer.
Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond
the end of `buf`, but the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(4);
@@ -2426,8 +2291,8 @@ buf.writeUInt8(0x4, 1);
buf.writeUInt8(0x23, 2);
buf.writeUInt8(0x42, 3);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeUInt16BE(value, offset[, noAssert])
@@ -2449,22 +2314,20 @@ undefined when `value` is anything other than an unsigned 16-bit integer.
Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond
the end of `buf`, but the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(4);
buf.writeUInt16BE(0xdead, 0);
buf.writeUInt16BE(0xbeef, 2);
-// Prints:
console.log(buf);
+// Prints:
buf.writeUInt16LE(0xdead, 0);
buf.writeUInt16LE(0xbeef, 2);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeUInt32BE(value, offset[, noAssert])
@@ -2486,20 +2349,18 @@ undefined when `value` is anything other than an unsigned 32-bit integer.
Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond
the end of `buf`, but the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(4);
buf.writeUInt32BE(0xfeedface, 0);
-// Prints:
console.log(buf);
+// Prints:
buf.writeUInt32LE(0xfeedface, 0);
-// Prints:
console.log(buf);
+// Prints:
```
### buf.writeUIntBE(value, offset, byteLength[, noAssert])
@@ -2522,20 +2383,18 @@ anything other than an unsigned integer.
Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond
the end of `buf`, but the resulting behavior is undefined.
-Examples:
-
```js
const buf = Buffer.allocUnsafe(6);
buf.writeUIntBE(0x1234567890ab, 0, 6);
-// Prints:
console.log(buf);
+// Prints:
buf.writeUIntLE(0x1234567890ab, 0, 6);
-// Prints:
console.log(buf);
+// Prints:
```
## buffer.INSPECT_MAX_BYTES
@@ -2663,13 +2522,13 @@ const { SlowBuffer } = require('buffer');
const buf = new SlowBuffer(5);
-// Prints: (contents may vary):
console.log(buf);
+// Prints: (contents may vary):
buf.fill(0);
-// Prints:
console.log(buf);
+// Prints:
```
## Buffer Constants
diff --git a/doc/api/crypto.md b/doc/api/crypto.md
index 00128cebfb8154..bf0315fc034366 100644
--- a/doc/api/crypto.md
+++ b/doc/api/crypto.md
@@ -1273,6 +1273,11 @@ Adversaries][] for details.
### crypto.createCipheriv(algorithm, key, iv[, options])
- `algorithm` {string}
- `key` {string | Buffer | TypedArray | DataView}
@@ -1288,7 +1293,8 @@ available cipher algorithms.
The `key` is the raw key used by the `algorithm` and `iv` is an
[initialization vector][]. Both arguments must be `'utf8'` encoded strings,
-[Buffers][`Buffer`], `TypedArray`, or `DataView`s.
+[Buffers][`Buffer`], `TypedArray`, or `DataView`s. If the cipher does not need
+an initialization vector, `iv` may be `null`.
### crypto.createCredentials(details)
- `algorithm` {string}
- `key` {string | Buffer | TypedArray | DataView}
@@ -1350,7 +1361,8 @@ available cipher algorithms.
The `key` is the raw key used by the `algorithm` and `iv` is an
[initialization vector][]. Both arguments must be `'utf8'` encoded strings,
-[Buffers][`Buffer`], `TypedArray`, or `DataView`s.
+[Buffers][`Buffer`], `TypedArray`, or `DataView`s. If the cipher does not need
+an initialization vector, `iv` may be `null`.
### crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])
+
+* Returns: {Buffer|undefined} The latest `Finished` message that has been
+sent to the socket as part of a SSL/TLS handshake, or `undefined` if
+no `Finished` message has been sent yet.
+
+As the `Finished` messages are message digests of the complete handshake
+(with a total of 192 bits for TLS 1.0 and more for SSL 3.0), they can
+be used for external authentication procedures when the authentication
+provided by SSL/TLS is not desired or is not enough.
+
+Corresponds to the `SSL_get_finished` routine in OpenSSL and may be used
+to implement the `tls-unique` channel binding from [RFC 5929][].
+
### tlsSocket.getPeerCertificate([detailed])
+
+* Returns: {Buffer|undefined} The latest `Finished` message that is expected
+or has actually been received from the socket as part of a SSL/TLS handshake,
+or `undefined` if there is no `Finished` message so far.
+
+As the `Finished` messages are message digests of the complete handshake
+(with a total of 192 bits for TLS 1.0 and more for SSL 3.0), they can
+be used for external authentication procedures when the authentication
+provided by SSL/TLS is not desired or is not enough.
+
+Corresponds to the `SSL_get_peer_finished` routine in OpenSSL and may be used
+to implement the `tls-unique` channel binding from [RFC 5929][].
+
### tlsSocket.getProtocol()
+
+* `env` {object} A object containing the environment variables to check.
+ Defaults to `process.env`.
+* Returns: {number}
+
+Returns:
+* 1 for 2,
+* 4 for 16,
+* 8 for 256,
+* 24 for 16,777,216
+colors supported.
+
+Use this to determine what colors the terminal supports. Due to the nature of
+colors in terminals it is possible to either have false positives or false
+negatives. It depends on process information and the environment variables that
+may lie about what terminal is used.
+To enforce a specific behavior without relying on `process.env` it is possible
+to pass in an object with different settings.
+
+Use the `NODE_DISABLE_COLORS` environment variable to enforce this function to
+always return 1.
+
## tty.isatty(fd)
diff --git a/doc/changelogs/CHANGELOG_V9.md b/doc/changelogs/CHANGELOG_V9.md
index 35107dc996d63f..df896acb4d7101 100644
--- a/doc/changelogs/CHANGELOG_V9.md
+++ b/doc/changelogs/CHANGELOG_V9.md
@@ -8,6 +8,7 @@
+9.9.0 9.8.0 9.7.1 9.7.0
@@ -35,6 +36,164 @@
* [io.js](CHANGELOG_IOJS.md)
* [Archive](CHANGELOG_ARCHIVE.md)
+
+## 2018-03-21, Version 9.9.0 (Current), @MylesBorins prepared by @targos
+
+### Notable Changes
+
+* **assert**:
+ - From now on all error messages produced by `assert` in strict mode will produce a error diff. (Ruben Bridgewater) [#17615](https://github.com/nodejs/node/pull/17615)
+ - From now on it is possible to use a validation object in throws instead of the other possibilities. (Ruben Bridgewater) [#17584](https://github.com/nodejs/node/pull/17584)
+* **crypto**:
+ - allow passing null as IV unless required (Tobias Nießen) [#18644](https://github.com/nodejs/node/pull/18644)
+* **fs**:
+ - support as and as+ flags in stringToFlags() (Sarat Addepalli) [#18801](https://github.com/nodejs/node/pull/18801)
+* **tls**:
+ - expose Finished messages in TLSSocket (Anton Salikhmetov) [#19102](https://github.com/nodejs/node/pull/19102)
+* **tty**:
+ - Add getColorDepth function to determine if terminal supports colors. (Ruben Bridgewater) [#17615](https://github.com/nodejs/node/pull/17615)
+* **util**:
+ - add util.inspect compact option (Ruben Bridgewater) [#17576](https://github.com/nodejs/node/pull/17576)
+* **Added new collaborators**
+ - [watson](https://github.com/watson) Thomas Watson
+
+### Commits
+
+* [[`acc86ed246`](https://github.com/nodejs/node/commit/acc86ed246)] - 2018-03-XX, Version 9.9.0 (Current) (Michaël Zasso)
+* [[`8d33e5c214`](https://github.com/nodejs/node/commit/8d33e5c214)] - **assert**: improve error check (Ruben Bridgewater) [#17574](https://github.com/nodejs/node/pull/17574)
+* [[`5e6b42ec9c`](https://github.com/nodejs/node/commit/5e6b42ec9c)] - **assert**: show proper differences (Ruben Bridgewater) [#18611](https://github.com/nodejs/node/pull/18611)
+* [[`9abbb6b857`](https://github.com/nodejs/node/commit/9abbb6b857)] - **assert**: fix infinite loop (Ruben Bridgewater) [#18611](https://github.com/nodejs/node/pull/18611)
+* [[`e9ac468146`](https://github.com/nodejs/node/commit/e9ac468146)] - **assert**: fix throws trace (Ruben Bridgewater) [#18595](https://github.com/nodejs/node/pull/18595)
+* [[`d3c2534bbe`](https://github.com/nodejs/node/commit/d3c2534bbe)] - **assert**: use destructuring for errors (Ruben Bridgewater) [#18247](https://github.com/nodejs/node/pull/18247)
+* [[`5aa3a2d172`](https://github.com/nodejs/node/commit/5aa3a2d172)] - **(SEMVER-MINOR)** **assert**: improve error messages (Ruben Bridgewater) [#17615](https://github.com/nodejs/node/pull/17615)
+* [[`f96ea47cf5`](https://github.com/nodejs/node/commit/f96ea47cf5)] - **assert**: fix strict regression (Ruben Bridgewater) [#17903](https://github.com/nodejs/node/pull/17903)
+* [[`ebd60fa505`](https://github.com/nodejs/node/commit/ebd60fa505)] - **(SEMVER-MINOR)** **assert**: .throws accept objects (Ruben Bridgewater) [#17584](https://github.com/nodejs/node/pull/17584)
+* [[`612ba1a3f0`](https://github.com/nodejs/node/commit/612ba1a3f0)] - **(SEMVER-MINOR)** **assert**: improve assert.throws (Ruben Bridgewater) [#17585](https://github.com/nodejs/node/pull/17585)
+* [[`24aeca7dd5`](https://github.com/nodejs/node/commit/24aeca7dd5)] - **assert**: fix throws and doesNotThrow stack frames (Ruben Bridgewater) [#17703](https://github.com/nodejs/node/pull/17703)
+* [[`db73d1c13b`](https://github.com/nodejs/node/commit/db73d1c13b)] - **assert**: use object argument in innerFail (Ruben Bridgewater) [#17582](https://github.com/nodejs/node/pull/17582)
+* [[`bae5de1949`](https://github.com/nodejs/node/commit/bae5de1949)] - **(SEMVER-MINOR)** **assert**: add strict functionality export (Ruben Bridgewater) [#17002](https://github.com/nodejs/node/pull/17002)
+* [[`f0f31d080a`](https://github.com/nodejs/node/commit/f0f31d080a)] - **async_hooks**: add copyHooks function (Daniel Bevenius) [#19391](https://github.com/nodejs/node/pull/19391)
+* [[`71b1c7f79f`](https://github.com/nodejs/node/commit/71b1c7f79f)] - **async_hooks**: don't set hook\_fields\[kTotals\] to 0 (Daniel Bevenius) [#19219](https://github.com/nodejs/node/pull/19219)
+* [[`530b8a4077`](https://github.com/nodejs/node/commit/530b8a4077)] - **benchmark**: fix benchmark for url (Sergey Golovin) [#19084](https://github.com/nodejs/node/pull/19084)
+* [[`563bed00f5`](https://github.com/nodejs/node/commit/563bed00f5)] - **benchmark,lib,test,tools**: use consistent quotes (Rich Trott) [#19156](https://github.com/nodejs/node/pull/19156)
+* [[`3f7c4eea04`](https://github.com/nodejs/node/commit/3f7c4eea04)] - **build**: do not cd on vcbuild help (Vse Mozhet Byt) [#19291](https://github.com/nodejs/node/pull/19291)
+* [[`5a1437cdbd`](https://github.com/nodejs/node/commit/5a1437cdbd)] - **build**: update arm64 minimum supported platform (Gibson Fahnestock) [#19164](https://github.com/nodejs/node/pull/19164)
+* [[`07845fc19e`](https://github.com/nodejs/node/commit/07845fc19e)] - **console**: port errors to new system (Ruben Bridgewater) [#18857](https://github.com/nodejs/node/pull/18857)
+* [[`03c321a713`](https://github.com/nodejs/node/commit/03c321a713)] - **(SEMVER-MINOR)** **crypto**: allow passing null as IV unless required (Tobias Nießen) [#18644](https://github.com/nodejs/node/pull/18644)
+* [[`044995e546`](https://github.com/nodejs/node/commit/044995e546)] - **crypto**: use bool over int consistently (Tobias Nießen) [#19238](https://github.com/nodejs/node/pull/19238)
+* [[`36f664ef9a`](https://github.com/nodejs/node/commit/36f664ef9a)] - **deps**: V8: backport 596d55a from upstream (Myles Borins) [#19477](https://github.com/nodejs/node/pull/19477)
+* [[`5966b8cc06`](https://github.com/nodejs/node/commit/5966b8cc06)] - **deps**: v8: cherry-pick fixes for v8:7535 (Flarna) [#19333](https://github.com/nodejs/node/pull/19333)
+* [[`cb732aeda4`](https://github.com/nodejs/node/commit/cb732aeda4)] - **doc**: enable eslint prefer-template rule (Ruben Bridgewater) [#18831](https://github.com/nodejs/node/pull/18831)
+* [[`ff82acb95a`](https://github.com/nodejs/node/commit/ff82acb95a)] - **doc**: update buffer examples (Ruben Bridgewater) [#18758](https://github.com/nodejs/node/pull/18758)
+* [[`a4c28d77f7`](https://github.com/nodejs/node/commit/a4c28d77f7)] - **doc**: fix deprecation removed by mistake (Michaël Zasso) [#19482](https://github.com/nodejs/node/pull/19482)
+* [[`b229912f6f`](https://github.com/nodejs/node/commit/b229912f6f)] - **doc**: do not announce obvious examples (Rich Trott) [#19270](https://github.com/nodejs/node/pull/19270)
+* [[`c1fa0926e3`](https://github.com/nodejs/node/commit/c1fa0926e3)] - **doc**: fix typos on n-api (Kyle Robinson Young) [#19385](https://github.com/nodejs/node/pull/19385)
+* [[`99e6734f19`](https://github.com/nodejs/node/commit/99e6734f19)] - **doc**: improve best practices in onboarding-extras (Rich Trott) [#19315](https://github.com/nodejs/node/pull/19315)
+* [[`5a56327e79`](https://github.com/nodejs/node/commit/5a56327e79)] - **doc**: fix minor issues in async\_hooks.md (Rich Trott) [#19313](https://github.com/nodejs/node/pull/19313)
+* [[`5da3ee7719`](https://github.com/nodejs/node/commit/5da3ee7719)] - **doc**: clarify default TLS handshake timeout (Rich Trott) [#19290](https://github.com/nodejs/node/pull/19290)
+* [[`7f652c2bcc`](https://github.com/nodejs/node/commit/7f652c2bcc)] - **doc**: update username and email (Yuta Hiroto) [#19338](https://github.com/nodejs/node/pull/19338)
+* [[`e247f19ac3`](https://github.com/nodejs/node/commit/e247f19ac3)] - **doc**: improve style guide text (Rich Trott) [#19269](https://github.com/nodejs/node/pull/19269)
+* [[`c9b12f302a`](https://github.com/nodejs/node/commit/c9b12f302a)] - **doc**: remove superfluous text in onboarding-extras (Rich Trott) [#19247](https://github.com/nodejs/node/pull/19247)
+* [[`6c5afebf55`](https://github.com/nodejs/node/commit/6c5afebf55)] - **doc**: make caveat in stream.md more concise (Rich Trott) [#19251](https://github.com/nodejs/node/pull/19251)
+* [[`8e88a180b9`](https://github.com/nodejs/node/commit/8e88a180b9)] - **doc**: add warning to assert.doesNotThrow() (Ruben Bridgewater) [#18699](https://github.com/nodejs/node/pull/18699)
+* [[`a04e4ae5e4`](https://github.com/nodejs/node/commit/a04e4ae5e4)] - **doc**: remove confusing "cats" from style guide (Rich Trott) [#19246](https://github.com/nodejs/node/pull/19246)
+* [[`7c3617558e`](https://github.com/nodejs/node/commit/7c3617558e)] - **doc**: remove superfluous adverb from style guide (Rich Trott) [#19246](https://github.com/nodejs/node/pull/19246)
+* [[`d117f5ff22`](https://github.com/nodejs/node/commit/d117f5ff22)] - **doc**: remove warning against readable/readable.read (Rich Trott) [#19193](https://github.com/nodejs/node/pull/19193)
+* [[`5c21d16c31`](https://github.com/nodejs/node/commit/5c21d16c31)] - **doc**: add watson to collaborators (Thomas Watson) [#19234](https://github.com/nodejs/node/pull/19234)
+* [[`9557e66ae1`](https://github.com/nodejs/node/commit/9557e66ae1)] - **doc**: update labels info in onboarding-extras.md (Rich Trott) [#19160](https://github.com/nodejs/node/pull/19160)
+* [[`84acb9fae5`](https://github.com/nodejs/node/commit/84acb9fae5)] - **doc**: add inspector usage example (Ali Ijaz Sheikh) [#19172](https://github.com/nodejs/node/pull/19172)
+* [[`27088cfaa7`](https://github.com/nodejs/node/commit/27088cfaa7)] - **doc**: improve onboarding instructions (Joyee Cheung) [#19108](https://github.com/nodejs/node/pull/19108)
+* [[`9ec0eab019`](https://github.com/nodejs/node/commit/9ec0eab019)] - **doc**: make suggestion more direct in stream.md (Rich Trott) [#19124](https://github.com/nodejs/node/pull/19124)
+* [[`968b867bf2`](https://github.com/nodejs/node/commit/968b867bf2)] - **doc**: document asserts Weak(Map|Set) behavior (Ruben Bridgewater) [#18248](https://github.com/nodejs/node/pull/18248)
+* [[`745709396c`](https://github.com/nodejs/node/commit/745709396c)] - **(SEMVER-MINOR)** **doc**: improve .throws RegExp info (Ruben Bridgewater) [#17585](https://github.com/nodejs/node/pull/17585)
+* [[`5a78c6c0a6`](https://github.com/nodejs/node/commit/5a78c6c0a6)] - **(SEMVER-MINOR)** **doc**: improve assert documentation (Ruben Bridgewater) [#17002](https://github.com/nodejs/node/pull/17002)
+* [[`f4f0266bfe`](https://github.com/nodejs/node/commit/f4f0266bfe)] - **errors**: add comments about falsy error types (Ruben Bridgewater) [#18857](https://github.com/nodejs/node/pull/18857)
+* [[`ffa16aad60`](https://github.com/nodejs/node/commit/ffa16aad60)] - **errors**: update all internal errors (Ruben Bridgewater) [#18857](https://github.com/nodejs/node/pull/18857)
+* [[`d57a2421fc`](https://github.com/nodejs/node/commit/d57a2421fc)] - **errors**: implement new error handling (Ruben Bridgewater) [#18857](https://github.com/nodejs/node/pull/18857)
+* [[`607b33cfcc`](https://github.com/nodejs/node/commit/607b33cfcc)] - **(SEMVER-MINOR)** **fs**: support as and as+ flags in stringToFlags() (Sarat Addepalli) [#18801](https://github.com/nodejs/node/pull/18801)
+* [[`b01bd800c6`](https://github.com/nodejs/node/commit/b01bd800c6)] - **fs**: fix `createReadStream(…, {end: n})` for non-seekable fds (Anna Henningsen) [#19329](https://github.com/nodejs/node/pull/19329)
+* [[`3914e97741`](https://github.com/nodejs/node/commit/3914e97741)] - **http2**: fixes error handling (Matteo Collina) [#19232](https://github.com/nodejs/node/pull/19232)
+* [[`3bf69cd3e7`](https://github.com/nodejs/node/commit/3bf69cd3e7)] - **http2**: some general code improvements (James M Snell) [#19400](https://github.com/nodejs/node/pull/19400)
+* [[`4277635bed`](https://github.com/nodejs/node/commit/4277635bed)] - **http2**: clean up Http2Settings (James M Snell) [#19400](https://github.com/nodejs/node/pull/19400)
+* [[`42b6d801dc`](https://github.com/nodejs/node/commit/42b6d801dc)] - **http2**: don't aggressively inline (James M Snell) [#19400](https://github.com/nodejs/node/pull/19400)
+* [[`89fbbc48ff`](https://github.com/nodejs/node/commit/89fbbc48ff)] - **http2**: simplify timeout tracking (Anna Henningsen) [#19206](https://github.com/nodejs/node/pull/19206)
+* [[`f06622cd56`](https://github.com/nodejs/node/commit/f06622cd56)] - **lib**: define printErr() in script string (cjihrig) [#19285](https://github.com/nodejs/node/pull/19285)
+* [[`b35eabb837`](https://github.com/nodejs/node/commit/b35eabb837)] - **lib**: handle `throw undefined` in assert.throws() (Ben Noordhuis) [#18029](https://github.com/nodejs/node/pull/18029)
+* [[`0e6f720991`](https://github.com/nodejs/node/commit/0e6f720991)] - **n-api**: separate out async\_hooks test (Gabriel Schulhof) [#19392](https://github.com/nodejs/node/pull/19392)
+* [[`528798c3f4`](https://github.com/nodejs/node/commit/528798c3f4)] - **n-api**: add missing exception checking (Michael Dawson) [#19362](https://github.com/nodejs/node/pull/19362)
+* [[`f679ac19e0`](https://github.com/nodejs/node/commit/f679ac19e0)] - **n-api**: resolve promise in test (Gabriel Schulhof) [#19245](https://github.com/nodejs/node/pull/19245)
+* [[`12f19a6b86`](https://github.com/nodejs/node/commit/12f19a6b86)] - **n-api**: update documentation (Gabriel Schulhof) [#19078](https://github.com/nodejs/node/pull/19078)
+* [[`0c9577edfc`](https://github.com/nodejs/node/commit/0c9577edfc)] - **n-api,test**: add int64 bounds tests (Kyle Farnung) [#19309](https://github.com/nodejs/node/pull/19309)
+* [[`f36521becf`](https://github.com/nodejs/node/commit/f36521becf)] - **n-api,test**: add a new.target test to addons-napi (Taylor Woll) [#19236](https://github.com/nodejs/node/pull/19236)
+* [[`5b12d3a58e`](https://github.com/nodejs/node/commit/5b12d3a58e)] - **net**: do not inherit the no-half-open enforcer (Luigi Pinca) [#18974](https://github.com/nodejs/node/pull/18974)
+* [[`a9bd8bff8a`](https://github.com/nodejs/node/commit/a9bd8bff8a)] - **path**: remove redundant function (Sergey Golovin) [#19237](https://github.com/nodejs/node/pull/19237)
+* [[`55f7bbb0bd`](https://github.com/nodejs/node/commit/55f7bbb0bd)] - **repl**: refactor code for readability (Ruben Bridgewater) [#17919](https://github.com/nodejs/node/pull/17919)
+* [[`6997af7378`](https://github.com/nodejs/node/commit/6997af7378)] - **repl**: upper case comments first char (Ruben Bridgewater) [#17919](https://github.com/nodejs/node/pull/17919)
+* [[`3e6858e4a7`](https://github.com/nodejs/node/commit/3e6858e4a7)] - **repl**: better handling of recoverable errors (Prince J Wesley) [#18915](https://github.com/nodejs/node/pull/18915)
+* [[`49391a70e1`](https://github.com/nodejs/node/commit/49391a70e1)] - **src**: fix util abort (Ruben Bridgewater) [#19223](https://github.com/nodejs/node/pull/19223)
+* [[`1ba1861731`](https://github.com/nodejs/node/commit/1ba1861731)] - **src**: remove unused using declarations async\_wrap (Daniel Bevenius) [#18893](https://github.com/nodejs/node/pull/18893)
+* [[`8757799d69`](https://github.com/nodejs/node/commit/8757799d69)] - **src**: remove unused stdlib.h include (Daniel Bevenius) [#19427](https://github.com/nodejs/node/pull/19427)
+* [[`da62c5ca68`](https://github.com/nodejs/node/commit/da62c5ca68)] - **src**: fix minor typo in comment stream\_base.h (Daniel Bevenius) [#19429](https://github.com/nodejs/node/pull/19429)
+* [[`43c482b9c8`](https://github.com/nodejs/node/commit/43c482b9c8)] - **src**: fix indentation of params in env-inl.h (Daniel Bevenius) [#19390](https://github.com/nodejs/node/pull/19390)
+* [[`054dd28da6`](https://github.com/nodejs/node/commit/054dd28da6)] - **src**: make AsyncWrap constructors delegate (Daniel Bevenius) [#19366](https://github.com/nodejs/node/pull/19366)
+* [[`7a3d1d205e`](https://github.com/nodejs/node/commit/7a3d1d205e)] - **src**: remove unused uv.h include from async\_wrap.cc (Daniel Bevenius) [#19342](https://github.com/nodejs/node/pull/19342)
+* [[`126a161928`](https://github.com/nodejs/node/commit/126a161928)] - **src**: fix indenting of wrap-\>EmitTraceEventBefore (Daniel Bevenius) [#19340](https://github.com/nodejs/node/pull/19340)
+* [[`03fb817a1d`](https://github.com/nodejs/node/commit/03fb817a1d)] - **src**: add extractPromiseWrap function (Daniel Bevenius) [#19340](https://github.com/nodejs/node/pull/19340)
+* [[`e208282f68`](https://github.com/nodejs/node/commit/e208282f68)] - **src**: refactor emit before/after/promiseResolve (Daniel Bevenius) [#19295](https://github.com/nodejs/node/pull/19295)
+* [[`49481d0e3b`](https://github.com/nodejs/node/commit/49481d0e3b)] - **src**: add convenience ctor for async trigger id scope (Anna Henningsen) [#19204](https://github.com/nodejs/node/pull/19204)
+* [[`4b9914a318`](https://github.com/nodejs/node/commit/4b9914a318)] - **src**: avoid duplicate Before/AtExitCallback structs (Daniel Bevenius) [#19226](https://github.com/nodejs/node/pull/19226)
+* [[`27754c5408`](https://github.com/nodejs/node/commit/27754c5408)] - **src**: add incr/decr operators for Reference (Daniel Bevenius) [#19083](https://github.com/nodejs/node/pull/19083)
+* [[`64f646269a`](https://github.com/nodejs/node/commit/64f646269a)] - **src**: use smart pointer in AsyncWrap::WeakCallback (Daniel Bevenius) [#19168](https://github.com/nodejs/node/pull/19168)
+* [[`152c931f53`](https://github.com/nodejs/node/commit/152c931f53)] - **stream**: make Duplex inherits from DuplexBase (Luigi Pinca) [#18974](https://github.com/nodejs/node/pull/18974)
+* [[`9c0c0e68ac`](https://github.com/nodejs/node/commit/9c0c0e68ac)] - **stream**: add no-half-open enforcer only if needed (Luigi Pinca) [#18953](https://github.com/nodejs/node/pull/18953)
+* [[`1eac1d7d85`](https://github.com/nodejs/node/commit/1eac1d7d85)] - **test**: minor refactoring (Ruben Bridgewater) [#18669](https://github.com/nodejs/node/pull/18669)
+* [[`574d061c3c`](https://github.com/nodejs/node/commit/574d061c3c)] - **test**: remove assert.doesNotThrow() (Ruben Bridgewater) [#18669](https://github.com/nodejs/node/pull/18669)
+* [[`5478746203`](https://github.com/nodejs/node/commit/5478746203)] - **test**: refactor assert test (Ruben Bridgewater) [#18610](https://github.com/nodejs/node/pull/18610)
+* [[`4e9279df5c`](https://github.com/nodejs/node/commit/4e9279df5c)] - **test**: remove NodeTestFixture from Env constructor (Daniel Bevenius) [#18558](https://github.com/nodejs/node/pull/18558)
+* [[`22b8f9fba6`](https://github.com/nodejs/node/commit/22b8f9fba6)] - **test**: introduce SetUpTestCase/TearDownTestCase (Daniel Bevenius) [#18558](https://github.com/nodejs/node/pull/18558)
+* [[`519850f21e`](https://github.com/nodejs/node/commit/519850f21e)] - **test**: http2 client setNextStreamID errors (Trivikram) [#18848](https://github.com/nodejs/node/pull/18848)
+* [[`e3ce084f7c`](https://github.com/nodejs/node/commit/e3ce084f7c)] - **test**: fix flaky test-http2-ping-flood (Rich Trott) [#19395](https://github.com/nodejs/node/pull/19395)
+* [[`7df6d9ddc8`](https://github.com/nodejs/node/commit/7df6d9ddc8)] - **test**: rename regression tests file names (Ujjwal Sharma) [#19332](https://github.com/nodejs/node/pull/19332)
+* [[`f49042131a`](https://github.com/nodejs/node/commit/f49042131a)] - **test**: use descriptive names for regression tests (Ujjwal Sharma) [#19275](https://github.com/nodejs/node/pull/19275)
+* [[`01749f07bd`](https://github.com/nodejs/node/commit/01749f07bd)] - **test**: fix flaky test-http2-settings-flood (Rich Trott) [#19349](https://github.com/nodejs/node/pull/19349)
+* [[`9aa5090689`](https://github.com/nodejs/node/commit/9aa5090689)] - **test**: fix test-cluster-send-handle-large-payload (Rich Trott) [#19311](https://github.com/nodejs/node/pull/19311)
+* [[`11a0ef566a`](https://github.com/nodejs/node/commit/11a0ef566a)] - **test**: delete test/parallel/test-regress-GH-4948 (Ujjwal Sharma) [#19279](https://github.com/nodejs/node/pull/19279)
+* [[`be20914958`](https://github.com/nodejs/node/commit/be20914958)] - **test**: shared lib build doesn't handle SIGPIPE (Yihong Wang) [#19211](https://github.com/nodejs/node/pull/19211)
+* [[`f84f548986`](https://github.com/nodejs/node/commit/f84f548986)] - **test**: fix assertion argument order (Rich Trott) [#19264](https://github.com/nodejs/node/pull/19264)
+* [[`84ae59e5f8`](https://github.com/nodejs/node/commit/84ae59e5f8)] - **test**: fix path in doctool/test-doctool-json (Vse Mozhet Byt) [#19287](https://github.com/nodejs/node/pull/19287)
+* [[`b8ca616baa`](https://github.com/nodejs/node/commit/b8ca616baa)] - **test**: fix compiler warnings in callback-scope (Daniel Bevenius) [#19252](https://github.com/nodejs/node/pull/19252)
+* [[`d3bc72e9cc`](https://github.com/nodejs/node/commit/d3bc72e9cc)] - **test**: name test files appropriately (Ujjwal Sharma) [#19212](https://github.com/nodejs/node/pull/19212)
+* [[`f0c8f6969f`](https://github.com/nodejs/node/commit/f0c8f6969f)] - **test**: fix test-abort-backtrace in shared lib build (Yihong Wang) [#19213](https://github.com/nodejs/node/pull/19213)
+* [[`e4c320e5d7`](https://github.com/nodejs/node/commit/e4c320e5d7)] - **test**: Remove unnecessary asserion messages in test-crypto-hash.js (Piotr Grzesik) [#18984](https://github.com/nodejs/node/pull/18984)
+* [[`411f3e03fe`](https://github.com/nodejs/node/commit/411f3e03fe)] - **test**: remove flaky status for test-npm-install (Rich Trott) [#19216](https://github.com/nodejs/node/pull/19216)
+* [[`a4a4819954`](https://github.com/nodejs/node/commit/a4a4819954)] - **test**: do not check text for engine-generated error (Rich Trott) [#19215](https://github.com/nodejs/node/pull/19215)
+* [[`38eb432260`](https://github.com/nodejs/node/commit/38eb432260)] - **test**: refactor http-https-default-ports (Ken Lin) [#19130](https://github.com/nodejs/node/pull/19130)
+* [[`0ece7cc227`](https://github.com/nodejs/node/commit/0ece7cc227)] - **test**: rename test-regress-GH-877.js (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`636a5f627e`](https://github.com/nodejs/node/commit/636a5f627e)] - **test**: rename test-regress-GH-784.js (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`c0c6d5848f`](https://github.com/nodejs/node/commit/c0c6d5848f)] - **test**: address nits and rename the corresponding fixture (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`22484e1fb2`](https://github.com/nodejs/node/commit/22484e1fb2)] - **test**: rename tests to remove "regress" keyword (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`2262a34f0b`](https://github.com/nodejs/node/commit/2262a34f0b)] - **test**: rename test-regress-GH-4027 (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`bdbfc0e20e`](https://github.com/nodejs/node/commit/bdbfc0e20e)] - **test**: rename test-regress-GH-4015 (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`da44c2ccf0`](https://github.com/nodejs/node/commit/da44c2ccf0)] - **test**: rename test-regress-GH-1697 (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`fa43d2f69e`](https://github.com/nodejs/node/commit/fa43d2f69e)] - **test**: rename test-regress-GH-1726 (Ujjwal Sharma) [#19161](https://github.com/nodejs/node/pull/19161)
+* [[`46b5915dab`](https://github.com/nodejs/node/commit/46b5915dab)] - **test**: skip postmortem metadata test when nm fails (Joyee Cheung) [#19107](https://github.com/nodejs/node/pull/19107)
+* [[`16ab3b54d1`](https://github.com/nodejs/node/commit/16ab3b54d1)] - **test**: address unreliable test-performance (Rich Trott) [#19228](https://github.com/nodejs/node/pull/19228)
+* [[`1e5c7e3e47`](https://github.com/nodejs/node/commit/1e5c7e3e47)] - **test**: refactor common.expectsError (Ruben Bridgewater) [#17703](https://github.com/nodejs/node/pull/17703)
+* [[`060216689a`](https://github.com/nodejs/node/commit/060216689a)] - **(SEMVER-MINOR)** **tls**: expose Finished messages in TLSSocket (Anton Salikhmetov) [#19102](https://github.com/nodejs/node/pull/19102)
+* [[`b04dd7b351`](https://github.com/nodejs/node/commit/b04dd7b351)] - **tools**: enable eslint one-var rule (Ruben Bridgewater) [#18831](https://github.com/nodejs/node/pull/18831)
+* [[`d4d7df8371`](https://github.com/nodejs/node/commit/d4d7df8371)] - **tools**: enable eslint strict key-spacing (Ruben Bridgewater) [#18831](https://github.com/nodejs/node/pull/18831)
+* [[`9e10ddc215`](https://github.com/nodejs/node/commit/9e10ddc215)] - **tools**: enable eslint no-undef-init rule (Ruben Bridgewater) [#18831](https://github.com/nodejs/node/pull/18831)
+* [[`9d1e409ee3`](https://github.com/nodejs/node/commit/9d1e409ee3)] - **tools**: enable no-unsafe-finally (Ruben Bridgewater) [#18745](https://github.com/nodejs/node/pull/18745)
+* [[`d7958657d7`](https://github.com/nodejs/node/commit/d7958657d7)] - **tools**: add assert.doesNotThrow eslint rule (Ruben Bridgewater) [#18669](https://github.com/nodejs/node/pull/18669)
+* [[`66694e28b1`](https://github.com/nodejs/node/commit/66694e28b1)] - **tools**: fix test-npm-package (Michaël Zasso) [#19293](https://github.com/nodejs/node/pull/19293)
+* [[`9613e02ff7`](https://github.com/nodejs/node/commit/9613e02ff7)] - **tools,bootstrap**: preprocess gypi files to json (Gus Caplan) [#19140](https://github.com/nodejs/node/pull/19140)
+* [[`74f0d1aa60`](https://github.com/nodejs/node/commit/74f0d1aa60)] - **(SEMVER-MINOR)** **tty**: refactor to es6 (Ruben Bridgewater) [#17615](https://github.com/nodejs/node/pull/17615)
+* [[`ead727c274`](https://github.com/nodejs/node/commit/ead727c274)] - **(SEMVER-MINOR)** **tty**: add getColorDepth function (Ruben Bridgewater) [#17615](https://github.com/nodejs/node/pull/17615)
+* [[`072adfea8c`](https://github.com/nodejs/node/commit/072adfea8c)] - **url**: replace "magic" numbers by constants (Sergey Golovin) [#19035](https://github.com/nodejs/node/pull/19035)
+* [[`c18ac52970`](https://github.com/nodejs/node/commit/c18ac52970)] - **(SEMVER-MINOR)** **util**: add util.inspect compact option (Ruben Bridgewater) [#17576](https://github.com/nodejs/node/pull/17576)
+* [[`ce3a5af69f`](https://github.com/nodejs/node/commit/ce3a5af69f)] - **(SEMVER-MINOR)** **util**: rename util.inspect argument (Ruben Bridgewater) [#17576](https://github.com/nodejs/node/pull/17576)
+* [[`fd4c05ab56`](https://github.com/nodejs/node/commit/fd4c05ab56)] - **(SEMVER-MINOR)** **util**: fix custom inspect description (Ruben Bridgewater) [#17576](https://github.com/nodejs/node/pull/17576)
+
## 2018-03-07, Version 9.8.0 (Current), @MylesBorins
diff --git a/doc/onboarding-extras.md b/doc/onboarding-extras.md
index fa2d1ae02d9b60..2bbf2957835295 100644
--- a/doc/onboarding-extras.md
+++ b/doc/onboarding-extras.md
@@ -50,28 +50,25 @@ If you cannot find who to cc for a file, `git shortlog -n -s ` may help.
## Labels
-### By Subsystem
+### Subsystems
-We generally sort issues by a concept of "subsystem" so that we know what
-part(s) of the codebase it touches.
+* `lib/*.js` (`assert`, `buffer`, etc.)
+* `build`
+* `doc`
+* `lib / src`
+* `test`
+* `tools`
-**Subsystems generally are**:
-
-* `lib/*.js`
-* `doc`, `build`, `tools`, `test`, `deps`, `lib / src` (special), and there may
- be others.
-* `meta` for anything non-code (process) related
-
-There may be more than one subsystem valid for any particular issue / PR.
+There may be more than one subsystem valid for any particular issue or pull
+request.
### General
-Please use these when possible / appropriate
-
* `confirmed-bug` - Bugs you have verified exist
* `discuss` - Things that need larger discussion
* `feature request` - Any issue that requests a new feature (usually not PRs)
* `good first issue` - Issues suitable for newcomers to process
+* `meta` - For issues whose topic is governance, policies, procedures, etc.
--
@@ -145,10 +142,7 @@ to update from nodejs/node:
* `git remote update -p` OR `git fetch --all` (I prefer the former)
* `git merge --ff-only upstream/master` (or `REMOTENAME/BRANCH`)
-## best practices
+## Best practices
-* commit often, out to your github fork (origin), open a PR
-* when making PRs make sure to spend time on the description:
- * every moment you spend writing a good description quarters the amount of
- time it takes to understand your code.
-* usually prefer to only squash at the *end* of your work, depends on the change
+* When making PRs, spend time writing a thorough description.
+* Usually only squash at the end of your work.
diff --git a/doc/onboarding.md b/doc/onboarding.md
index a85e493d3c7561..17d5e74f41ade9 100644
--- a/doc/onboarding.md
+++ b/doc/onboarding.md
@@ -6,16 +6,21 @@ onboarding session.
## One week before the onboarding session
* If the new Collaborator is not yet a member of the nodejs GitHub organization,
- confirm that they are using two-factor authentication. It will not be possible
- to add them to the organization if they are not using two-factor
- authentication.
+ confirm that they are using [two-factor authentication][]. It will not be
+ possible to add them to the organization if they are not using two-factor
+ authentication. If they cannot receive SMS messages from GitHub, try
+ [using a TOTP mobile app][].
* Announce the accepted nomination in a TSC meeting and in the TSC
mailing list.
+* Suggest the new Collaborator install [`node-core-utils`][] and
+ [set up the credentials][] for it.
## Fifteen minutes before the onboarding session
* Prior to the onboarding session, add the new Collaborator to
[the Collaborators team](https://github.com/orgs/nodejs/teams/collaborators).
+* Ask them if they want to join any subsystem teams. See
+ [Who to CC for Issues][who-to-cc].
## Onboarding session
@@ -87,7 +92,7 @@ onboarding session.
* When adding a `semver-*` label, add a comment explaining why you're adding
it. Do it right away so you don't forget!
-* [**See "Who to CC in issues"**](./onboarding-extras.md#who-to-cc-in-issues)
+* [**See "Who to CC in issues"**][who-to-cc]
* This will come more naturally over time
* For many of the teams listed there, you can ask to be added if you are
interested
@@ -183,7 +188,13 @@ onboarding session.
## Landing PRs
-* See the Collaborator Guide: [Landing Pull Requests][]
+See the Collaborator Guide: [Landing Pull Requests][].
+
+Note that commits in one PR that belong to one logical change should
+be squashed. It is rarely the case in onboarding exercises, so this
+needs to be pointed out separately during the onboarding.
+
+
## Exercise: Make a PR adding yourself to the README
@@ -202,9 +213,11 @@ onboarding session.
for 48/72 hours to land).
* Be sure to add the `PR-URL: ` and appropriate `Reviewed-By:`
metadata.
- * [`core-validate-commit`][] automates the validation of commit messages.
* [`node-core-utils`][] automates the generation of metadata and the landing
process. See the documentation of [`git-node`][].
+ * [`core-validate-commit`][] automates the validation of commit messages.
+ This will be run during `git node land --final` of the [`git-node`][]
+ command.
## Final notes
@@ -227,9 +240,13 @@ onboarding session.
[Code of Conduct]: https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md
[`core-validate-commit`]: https://github.com/evanlucas/core-validate-commit
-[`git-node`]: https://github.com/nodejs/node-core-utils#git-node
+[`git-node`]: https://github.com/nodejs/node-core-utils/blob/master/docs/git-node.md
[`node-core-utils`]: https://github.com/nodejs/node-core-utils
[Landing Pull Requests]: https://github.com/nodejs/node/blob/master/COLLABORATOR_GUIDE.md#landing-pull-requests
[https://github.com/nodejs/node/commit/ce986de829457c39257cd205067602e765768fb0]: https://github.com/nodejs/node/commit/ce986de829457c39257cd205067602e765768fb0
[Publicizing or hiding organization membership]: https://help.github.com/articles/publicizing-or-hiding-organization-membership/
+[set up the credentials]: https://github.com/nodejs/node-core-utils#setting-up-credentials
+[two-factor authentication]: https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
[Updating Node.js from Upstream]: ./onboarding-extras.md#updating-nodejs-from-upstream
+[using a TOTP mobile app]: https://help.github.com/articles/configuring-two-factor-authentication-via-a-totp-mobile-app/
+[who-to-cc]: ./onboarding-extras.md#who-to-cc-in-issues
diff --git a/lib/_stream_duplex.js b/lib/_stream_duplex.js
index 288b8b538c3219..79ff582f459109 100644
--- a/lib/_stream_duplex.js
+++ b/lib/_stream_duplex.js
@@ -29,39 +29,21 @@
module.exports = Duplex;
const util = require('util');
-const Readable = require('_stream_readable');
-const Writable = require('_stream_writable');
-
-util.inherits(Duplex, Readable);
-
-{
- // avoid scope creep, the keys array can then be collected
- const keys = Object.keys(Writable.prototype);
- for (var v = 0; v < keys.length; v++) {
- const method = keys[v];
- if (!Duplex.prototype[method])
- Duplex.prototype[method] = Writable.prototype[method];
- }
-}
+const DuplexBase = require('internal/streams/duplex_base');
+
+util.inherits(Duplex, DuplexBase);
function Duplex(options) {
if (!(this instanceof Duplex))
return new Duplex(options);
- Readable.call(this, options);
- Writable.call(this, options);
-
- if (options && options.readable === false)
- this.readable = false;
-
- if (options && options.writable === false)
- this.writable = false;
+ DuplexBase.call(this, options);
this.allowHalfOpen = true;
- if (options && options.allowHalfOpen === false)
+ if (options && options.allowHalfOpen === false) {
this.allowHalfOpen = false;
-
- this.once('end', onend);
+ this.once('end', onend);
+ }
}
Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
@@ -96,9 +78,8 @@ Object.defineProperty(Duplex.prototype, 'writableLength', {
// the no-half-open enforcer
function onend() {
- // if we allow half-open state, or if the writable side ended,
- // then we're ok.
- if (this.allowHalfOpen || this._writableState.ended)
+ // If the writable side ended, then we're ok.
+ if (this._writableState.ended)
return;
// no more data can be written.
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index e17ea3f5948e82..8d988cbdbc3b90 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -668,6 +668,16 @@ TLSSocket.prototype.getPeerCertificate = function(detailed) {
return null;
};
+TLSSocket.prototype.getFinished = function() {
+ if (this._handle)
+ return this._handle.getFinished();
+};
+
+TLSSocket.prototype.getPeerFinished = function() {
+ if (this._handle)
+ return this._handle.getPeerFinished();
+};
+
TLSSocket.prototype.getSession = function() {
if (this._handle) {
return this._handle.getSession();
diff --git a/lib/assert.js b/lib/assert.js
index 0d061dbff617f7..6c33af3fd4b2ca 100644
--- a/lib/assert.js
+++ b/lib/assert.js
@@ -22,7 +22,12 @@
const { isDeepEqual, isDeepStrictEqual } =
require('internal/util/comparisons');
-const errors = require('internal/errors');
+const { AssertionError, TypeError } = require('internal/errors');
+const { inspect } = require('util');
+
+const ERR_DIFF_DEACTIVATED = 0;
+const ERR_DIFF_NOT_EQUAL = 1;
+const ERR_DIFF_EQUAL = 2;
// The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
@@ -30,25 +35,21 @@ const errors = require('internal/errors');
const assert = module.exports = ok;
+const NO_EXCEPTION_SENTINEL = {};
+
// All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
-function innerFail(actual, expected, message, operator, stackStartFunction) {
- if (message instanceof Error) throw message;
+function innerFail(obj) {
+ if (obj.message instanceof Error) throw obj.message;
- throw new errors.AssertionError({
- message,
- actual,
- expected,
- operator,
- stackStartFunction
- });
+ throw new AssertionError(obj);
}
-function fail(actual, expected, message, operator, stackStartFunction) {
+function fail(actual, expected, message, operator, stackStartFn) {
const argsLen = arguments.length;
if (argsLen === 0) {
@@ -60,7 +61,13 @@ function fail(actual, expected, message, operator, stackStartFunction) {
operator = '!=';
}
- innerFail(actual, expected, message, operator, stackStartFunction || fail);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator,
+ stackStartFn: stackStartFn || fail
+ });
}
assert.fail = fail;
@@ -69,13 +76,21 @@ assert.fail = fail;
// new assert.AssertionError({ message: message,
// actual: actual,
// expected: expected });
-assert.AssertionError = errors.AssertionError;
+assert.AssertionError = AssertionError;
// Pure assertion tests whether a value is truthy, as determined
// by !!value.
function ok(value, message) {
- if (!value) innerFail(value, true, message, '==', ok);
+ if (!value) {
+ innerFail({
+ actual: value,
+ expected: true,
+ message,
+ operator: '==',
+ stackStartFn: ok
+ });
+ }
}
assert.ok = ok;
@@ -83,7 +98,15 @@ assert.ok = ok;
/* eslint-disable no-restricted-properties */
assert.equal = function equal(actual, expected, message) {
// eslint-disable-next-line eqeqeq
- if (actual != expected) innerFail(actual, expected, message, '==', equal);
+ if (actual != expected) {
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: '==',
+ stackStartFn: equal
+ });
+ }
};
// The non-equality assertion tests for whether two objects are not
@@ -91,43 +114,81 @@ assert.equal = function equal(actual, expected, message) {
assert.notEqual = function notEqual(actual, expected, message) {
// eslint-disable-next-line eqeqeq
if (actual == expected) {
- innerFail(actual, expected, message, '!=', notEqual);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: '!=',
+ stackStartFn: notEqual
+ });
}
};
// The equivalence assertion tests a deep equality relation.
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!isDeepEqual(actual, expected)) {
- innerFail(actual, expected, message, 'deepEqual', deepEqual);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: 'deepEqual',
+ stackStartFn: deepEqual
+ });
}
};
// The non-equivalence assertion tests for any deep inequality.
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (isDeepEqual(actual, expected)) {
- innerFail(actual, expected, message, 'notDeepEqual', notDeepEqual);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: 'notDeepEqual',
+ stackStartFn: notDeepEqual
+ });
}
};
/* eslint-enable */
assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
if (!isDeepStrictEqual(actual, expected)) {
- innerFail(actual, expected, message, 'deepStrictEqual', deepStrictEqual);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: 'deepStrictEqual',
+ stackStartFn: deepStrictEqual,
+ errorDiff: this === strict ? ERR_DIFF_EQUAL : ERR_DIFF_DEACTIVATED
+ });
}
};
assert.notDeepStrictEqual = notDeepStrictEqual;
function notDeepStrictEqual(actual, expected, message) {
if (isDeepStrictEqual(actual, expected)) {
- innerFail(actual, expected, message, 'notDeepStrictEqual',
- notDeepStrictEqual);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: 'notDeepStrictEqual',
+ stackStartFn: notDeepStrictEqual,
+ errorDiff: this === strict ? ERR_DIFF_NOT_EQUAL : ERR_DIFF_DEACTIVATED
+ });
}
}
// The strict equality assertion tests strict equality, as determined by ===.
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
- innerFail(actual, expected, message, '===', strictEqual);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: '===',
+ stackStartFn: strictEqual,
+ errorDiff: this === strict ? ERR_DIFF_EQUAL : ERR_DIFF_DEACTIVATED
+ });
}
};
@@ -135,14 +196,51 @@ assert.strictEqual = function strictEqual(actual, expected, message) {
// determined by !==.
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
- innerFail(actual, expected, message, '!==', notStrictEqual);
+ innerFail({
+ actual,
+ expected,
+ message,
+ operator: '!==',
+ stackStartFn: notStrictEqual,
+ errorDiff: this === strict ? ERR_DIFF_NOT_EQUAL : ERR_DIFF_DEACTIVATED
+ });
}
};
-function expectedException(actual, expected) {
+function compareExceptionKey(actual, expected, key, msg) {
+ if (!isDeepStrictEqual(actual[key], expected[key])) {
+ innerFail({
+ actual: actual[key],
+ expected: expected[key],
+ message: msg || `${key}: expected ${inspect(expected[key])}, ` +
+ `not ${inspect(actual[key])}`,
+ operator: 'throws',
+ stackStartFn: assert.throws
+ });
+ }
+}
+
+function expectedException(actual, expected, msg) {
if (typeof expected !== 'function') {
- // Should be a RegExp, if not fail hard
- return expected.test(actual);
+ if (expected instanceof RegExp)
+ return expected.test(actual);
+ // assert.doesNotThrow does not accept objects.
+ if (arguments.length === 2) {
+ throw new TypeError('ERR_INVALID_ARG_TYPE', 'expected',
+ ['Function', 'RegExp'], expected);
+ }
+ // The name and message could be non enumerable. Therefore test them
+ // explicitly.
+ if ('name' in expected) {
+ compareExceptionKey(actual, expected, 'name', msg);
+ }
+ if ('message' in expected) {
+ compareExceptionKey(actual, expected, 'message', msg);
+ }
+ for (const key of Object.keys(expected)) {
+ compareExceptionKey(actual, expected, key, msg);
+ }
+ return true;
}
// Guard instanceof against arrow functions as they don't have a prototype.
if (expected.prototype !== undefined && actual instanceof expected) {
@@ -154,59 +252,94 @@ function expectedException(actual, expected) {
return expected.call({}, actual) === true;
}
-function tryBlock(block) {
+function getActual(block) {
+ if (typeof block !== 'function') {
+ throw new TypeError('ERR_INVALID_ARG_TYPE', 'block', 'Function',
+ block);
+ }
try {
block();
} catch (e) {
return e;
}
+ return NO_EXCEPTION_SENTINEL;
}
-function innerThrows(shouldThrow, block, expected, message) {
- var details = '';
+// Expected to throw an error.
+assert.throws = function throws(block, error, message) {
+ const actual = getActual(block);
- if (typeof block !== 'function') {
- throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'block', 'Function',
- block);
- }
+ if (typeof error === 'string') {
+ if (arguments.length === 3)
+ throw new TypeError('ERR_INVALID_ARG_TYPE',
+ 'error',
+ ['Function', 'RegExp'],
+ error);
- if (typeof expected === 'string') {
- message = expected;
- expected = null;
+ message = error;
+ error = null;
}
- const actual = tryBlock(block);
-
- if (shouldThrow === true) {
- if (actual === undefined) {
- if (expected && expected.name) {
- details += ` (${expected.name})`;
- }
- details += message ? `: ${message}` : '.';
- fail(actual, expected, `Missing expected exception${details}`, 'throws');
- }
- if (expected && expectedException(actual, expected) === false) {
- throw actual;
- }
- } else if (actual !== undefined) {
- if (!expected || expectedException(actual, expected)) {
- details = message ? `: ${message}` : '.';
- fail(actual,
- expected,
- `Got unwanted exception${details}\n${actual.message}`,
- 'doesNotThrow');
+ if (actual === NO_EXCEPTION_SENTINEL) {
+ let details = '';
+ if (error && error.name) {
+ details += ` (${error.name})`;
}
+ details += message ? `: ${message}` : '.';
+ innerFail({
+ actual,
+ expected: error,
+ operator: 'throws',
+ message: `Missing expected exception${details}`,
+ stackStartFn: throws
+ });
+ }
+ if (error && expectedException(actual, error, message) === false) {
throw actual;
}
-}
-
-// Expected to throw an error.
-assert.throws = function throws(block, error, message) {
- innerThrows(true, block, error, message);
};
assert.doesNotThrow = function doesNotThrow(block, error, message) {
- innerThrows(false, block, error, message);
+ const actual = getActual(block);
+ if (actual === NO_EXCEPTION_SENTINEL)
+ return;
+
+ if (typeof error === 'string') {
+ message = error;
+ error = null;
+ }
+
+ if (!error || expectedException(actual, error)) {
+ const details = message ? `: ${message}` : '.';
+ innerFail({
+ actual,
+ expected: error,
+ operator: 'doesNotThrow',
+ message: `Got unwanted exception${details}\n${actual && actual.message}`,
+ stackStartFn: doesNotThrow
+ });
+ }
+ throw actual;
};
assert.ifError = function ifError(err) { if (err) throw err; };
+
+// Expose a strict only variant of assert
+function strict(value, message) {
+ if (!value) {
+ innerFail({
+ actual: value,
+ expected: true,
+ message,
+ operator: '==',
+ stackStartFn: strict
+ });
+ }
+}
+assert.strict = Object.assign(strict, assert, {
+ equal: assert.strictEqual,
+ deepEqual: assert.deepStrictEqual,
+ notEqual: assert.notStrictEqual,
+ notDeepEqual: assert.notDeepStrictEqual
+});
+assert.strict.strict = assert.strict;
diff --git a/lib/async_hooks.js b/lib/async_hooks.js
index 19e7886360c13f..b7ed6ab21b1365 100644
--- a/lib/async_hooks.js
+++ b/lib/async_hooks.js
@@ -77,12 +77,11 @@ class AsyncHook {
return this;
const prev_kTotals = hook_fields[kTotals];
- hook_fields[kTotals] = 0;
// createHook() has already enforced that the callbacks are all functions,
// so here simply increment the count of whether each callbacks exists or
// not.
- hook_fields[kTotals] += hook_fields[kInit] += +!!this[init_symbol];
+ hook_fields[kTotals] = hook_fields[kInit] += +!!this[init_symbol];
hook_fields[kTotals] += hook_fields[kBefore] += +!!this[before_symbol];
hook_fields[kTotals] += hook_fields[kAfter] += +!!this[after_symbol];
hook_fields[kTotals] += hook_fields[kDestroy] += +!!this[destroy_symbol];
@@ -105,9 +104,8 @@ class AsyncHook {
return this;
const prev_kTotals = hook_fields[kTotals];
- hook_fields[kTotals] = 0;
- hook_fields[kTotals] += hook_fields[kInit] -= +!!this[init_symbol];
+ hook_fields[kTotals] = hook_fields[kInit] -= +!!this[init_symbol];
hook_fields[kTotals] += hook_fields[kBefore] -= +!!this[before_symbol];
hook_fields[kTotals] += hook_fields[kAfter] -= +!!this[after_symbol];
hook_fields[kTotals] += hook_fields[kDestroy] -= +!!this[destroy_symbol];
diff --git a/lib/console.js b/lib/console.js
index ac75664e850e56..ad6276297f26f7 100644
--- a/lib/console.js
+++ b/lib/console.js
@@ -21,7 +21,7 @@
'use strict';
-const errors = require('internal/errors');
+const { ERR_CONSOLE_WRITABLE_STREAM } = require('internal/errors').codes;
const util = require('util');
const kCounts = Symbol('counts');
@@ -35,12 +35,12 @@ function Console(stdout, stderr, ignoreErrors = true) {
return new Console(stdout, stderr, ignoreErrors);
}
if (!stdout || typeof stdout.write !== 'function') {
- throw new errors.TypeError('ERR_CONSOLE_WRITABLE_STREAM', 'stdout');
+ throw new ERR_CONSOLE_WRITABLE_STREAM('stdout');
}
if (!stderr) {
stderr = stdout;
} else if (typeof stderr.write !== 'function') {
- throw new errors.TypeError('ERR_CONSOLE_WRITABLE_STREAM', 'stderr');
+ throw new ERR_CONSOLE_WRITABLE_STREAM('stderr');
}
var prop = {
diff --git a/lib/fs.js b/lib/fs.js
index d0a0280f4000b9..231303ec42c620 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -2011,8 +2011,7 @@ function ReadStream(path, options) {
this.flags = options.flags === undefined ? 'r' : options.flags;
this.mode = options.mode === undefined ? 0o666 : options.mode;
- this.start = typeof this.fd !== 'number' && options.start === undefined ?
- 0 : options.start;
+ this.start = options.start;
this.end = options.end;
this.autoClose = options.autoClose === undefined ? true : options.autoClose;
this.pos = undefined;
@@ -2046,6 +2045,12 @@ function ReadStream(path, options) {
this.pos = this.start;
}
+ // Backwards compatibility: Make sure `end` is a number regardless of `start`.
+ // TODO(addaleax): Make the above typecheck not depend on `start` instead.
+ // (That is a semver-major change).
+ if (typeof this.end !== 'number')
+ this.end = Infinity;
+
if (typeof this.fd !== 'number')
this.open();
@@ -2100,6 +2105,8 @@ ReadStream.prototype._read = function(n) {
if (this.pos !== undefined)
toRead = Math.min(this.end - this.pos + 1, toRead);
+ else
+ toRead = Math.min(this.end - this.bytesRead + 1, toRead);
// already read everything we were supposed to read!
// treat as EOF.
diff --git a/lib/internal/async_hooks.js b/lib/internal/async_hooks.js
index 6f9b5b0a93eee5..4977af637bd1da 100644
--- a/lib/internal/async_hooks.js
+++ b/lib/internal/async_hooks.js
@@ -207,11 +207,15 @@ function storeActiveHooks() {
// Don't want to make the assumption that kInit to kDestroy are indexes 0 to
// 4. So do this the long way.
active_hooks.tmp_fields = [];
- active_hooks.tmp_fields[kInit] = async_hook_fields[kInit];
- active_hooks.tmp_fields[kBefore] = async_hook_fields[kBefore];
- active_hooks.tmp_fields[kAfter] = async_hook_fields[kAfter];
- active_hooks.tmp_fields[kDestroy] = async_hook_fields[kDestroy];
- active_hooks.tmp_fields[kPromiseResolve] = async_hook_fields[kPromiseResolve];
+ copyHooks(active_hooks.tmp_fields, async_hook_fields);
+}
+
+function copyHooks(destination, source) {
+ destination[kInit] = source[kInit];
+ destination[kBefore] = source[kBefore];
+ destination[kAfter] = source[kAfter];
+ destination[kDestroy] = source[kDestroy];
+ destination[kPromiseResolve] = source[kPromiseResolve];
}
@@ -219,11 +223,7 @@ function storeActiveHooks() {
// during hook callback execution.
function restoreActiveHooks() {
active_hooks.array = active_hooks.tmp_array;
- async_hook_fields[kInit] = active_hooks.tmp_fields[kInit];
- async_hook_fields[kBefore] = active_hooks.tmp_fields[kBefore];
- async_hook_fields[kAfter] = active_hooks.tmp_fields[kAfter];
- async_hook_fields[kDestroy] = active_hooks.tmp_fields[kDestroy];
- async_hook_fields[kPromiseResolve] = active_hooks.tmp_fields[kPromiseResolve];
+ copyHooks(async_hook_fields, active_hooks.tmp_fields);
active_hooks.tmp_array = null;
active_hooks.tmp_fields = null;
diff --git a/lib/internal/constants.js b/lib/internal/constants.js
index f0ffec7a447529..c9a5bea833306f 100644
--- a/lib/internal/constants.js
+++ b/lib/internal/constants.js
@@ -8,9 +8,39 @@ module.exports = {
CHAR_LOWERCASE_Z: 122, /*z*/
// Non-alphabetic chars.
- CHAR_DOT: 46, /*.*/
- CHAR_FORWARD_SLASH: 47, /*/*/
- CHAR_BACKWARD_SLASH: 92, /*\*/
- CHAR_COLON: 58, /*:*/
- CHAR_QUESTION_MARK: 63, /*?*/
+ CHAR_DOT: 46, /* . */
+ CHAR_FORWARD_SLASH: 47, /* / */
+ CHAR_BACKWARD_SLASH: 92, /* \ */
+ CHAR_VERTICAL_LINE: 124, /* | */
+ CHAR_COLON: 58, /* : */
+ CHAR_QUESTION_MARK: 63, /* ? */
+ CHAR_UNDERSCORE: 95, /* _ */
+ CHAR_LINE_FEED: 10, /* \n */
+ CHAR_CARRIAGE_RETURN: 13, /* \r */
+ CHAR_TAB: 9, /* \t */
+ CHAR_FORM_FEED: 12, /* \f */
+ CHAR_EXCLAMATION_MARK: 33, /* ! */
+ CHAR_HASH: 35, /* # */
+ CHAR_SPACE: 32, /* */
+ CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */
+ CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */
+ CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */
+ CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */
+ CHAR_LEFT_ANGLE_BRACKET: 60, /* < */
+ CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */
+ CHAR_LEFT_CURLY_BRACKET: 123, /* { */
+ CHAR_RIGHT_CURLY_BRACKET: 125, /* } */
+ CHAR_HYPHEN_MINUS: 45, /* - */
+ CHAR_PLUS: 43, /* + */
+ CHAR_DOUBLE_QUOTE: 34, /* " */
+ CHAR_SINGLE_QUOTE: 39, /* ' */
+ CHAR_PERCENT: 37, /* % */
+ CHAR_SEMICOLON: 59, /* ; */
+ CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */
+ CHAR_GRAVE_ACCENT: 96, /* ` */
+ CHAR_AT: 64, /* @ */
+
+ // Digits
+ CHAR_0: 48, /* 0 */
+ CHAR_9: 57, /* 9 */
};
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index f4a77e037bc491..d08b1bfad156c0 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -12,6 +12,11 @@
const kCode = Symbol('code');
const messages = new Map();
+const codes = {};
+
+var green = '';
+var red = '';
+var white = '';
const {
UV_EAI_MEMORY,
@@ -78,22 +83,227 @@ function makeNodeError(Base) {
};
}
+function createErrDiff(actual, expected, operator) {
+ var other = '';
+ var res = '';
+ var lastPos = 0;
+ var end = '';
+ var skipped = false;
+ const util = lazyUtil();
+ const actualLines = util
+ .inspect(actual, { compact: false, customInspect: false }).split('\n');
+ const expectedLines = util
+ .inspect(expected, { compact: false, customInspect: false }).split('\n');
+ const msg = `Input A expected to ${operator} input B:\n` +
+ `${green}+ expected${white} ${red}- actual${white}`;
+ const skippedMsg = ' ... Lines skipped';
+
+ // Remove all ending lines that match (this optimizes the output for
+ // readability by reducing the number of total changed lines).
+ var a = actualLines[actualLines.length - 1];
+ var b = expectedLines[expectedLines.length - 1];
+ var i = 0;
+ while (a === b) {
+ if (i++ < 2) {
+ end = `\n ${a}${end}`;
+ } else {
+ other = a;
+ }
+ actualLines.pop();
+ expectedLines.pop();
+ if (actualLines.length === 0 || expectedLines.length === 0)
+ break;
+ a = actualLines[actualLines.length - 1];
+ b = expectedLines[expectedLines.length - 1];
+ }
+ if (i > 3) {
+ end = `\n...${end}`;
+ skipped = true;
+ }
+ if (other !== '') {
+ end = `\n ${other}${end}`;
+ other = '';
+ }
+
+ const maxLines = Math.max(actualLines.length, expectedLines.length);
+ var printedLines = 0;
+ for (i = 0; i < maxLines; i++) {
+ // Only extra expected lines exist
+ const cur = i - lastPos;
+ if (actualLines.length < i + 1) {
+ if (cur > 1 && i > 2) {
+ if (cur > 4) {
+ res += '\n...';
+ skipped = true;
+ } else if (cur > 3) {
+ res += `\n ${expectedLines[i - 2]}`;
+ printedLines++;
+ }
+ res += `\n ${expectedLines[i - 1]}`;
+ printedLines++;
+ }
+ lastPos = i;
+ other += `\n${green}+${white} ${expectedLines[i]}`;
+ printedLines++;
+ // Only extra actual lines exist
+ } else if (expectedLines.length < i + 1) {
+ if (cur > 1 && i > 2) {
+ if (cur > 4) {
+ res += '\n...';
+ skipped = true;
+ } else if (cur > 3) {
+ res += `\n ${actualLines[i - 2]}`;
+ printedLines++;
+ }
+ res += `\n ${actualLines[i - 1]}`;
+ printedLines++;
+ }
+ lastPos = i;
+ res += `\n${red}-${white} ${actualLines[i]}`;
+ printedLines++;
+ // Lines diverge
+ } else if (actualLines[i] !== expectedLines[i]) {
+ if (cur > 1 && i > 2) {
+ if (cur > 4) {
+ res += '\n...';
+ skipped = true;
+ } else if (cur > 3) {
+ res += `\n ${actualLines[i - 2]}`;
+ printedLines++;
+ }
+ res += `\n ${actualLines[i - 1]}`;
+ printedLines++;
+ }
+ lastPos = i;
+ res += `\n${red}-${white} ${actualLines[i]}`;
+ other += `\n${green}+${white} ${expectedLines[i]}`;
+ printedLines += 2;
+ // Lines are identical
+ } else {
+ res += other;
+ other = '';
+ if (cur === 1 || i === 0) {
+ res += `\n ${actualLines[i]}`;
+ printedLines++;
+ }
+ }
+ // Inspected object to big (Show ~20 rows max)
+ if (printedLines > 20 && i < maxLines - 2) {
+ return `${msg}${skippedMsg}\n${res}\n...${other}\n...`;
+ }
+ }
+ return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}`;
+}
+
+function makeNodeErrorWithCode(Base, key) {
+ return class NodeError extends Base {
+ constructor(...args) {
+ super(message(key, args));
+ }
+
+ get name() {
+ return `${super.name} [${key}]`;
+ }
+
+ set name(value) {
+ defineProperty(this, 'name', {
+ configurable: true,
+ enumerable: true,
+ value,
+ writable: true
+ });
+ }
+
+ get code() {
+ return key;
+ }
+
+ set code(value) {
+ defineProperty(this, 'code', {
+ configurable: true,
+ enumerable: true,
+ value,
+ writable: true
+ });
+ }
+ };
+}
+
+// Utility function for registering the error codes. Only used here. Exported
+// *only* to allow for testing.
+function E(sym, val, def, ...otherClasses) {
+ messages.set(sym, val);
+ if (def === undefined) return;
+ def = makeNodeErrorWithCode(def, sym);
+ if (otherClasses.length !== 0) {
+ otherClasses.forEach((clazz) => {
+ def[clazz.name] = makeNodeErrorWithCode(clazz, sym);
+ });
+ }
+ codes[sym] = def;
+}
+
class AssertionError extends Error {
constructor(options) {
if (typeof options !== 'object' || options === null) {
throw new exports.TypeError('ERR_INVALID_ARG_TYPE', 'options', 'Object');
}
- var { actual, expected, message, operator, stackStartFunction } = options;
- if (message) {
+ var {
+ actual,
+ expected,
+ message,
+ operator,
+ stackStartFn,
+ errorDiff = 0
+ } = options;
+
+ if (message != null) {
super(message);
} else {
+ if (util_ === null &&
+ process.stdout.isTTY &&
+ process.stdout.getColorDepth() !== 1) {
+ green = '\u001b[32m';
+ white = '\u001b[39m';
+ red = '\u001b[31m';
+ }
const util = lazyUtil();
- if (actual && actual.stack && actual instanceof Error)
+ if (typeof actual === 'object' && actual !== null &&
+ 'stack' in actual && actual instanceof Error) {
actual = `${actual.name}: ${actual.message}`;
- if (expected && expected.stack && expected instanceof Error)
+ }
+ if (typeof expected === 'object' && expected !== null &&
+ 'stack' in expected && expected instanceof Error) {
expected = `${expected.name}: ${expected.message}`;
- super(`${util.inspect(actual).slice(0, 128)} ` +
- `${operator} ${util.inspect(expected).slice(0, 128)}`);
+ }
+
+ if (errorDiff === 0) {
+ let res = util.inspect(actual);
+ let other = util.inspect(expected);
+ if (res.length > 128)
+ res = `${res.slice(0, 125)}...`;
+ if (other.length > 128)
+ other = `${other.slice(0, 125)}...`;
+ super(`${res} ${operator} ${other}`);
+ } else if (errorDiff === 1) {
+ // In case the objects are equal but the operator requires unequal, show
+ // the first object and say A equals B
+ const res = util.inspect(
+ actual,
+ { compact: false, customInspect: false }
+ ).split('\n');
+
+ if (res.length > 20) {
+ res[19] = '...';
+ while (res.length > 20) {
+ res.pop();
+ }
+ }
+ // Only print a single object.
+ super(`Identical input passed to ${operator}:\n${res.join('\n')}`);
+ } else {
+ super(createErrDiff(actual, expected, operator));
+ }
}
this.generatedMessage = !message;
@@ -102,7 +312,7 @@ class AssertionError extends Error {
this.actual = actual;
this.expected = expected;
this.operator = operator;
- Error.captureStackTrace(this, stackStartFunction);
+ Error.captureStackTrace(this, stackStartFn);
}
}
@@ -135,12 +345,6 @@ function message(key, args) {
return String(fmt.apply(null, args));
}
-// Utility function for registering the error codes. Only used here. Exported
-// *only* to allow for testing.
-function E(sym, val) {
- messages.set(sym, typeof val === 'function' ? val : String(val));
-}
-
/**
* This used to be util._errnoException().
*
@@ -251,6 +455,7 @@ module.exports = exports = {
RangeError: makeNodeError(RangeError),
URIError: makeNodeError(URIError),
AssertionError,
+ codes,
E // This is exported only to facilitate testing.
};
@@ -267,124 +472,135 @@ module.exports = exports = {
// Any error code added here should also be added to the documentation
//
// Note: Please try to keep these in alphabetical order
-E('ERR_ARG_NOT_ITERABLE', '%s must be iterable');
-E('ERR_ASSERTION', '%s');
-E('ERR_ASYNC_CALLBACK', '%s must be a function');
-E('ERR_ASYNC_TYPE', 'Invalid name for async "type": %s');
-E('ERR_BUFFER_OUT_OF_BOUNDS', bufferOutOfBounds);
+//
+// Note: Node.js specific errors must begin with the prefix ERR_
+
+E('ERR_ARG_NOT_ITERABLE', '%s must be iterable', TypeError);
+E('ERR_ASSERTION', '%s', AssertionError);
+E('ERR_ASYNC_CALLBACK', '%s must be a function', TypeError);
+E('ERR_ASYNC_TYPE', 'Invalid name for async "type": %s', TypeError);
+E('ERR_BUFFER_OUT_OF_BOUNDS', bufferOutOfBounds, RangeError);
E('ERR_BUFFER_TOO_LARGE',
- `Cannot create a Buffer larger than 0x${kMaxLength.toString(16)} bytes`);
-E('ERR_CHILD_CLOSED_BEFORE_REPLY', 'Child closed before reply received');
+ `Cannot create a Buffer larger than 0x${kMaxLength.toString(16)} bytes`,
+ RangeError);
+E('ERR_CHILD_CLOSED_BEFORE_REPLY',
+ 'Child closed before reply received', Error);
E('ERR_CONSOLE_WRITABLE_STREAM',
- 'Console expects a writable stream instance for %s');
-E('ERR_CPU_USAGE', 'Unable to obtain cpu usage %s');
+ 'Console expects a writable stream instance for %s', TypeError);
+E('ERR_CPU_USAGE', 'Unable to obtain cpu usage %s', Error);
E('ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
- 'Custom engines not supported by this OpenSSL');
-E('ERR_CRYPTO_ECDH_INVALID_FORMAT', 'Invalid ECDH format: %s');
-E('ERR_CRYPTO_ENGINE_UNKNOWN', 'Engine "%s" was not found');
+ 'Custom engines not supported by this OpenSSL', Error);
+E('ERR_CRYPTO_ECDH_INVALID_FORMAT', 'Invalid ECDH format: %s', TypeError);
+E('ERR_CRYPTO_ENGINE_UNKNOWN', 'Engine "%s" was not found', Error);
E('ERR_CRYPTO_FIPS_FORCED',
- 'Cannot set FIPS mode, it was forced with --force-fips at startup.');
-E('ERR_CRYPTO_FIPS_UNAVAILABLE', 'Cannot set FIPS mode in a non-FIPS build.');
-E('ERR_CRYPTO_HASH_DIGEST_NO_UTF16', 'hash.digest() does not support UTF-16');
-E('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called');
-E('ERR_CRYPTO_HASH_UPDATE_FAILED', 'Hash update failed');
-E('ERR_CRYPTO_INVALID_DIGEST', 'Invalid digest: %s');
-E('ERR_CRYPTO_SIGN_KEY_REQUIRED', 'No key provided to sign');
+ 'Cannot set FIPS mode, it was forced with --force-fips at startup.', Error);
+E('ERR_CRYPTO_FIPS_UNAVAILABLE', 'Cannot set FIPS mode in a non-FIPS build.',
+ Error);
+E('ERR_CRYPTO_HASH_DIGEST_NO_UTF16', 'hash.digest() does not support UTF-16',
+ Error);
+E('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called', Error);
+E('ERR_CRYPTO_HASH_UPDATE_FAILED', 'Hash update failed', Error);
+E('ERR_CRYPTO_INVALID_DIGEST', 'Invalid digest: %s', TypeError);
+// Switch to TypeError. The current implementation does not seem right.
+E('ERR_CRYPTO_SIGN_KEY_REQUIRED', 'No key provided to sign', Error);
E('ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH',
- 'Input buffers must have the same length');
-E('ERR_DNS_SET_SERVERS_FAILED', 'c-ares failed to set servers: "%s" [%s]');
+ 'Input buffers must have the same length', RangeError);
+E('ERR_DNS_SET_SERVERS_FAILED', 'c-ares failed to set servers: "%s" [%s]',
+ Error);
E('ERR_DOMAIN_CALLBACK_NOT_AVAILABLE',
'A callback was registered through ' +
- 'process.setUncaughtExceptionCaptureCallback(), which is mutually ' +
- 'exclusive with using the `domain` module');
+ 'process.setUncaughtExceptionCaptureCallback(), which is mutually ' +
+ 'exclusive with using the `domain` module',
+ Error);
E('ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE',
'The `domain` module is in use, which is mutually exclusive with calling ' +
- 'process.setUncaughtExceptionCaptureCallback()');
+ 'process.setUncaughtExceptionCaptureCallback()',
+ Error);
E('ERR_ENCODING_INVALID_ENCODED_DATA',
- 'The encoded data was not valid for encoding %s');
-E('ERR_ENCODING_NOT_SUPPORTED', 'The "%s" encoding is not supported');
-E('ERR_FALSY_VALUE_REJECTION', 'Promise was rejected with falsy value');
-E('ERR_HTTP2_ALREADY_SHUTDOWN',
- 'Http2Session is already shutdown or destroyed');
+ 'The encoded data was not valid for encoding %s', TypeError);
+E('ERR_ENCODING_NOT_SUPPORTED', 'The "%s" encoding is not supported',
+ RangeError); // One entry is currently falsy implemented as "Error"
+E('ERR_FALSY_VALUE_REJECTION', 'Promise was rejected with falsy value', Error);
E('ERR_HTTP2_ALTSVC_INVALID_ORIGIN',
- 'HTTP/2 ALTSVC frames require a valid origin');
+ 'HTTP/2 ALTSVC frames require a valid origin', TypeError);
E('ERR_HTTP2_ALTSVC_LENGTH',
- 'HTTP/2 ALTSVC frames are limited to 16382 bytes');
+ 'HTTP/2 ALTSVC frames are limited to 16382 bytes', TypeError);
E('ERR_HTTP2_CONNECT_AUTHORITY',
- ':authority header is required for CONNECT requests');
+ ':authority header is required for CONNECT requests', Error);
E('ERR_HTTP2_CONNECT_PATH',
- 'The :path header is forbidden for CONNECT requests');
+ 'The :path header is forbidden for CONNECT requests', Error);
E('ERR_HTTP2_CONNECT_SCHEME',
- 'The :scheme header is forbidden for CONNECT requests');
-E('ERR_HTTP2_FRAME_ERROR',
- (type, code, id) => {
- let msg = `Error sending frame type ${type}`;
- if (id !== undefined)
- msg += ` for stream ${id}`;
- msg += ` with code ${code}`;
- return msg;
- });
+ 'The :scheme header is forbidden for CONNECT requests', Error);
E('ERR_HTTP2_GOAWAY_SESSION',
- 'New streams cannot be created after receiving a GOAWAY');
+ 'New streams cannot be created after receiving a GOAWAY', Error);
E('ERR_HTTP2_HEADERS_AFTER_RESPOND',
- 'Cannot specify additional headers after response initiated');
-E('ERR_HTTP2_HEADERS_OBJECT', 'Headers must be an object');
-E('ERR_HTTP2_HEADERS_SENT', 'Response has already been initiated.');
-E('ERR_HTTP2_HEADER_REQUIRED', 'The %s header is required');
+ 'Cannot specify additional headers after response initiated', Error);
+E('ERR_HTTP2_HEADERS_SENT', 'Response has already been initiated.', Error);
+
+// This should probably be a `TypeError`.
E('ERR_HTTP2_HEADER_SINGLE_VALUE',
- 'Header field "%s" must have only a single value');
-E('ERR_HTTP2_INFO_HEADERS_AFTER_RESPOND',
- 'Cannot send informational headers after the HTTP message has been sent');
+ 'Header field "%s" must have only a single value', Error);
E('ERR_HTTP2_INFO_STATUS_NOT_ALLOWED',
- 'Informational status codes cannot be used');
+ 'Informational status codes cannot be used', RangeError);
+
+// This should probably be a `TypeError`.
E('ERR_HTTP2_INVALID_CONNECTION_HEADERS',
- 'HTTP/1 Connection specific headers are forbidden: "%s"');
-E('ERR_HTTP2_INVALID_HEADER_VALUE', 'Invalid value "%s" for header "%s"');
+ 'HTTP/1 Connection specific headers are forbidden: "%s"', Error);
+E('ERR_HTTP2_INVALID_HEADER_VALUE',
+ 'Invalid value "%s" for header "%s"', TypeError);
E('ERR_HTTP2_INVALID_INFO_STATUS',
- 'Invalid informational status code: %s');
+ 'Invalid informational status code: %s', RangeError);
E('ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH',
- 'Packed settings length must be a multiple of six');
+ 'Packed settings length must be a multiple of six', RangeError);
+
+// This should probably be a `TypeError`.
E('ERR_HTTP2_INVALID_PSEUDOHEADER',
- '"%s" is an invalid pseudoheader or is used incorrectly');
-E('ERR_HTTP2_INVALID_SESSION', 'The session has been destroyed');
+ '"%s" is an invalid pseudoheader or is used incorrectly', Error);
+E('ERR_HTTP2_INVALID_SESSION', 'The session has been destroyed', Error);
E('ERR_HTTP2_INVALID_SETTING_VALUE',
- 'Invalid value for setting "%s": %s');
-E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed');
+ 'Invalid value for setting "%s": %s', TypeError, RangeError);
+E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error);
E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK',
- 'Maximum number of pending settings acknowledgements (%s)');
+ 'Maximum number of pending settings acknowledgements (%s)', Error);
E('ERR_HTTP2_NO_SOCKET_MANIPULATION',
- 'HTTP/2 sockets should not be directly manipulated (e.g. read and written)');
+ 'HTTP/2 sockets should not be directly manipulated (e.g. read and written)',
+ Error);
E('ERR_HTTP2_OUT_OF_STREAMS',
- 'No stream ID is available because maximum stream ID has been reached');
+ 'No stream ID is available because maximum stream ID has been reached',
+ Error);
E('ERR_HTTP2_PAYLOAD_FORBIDDEN',
- 'Responses with %s status must not have a payload');
-E('ERR_HTTP2_PING_CANCEL', 'HTTP2 ping cancelled');
-E('ERR_HTTP2_PING_LENGTH', 'HTTP2 ping payload must be 8 bytes');
-E('ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED', 'Cannot set HTTP/2 pseudo-headers');
-E('ERR_HTTP2_PUSH_DISABLED', 'HTTP/2 client has disabled push streams');
-E('ERR_HTTP2_SEND_FILE', 'Only regular files can be sent');
-E('ERR_HTTP2_SESSION_ERROR', 'Session closed with error code %s');
+ 'Responses with %s status must not have a payload', Error);
+E('ERR_HTTP2_PING_CANCEL', 'HTTP2 ping cancelled', Error);
+E('ERR_HTTP2_PING_LENGTH', 'HTTP2 ping payload must be 8 bytes', RangeError);
+
+// This should probably be a `TypeError`.
+E('ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED',
+ 'Cannot set HTTP/2 pseudo-headers', Error);
+E('ERR_HTTP2_PUSH_DISABLED', 'HTTP/2 client has disabled push streams', Error);
+E('ERR_HTTP2_SEND_FILE', 'Only regular files can be sent', Error);
+E('ERR_HTTP2_SESSION_ERROR', 'Session closed with error code %s', Error);
E('ERR_HTTP2_SOCKET_BOUND',
- 'The socket is already bound to an Http2Session');
+ 'The socket is already bound to an Http2Session', Error);
E('ERR_HTTP2_STATUS_101',
- 'HTTP status code 101 (Switching Protocols) is forbidden in HTTP/2');
-E('ERR_HTTP2_STATUS_INVALID', 'Invalid status code: %s');
-E('ERR_HTTP2_STREAM_CANCEL', 'The pending stream has been canceled');
-E('ERR_HTTP2_STREAM_ERROR', 'Stream closed with error code %s');
-E('ERR_HTTP2_STREAM_SELF_DEPENDENCY', 'A stream cannot depend on itself');
-E('ERR_HTTP2_UNSUPPORTED_PROTOCOL', 'protocol "%s" is unsupported.');
+ 'HTTP status code 101 (Switching Protocols) is forbidden in HTTP/2', Error);
+E('ERR_HTTP2_STATUS_INVALID', 'Invalid status code: %s', RangeError);
+E('ERR_HTTP2_STREAM_CANCEL', 'The pending stream has been canceled', Error);
+E('ERR_HTTP2_STREAM_ERROR', 'Stream closed with error code %s', Error);
+E('ERR_HTTP2_STREAM_SELF_DEPENDENCY',
+ 'A stream cannot depend on itself', Error);
+E('ERR_HTTP2_UNSUPPORTED_PROTOCOL', 'protocol "%s" is unsupported.', Error);
E('ERR_HTTP_HEADERS_SENT',
- 'Cannot %s headers after they are sent to the client');
-E('ERR_HTTP_INVALID_CHAR', 'Invalid character in statusMessage.');
-E('ERR_HTTP_INVALID_STATUS_CODE', 'Invalid status code: %s');
+ 'Cannot %s headers after they are sent to the client', Error);
+E('ERR_HTTP_INVALID_STATUS_CODE', 'Invalid status code: %s', RangeError);
E('ERR_HTTP_TRAILER_INVALID',
- 'Trailers are invalid with this transfer encoding');
-E('ERR_INDEX_OUT_OF_RANGE', 'Index out of range');
-E('ERR_INSPECTOR_ALREADY_CONNECTED', 'The inspector is already connected');
-E('ERR_INSPECTOR_CLOSED', 'Session was closed');
-E('ERR_INSPECTOR_NOT_AVAILABLE', 'Inspector is not available');
-E('ERR_INSPECTOR_NOT_CONNECTED', 'Session is not connected');
-E('ERR_INVALID_ARG_TYPE', invalidArgType);
+ 'Trailers are invalid with this transfer encoding', Error);
+E('ERR_INDEX_OUT_OF_RANGE', 'Index out of range', RangeError);
+E('ERR_INSPECTOR_ALREADY_CONNECTED',
+ 'The inspector is already connected', Error);
+E('ERR_INSPECTOR_CLOSED', 'Session was closed', Error);
+E('ERR_INSPECTOR_NOT_AVAILABLE', 'Inspector is not available', Error);
+E('ERR_INSPECTOR_NOT_CONNECTED', 'Session is not connected', Error);
+E('ERR_INVALID_ARG_TYPE', invalidArgType, TypeError);
E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => {
const util = lazyUtil();
let inspected = util.inspect(value);
@@ -392,136 +608,165 @@ E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => {
inspected = inspected.slice(0, 128) + '...';
}
return `The argument '${name}' ${reason}. Received ${inspected}`;
-}),
+}, TypeError, RangeError); // Some are currently falsy implemented as "Error"
E('ERR_INVALID_ARRAY_LENGTH',
(name, len, actual) => {
internalAssert(typeof actual === 'number', 'actual must be a number');
return `The array "${name}" (length ${actual}) must be of length ${len}.`;
- });
-E('ERR_INVALID_ASYNC_ID', 'Invalid %s value: %s');
-E('ERR_INVALID_BUFFER_SIZE', 'Buffer size must be a multiple of %s');
-E('ERR_INVALID_CALLBACK', 'Callback must be a function');
-E('ERR_INVALID_CHAR', invalidChar);
+ }, TypeError);
+E('ERR_INVALID_ASYNC_ID', 'Invalid %s value: %s', RangeError);
+E('ERR_INVALID_BUFFER_SIZE',
+ 'Buffer size must be a multiple of %s', RangeError);
+E('ERR_INVALID_CALLBACK', 'Callback must be a function', TypeError);
+E('ERR_INVALID_CHAR', invalidChar, TypeError); //Check falsy "Error" entries.
+
+// This should probably be a `TypeError`.
E('ERR_INVALID_CURSOR_POS',
- 'Cannot set cursor row without setting its column');
-E('ERR_INVALID_DOMAIN_NAME', 'Unable to determine the domain name');
-E('ERR_INVALID_FD', '"fd" must be a positive integer: %s');
-E('ERR_INVALID_FD_TYPE', 'Unsupported fd type: %s');
+ 'Cannot set cursor row without setting its column', Error);
+
+// This should probably be a `TypeError`.
+E('ERR_INVALID_DOMAIN_NAME', 'Unable to determine the domain name', Error);
+E('ERR_INVALID_FD',
+ '"fd" must be a positive integer: %s', RangeError);
+E('ERR_INVALID_FD_TYPE', 'Unsupported fd type: %s', TypeError);
E('ERR_INVALID_FILE_URL_HOST',
- 'File URL host must be "localhost" or empty on %s');
-E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s');
-E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent');
-E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]');
-E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s');
+ 'File URL host must be "localhost" or empty on %s', TypeError);
+E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s', TypeError);
+E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent', TypeError);
+E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]', TypeError);
+// The `Error` should probably be a `TypeError`.
+E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s', TypeError, Error);
E('ERR_INVALID_OPT_VALUE', (name, value) =>
- `The value "${String(value)}" is invalid for option "${name}"`);
+ `The value "${String(value)}" is invalid for option "${name}"`,
+ TypeError,
+ RangeError);
E('ERR_INVALID_OPT_VALUE_ENCODING',
- 'The value "%s" is invalid for option "encoding"');
-E('ERR_INVALID_PERFORMANCE_MARK', 'The "%s" performance mark has not been set');
-E('ERR_INVALID_PROTOCOL', 'Protocol "%s" not supported. Expected "%s"');
+ 'The value "%s" is invalid for option "encoding"', TypeError);
+E('ERR_INVALID_PERFORMANCE_MARK',
+ 'The "%s" performance mark has not been set', Error);
+
+// This should probably be a `TypeError`.
+E('ERR_INVALID_PROTOCOL', 'Protocol "%s" not supported. Expected "%s"', Error);
+
+// This should probably be a `TypeError`.
E('ERR_INVALID_REPL_EVAL_CONFIG',
- 'Cannot specify both "breakEvalOnSigint" and "eval" for REPL');
+ 'Cannot specify both "breakEvalOnSigint" and "eval" for REPL', Error);
E('ERR_INVALID_SYNC_FORK_INPUT',
- 'Asynchronous forks do not support Buffer, Uint8Array or string input: %s');
-E('ERR_INVALID_THIS', 'Value of "this" must be of type %s');
-E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple');
-E('ERR_INVALID_URI', 'URI malformed');
-E('ERR_INVALID_URL', 'Invalid URL: %s');
+ 'Asynchronous forks do not support Buffer, Uint8Array or string input: %s',
+ TypeError);
+E('ERR_INVALID_THIS', 'Value of "this" must be of type %s', TypeError);
+E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple', TypeError);
+E('ERR_INVALID_URI', 'URI malformed', URIError);
+E('ERR_INVALID_URL', 'Invalid URL: %s', TypeError);
E('ERR_INVALID_URL_SCHEME',
- (expected) => `The URL must be ${oneOf(expected, 'scheme')}`);
-E('ERR_IPC_CHANNEL_CLOSED', 'Channel closed');
-E('ERR_IPC_DISCONNECTED', 'IPC channel is already disconnected');
-E('ERR_IPC_ONE_PIPE', 'Child process can have only one IPC pipe');
-E('ERR_IPC_SYNC_FORK', 'IPC cannot be used with synchronous forks');
-E('ERR_METHOD_NOT_IMPLEMENTED', 'The %s method is not implemented');
-E('ERR_MISSING_ARGS', missingArgs);
-E('ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK',
- 'The ES Module loader may not return a format of \'dynamic\' when no ' +
- 'dynamicInstantiate function was provided');
-E('ERR_MISSING_MODULE', 'Cannot find module %s');
-E('ERR_MODULE_RESOLUTION_LEGACY', '%s not found by import in %s.' +
- ' Legacy behavior in require() would have found it at %s');
-E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');
-E('ERR_NAPI_CONS_FUNCTION', 'Constructor must be a function');
-E('ERR_NAPI_CONS_PROTOTYPE_OBJECT', 'Constructor.prototype must be an object');
+ (expected) => `The URL must be ${oneOf(expected, 'scheme')}`, TypeError);
+E('ERR_IPC_CHANNEL_CLOSED', 'Channel closed', Error);
+E('ERR_IPC_DISCONNECTED', 'IPC channel is already disconnected', Error);
+E('ERR_IPC_ONE_PIPE', 'Child process can have only one IPC pipe', Error);
+E('ERR_IPC_SYNC_FORK', 'IPC cannot be used with synchronous forks', Error);
+E('ERR_METHOD_NOT_IMPLEMENTED', 'The %s method is not implemented', Error);
+E('ERR_MISSING_ARGS', missingArgs, TypeError);
+E('ERR_MISSING_MODULE', 'Cannot find module %s', Error);
+E('ERR_MODULE_RESOLUTION_LEGACY',
+ '%s not found by import in %s.' +
+ ' Legacy behavior in require() would have found it at %s',
+ Error);
+E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error);
+E('ERR_NAPI_CONS_FUNCTION', 'Constructor must be a function', TypeError);
E('ERR_NAPI_INVALID_DATAVIEW_ARGS',
'byte_offset + byte_length should be less than or eqaul to the size in ' +
- 'bytes of the array passed in');
-E('ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT', 'start offset of %s should be a ' +
- 'multiple of %s');
-E('ERR_NAPI_INVALID_TYPEDARRAY_LENGTH', 'Invalid typed array length');
-E('ERR_NO_CRYPTO', 'Node.js is not compiled with OpenSSL crypto support');
-E('ERR_NO_ICU', '%s is not supported on Node.js compiled without ICU');
-E('ERR_NO_LONGER_SUPPORTED', '%s is no longer supported');
-E('ERR_OUT_OF_RANGE', 'The "%s" argument is out of range');
-E('ERR_PARSE_HISTORY_DATA', 'Could not parse history data in %s');
-E('ERR_REQUIRE_ESM', 'Must use import to load ES Module: %s');
+ 'bytes of the array passed in',
+ RangeError);
+E('ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT',
+ 'start offset of %s should be a multiple of %s', RangeError);
+E('ERR_NAPI_INVALID_TYPEDARRAY_LENGTH',
+ 'Invalid typed array length', RangeError);
+E('ERR_NO_CRYPTO',
+ 'Node.js is not compiled with OpenSSL crypto support', Error);
+E('ERR_NO_ICU',
+ '%s is not supported on Node.js compiled without ICU', TypeError);
+E('ERR_NO_LONGER_SUPPORTED', '%s is no longer supported', Error);
+E('ERR_OUT_OF_RANGE', 'The "%s" argument is out of range', RangeError);
+E('ERR_REQUIRE_ESM', 'Must use import to load ES Module: %s', Error);
E('ERR_SERVER_ALREADY_LISTEN',
- 'Listen method has been called more than once without closing.');
-E('ERR_SOCKET_ALREADY_BOUND', 'Socket is already bound');
-E('ERR_SOCKET_BAD_BUFFER_SIZE', 'Buffer size must be a positive integer');
-E('ERR_SOCKET_BAD_PORT', 'Port should be > 0 and < 65536. Received %s.');
+ 'Listen method has been called more than once without closing.', Error);
+E('ERR_SOCKET_ALREADY_BOUND', 'Socket is already bound', Error);
+E('ERR_SOCKET_BAD_BUFFER_SIZE',
+ 'Buffer size must be a positive integer', TypeError);
+E('ERR_SOCKET_BAD_PORT',
+ 'Port should be > 0 and < 65536. Received %s.', RangeError);
E('ERR_SOCKET_BAD_TYPE',
- 'Bad socket type specified. Valid types are: udp4, udp6');
-E('ERR_SOCKET_BUFFER_SIZE', 'Could not get or set buffer size: %s');
-E('ERR_SOCKET_CANNOT_SEND', 'Unable to send data');
-E('ERR_SOCKET_CLOSED', 'Socket is closed');
-E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running');
-E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed');
-E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed');
-E('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable');
-E('ERR_STREAM_NULL_VALUES', 'May not write null values to stream');
-E('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF');
-E('ERR_STREAM_READ_NOT_IMPLEMENTED', '_read() is not implemented');
-E('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event');
-E('ERR_STREAM_WRAP', 'Stream has StringDecoder set or is in objectMode');
-E('ERR_STREAM_WRITE_AFTER_END', 'write after end');
+ 'Bad socket type specified. Valid types are: udp4, udp6', TypeError);
+E('ERR_SOCKET_BUFFER_SIZE', 'Could not get or set buffer size: %s', Error);
+E('ERR_SOCKET_CANNOT_SEND', 'Unable to send data', Error);
+E('ERR_SOCKET_CLOSED', 'Socket is closed', Error);
+E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running', Error);
+E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed', Error);
+E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed', Error);
+E('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable', Error);
+E('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError);
+E('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF', Error);
+E('ERR_STREAM_READ_NOT_IMPLEMENTED', '_read() is not implemented', Error);
+E('ERR_STREAM_UNSHIFT_AFTER_END_EVENT',
+ 'stream.unshift() after end event', Error);
+E('ERR_STREAM_WRAP', 'Stream has StringDecoder set or is in objectMode', Error);
+E('ERR_STREAM_WRITE_AFTER_END', 'write after end', Error);
E('ERR_TLS_CERT_ALTNAME_INVALID',
- 'Hostname/IP does not match certificate\'s altnames: %s');
-E('ERR_TLS_DH_PARAM_SIZE', 'DH parameter size %s is less than 2048');
-E('ERR_TLS_HANDSHAKE_TIMEOUT', 'TLS handshake timeout');
-E('ERR_TLS_RENEGOTIATION_FAILED', 'Failed to renegotiate');
+ 'Hostname/IP does not match certificate\'s altnames: %s', Error);
+E('ERR_TLS_DH_PARAM_SIZE', 'DH parameter size %s is less than 2048', Error);
+E('ERR_TLS_HANDSHAKE_TIMEOUT', 'TLS handshake timeout', Error);
E('ERR_TLS_REQUIRED_SERVER_NAME',
- '"servername" is required parameter for Server.addContext');
-E('ERR_TLS_SESSION_ATTACK', 'TLS session renegotiation attack detected');
+ '"servername" is required parameter for Server.addContext', Error);
+E('ERR_TLS_SESSION_ATTACK', 'TLS session renegotiation attack detected', Error);
E('ERR_TRANSFORM_ALREADY_TRANSFORMING',
- 'Calling transform done when still transforming');
+ 'Calling transform done when still transforming', Error);
+
+// This should probably be a `RangeError`.
E('ERR_TRANSFORM_WITH_LENGTH_0',
- 'Calling transform done when writableState.length != 0');
+ 'Calling transform done when writableState.length != 0', Error);
E('ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET',
'`process.setupUncaughtExceptionCapture()` was called while a capture ' +
- 'callback was already active');
-E('ERR_UNESCAPED_CHARACTERS', '%s contains unescaped characters');
+ 'callback was already active',
+ Error);
+E('ERR_UNESCAPED_CHARACTERS', '%s contains unescaped characters', TypeError);
E('ERR_UNHANDLED_ERROR',
(err) => {
const msg = 'Unhandled error.';
if (err === undefined) return msg;
return `${msg} (${err})`;
- });
-E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s');
-E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension: %s');
-E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s');
-E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s');
-E('ERR_UNKNOWN_STDIN_TYPE', 'Unknown stdin file type');
-E('ERR_UNKNOWN_STREAM_TYPE', 'Unknown stream file type');
-E('ERR_V8BREAKITERATOR', 'Full ICU data not installed. ' +
- 'See https://github.com/nodejs/node/wiki/Intl');
+ }, Error);
+E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError);
+
+// This should probably be a `TypeError`.
+E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension: %s', Error);
+E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s', RangeError);
+E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError);
+E('ERR_UNKNOWN_STDIN_TYPE', 'Unknown stdin file type', Error);
+
+// This should probably be a `TypeError`.
+E('ERR_UNKNOWN_STREAM_TYPE', 'Unknown stream file type', Error);
+E('ERR_V8BREAKITERATOR',
+ 'Full ICU data not installed. See https://github.com/nodejs/node/wiki/Intl',
+ Error);
+
+// This should probably be a `TypeError`.
E('ERR_VALID_PERFORMANCE_ENTRY_TYPE',
- 'At least one valid performance entry type is required');
+ 'At least one valid performance entry type is required', Error);
E('ERR_VALUE_OUT_OF_RANGE', (start, end, value) => {
return `The value of "${start}" must be ${end}. Received "${value}"`;
-});
-E('ERR_VM_MODULE_ALREADY_LINKED', 'Module has already been linked');
+}, RangeError);
+E('ERR_VM_MODULE_ALREADY_LINKED', 'Module has already been linked', Error);
E('ERR_VM_MODULE_DIFFERENT_CONTEXT',
- 'Linked modules must use the same context');
+ 'Linked modules must use the same context', Error);
E('ERR_VM_MODULE_LINKING_ERRORED',
- 'Linking has already failed for the provided module');
+ 'Linking has already failed for the provided module', Error);
E('ERR_VM_MODULE_NOT_LINKED',
- 'Module must be linked before it can be instantiated');
-E('ERR_VM_MODULE_NOT_MODULE', 'Provided module is not an instance of Module');
-E('ERR_VM_MODULE_STATUS', 'Module status %s');
-E('ERR_ZLIB_BINDING_CLOSED', 'zlib binding closed');
-E('ERR_ZLIB_INITIALIZATION_FAILED', 'Initialization failed');
+ 'Module must be linked before it can be instantiated', Error);
+E('ERR_VM_MODULE_NOT_MODULE',
+ 'Provided module is not an instance of Module', Error);
+E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
+E('ERR_ZLIB_BINDING_CLOSED', 'zlib binding closed', Error);
+E('ERR_ZLIB_INITIALIZATION_FAILED', 'Initialization failed', Error);
function invalidArgType(name, expected, actual) {
internalAssert(name, 'name is required');
diff --git a/lib/internal/fs.js b/lib/internal/fs.js
index 01c5ff4bfc2e4d..e58b3f5110a804 100644
--- a/lib/internal/fs.js
+++ b/lib/internal/fs.js
@@ -47,10 +47,14 @@ function stringToFlags(flags) {
case 'a' : return O_APPEND | O_CREAT | O_WRONLY;
case 'ax' : // Fall through.
case 'xa' : return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
+ case 'as' : // Fall through.
+ case 'sa' : return O_APPEND | O_CREAT | O_WRONLY | O_SYNC;
case 'a+' : return O_APPEND | O_CREAT | O_RDWR;
case 'ax+': // Fall through.
case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
+ case 'as+': // Fall through.
+ case 'sa+': return O_APPEND | O_CREAT | O_RDWR | O_SYNC;
}
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'flags', flags);
diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js
index 93b76588db03b2..86e33d9cda0da8 100644
--- a/lib/internal/http2/core.js
+++ b/lib/internal/http2/core.js
@@ -948,7 +948,7 @@ class Http2Session extends EventEmitter {
if (typeof id !== 'number')
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'id', 'number');
if (id <= 0 || id > kMaxStreams)
- throw new errors.RangeError('ERR_OUT_OF_RANGE');
+ throw new errors.RangeError('ERR_OUT_OF_RANGE', 'id');
this[kHandle].setNextStreamID(id);
}
@@ -2041,19 +2041,12 @@ function afterOpen(session, options, headers, streamOptions, err, fd) {
headers, streamOptions));
}
-function streamOnError(err) {
- // we swallow the error for parity with HTTP1
- // all the errors that ends here are not critical for the project
-}
-
-
class ServerHttp2Stream extends Http2Stream {
constructor(session, handle, id, options, headers) {
super(session, options);
this[kInit](id, handle);
this[kProtocol] = headers[HTTP2_HEADER_SCHEME];
this[kAuthority] = headers[HTTP2_HEADER_AUTHORITY];
- this.on('error', streamOnError);
}
// true if the remote peer accepts push streams
diff --git a/lib/internal/loader/DefaultResolve.js b/lib/internal/loader/DefaultResolve.js
index d815be87dd8954..bd99f31e54c599 100644
--- a/lib/internal/loader/DefaultResolve.js
+++ b/lib/internal/loader/DefaultResolve.js
@@ -40,7 +40,7 @@ function search(target, base) {
}
const extensionFormatMap = {
- __proto__: null,
+ '__proto__': null,
'.mjs': 'esm',
'.json': 'json',
'.node': 'addon',
diff --git a/lib/internal/process.js b/lib/internal/process.js
index 70186f0e66deaa..c94b0a9d5fc442 100644
--- a/lib/internal/process.js
+++ b/lib/internal/process.js
@@ -118,16 +118,9 @@ function setupMemoryUsage() {
function setupConfig(_source) {
// NativeModule._source
// used for `process.config`, but not a real module
- var config = _source.config;
+ const config = _source.config;
delete _source.config;
- // strip the gyp comment line at the beginning
- config = config.split('\n')
- .slice(1)
- .join('\n')
- .replace(/"/g, '\\"')
- .replace(/'/g, '"');
-
process.config = JSON.parse(config, function(key, value) {
if (value === 'true') return true;
if (value === 'false') return false;
diff --git a/lib/internal/streams/duplex_base.js b/lib/internal/streams/duplex_base.js
new file mode 100644
index 00000000000000..df3c5c37a80ea7
--- /dev/null
+++ b/lib/internal/streams/duplex_base.js
@@ -0,0 +1,30 @@
+'use strict';
+
+const util = require('util');
+const Readable = require('_stream_readable');
+const Writable = require('_stream_writable');
+
+function DuplexBase(options) {
+ Readable.call(this, options);
+ Writable.call(this, options);
+
+ if (options && options.readable === false)
+ this.readable = false;
+
+ if (options && options.writable === false)
+ this.writable = false;
+}
+
+util.inherits(DuplexBase, Readable);
+
+{
+ // Avoid scope creep, the keys array can then be collected.
+ const keys = Object.keys(Writable.prototype);
+ for (var v = 0; v < keys.length; v++) {
+ const method = keys[v];
+ if (!DuplexBase.prototype[method])
+ DuplexBase.prototype[method] = Writable.prototype[method];
+ }
+}
+
+module.exports = DuplexBase;
diff --git a/lib/internal/v8_prof_processor.js b/lib/internal/v8_prof_processor.js
index 7592253060294c..4799a88f69ca54 100644
--- a/lib/internal/v8_prof_processor.js
+++ b/lib/internal/v8_prof_processor.js
@@ -21,11 +21,6 @@ scriptFiles.forEach(function(s) {
script += process.binding('natives')[s] + '\n';
});
-// eslint-disable-next-line no-unused-vars
-function printErr(err) {
- console.error(err);
-}
-
const tickArguments = [];
if (process.platform === 'darwin') {
tickArguments.push('--mac');
@@ -36,6 +31,7 @@ tickArguments.push.apply(tickArguments, process.argv.slice(1));
script = `(function(module, require) {
arguments = ${JSON.stringify(tickArguments)};
function write (s) { process.stdout.write(s) }
+ function printErr(err) { console.error(err); }
${script}
})`;
vm.runInThisContext(script)(module, require);
diff --git a/lib/net.js b/lib/net.js
index 90e0db558e3a9b..17a128a4f0c8db 100644
--- a/lib/net.js
+++ b/lib/net.js
@@ -50,6 +50,7 @@ const { async_id_symbol } = process.binding('async_wrap');
const { newUid, defaultTriggerAsyncIdScope } = require('internal/async_hooks');
const { nextTick } = require('internal/process/next_tick');
const errors = require('internal/errors');
+const DuplexBase = require('internal/streams/duplex_base');
const dns = require('dns');
const kLastWriteQueueSize = Symbol('lastWriteQueueSize');
@@ -211,7 +212,11 @@ function Socket(options) {
else if (options === undefined)
options = {};
- stream.Duplex.call(this, options);
+ // `DuplexBase` is just a slimmed down constructor for `Duplex` which allow
+ // us to not inherit the "no-half-open enforcer" as there is already one in
+ // place. Instances of `Socket` are still instances of `Duplex`, that is,
+ // `socket instanceof Duplex === true`.
+ DuplexBase.call(this, options);
if (options.handle) {
this._handle = options.handle; // private
@@ -236,8 +241,6 @@ function Socket(options) {
this._writev = null;
this._write = makeSyncWrite(fd);
}
- this.readable = options.readable !== false;
- this.writable = options.writable !== false;
} else {
// these will be set once there is a connection
this.readable = this.writable = false;
@@ -256,7 +259,7 @@ function Socket(options) {
this._writableState.decodeStrings = false;
// default to *not* allowing half open sockets
- this.allowHalfOpen = options && options.allowHalfOpen || false;
+ this.allowHalfOpen = options.allowHalfOpen || false;
// if we have a handle, then start the flow of data into the
// buffer. if not, then this will happen when we connect
diff --git a/lib/path.js b/lib/path.js
index 098416adfe1a3a..3530388e945d0a 100644
--- a/lib/path.js
+++ b/lib/path.js
@@ -50,7 +50,7 @@ function isWindowsDeviceRoot(code) {
}
// Resolves . and .. elements in a path with directory names
-function normalizeStringWin32(path, allowAboveRoot) {
+function normalizeString(path, allowAboveRoot, separator) {
var res = '';
var lastSegmentLength = 0;
var lastSlash = -1;
@@ -72,14 +72,14 @@ function normalizeStringWin32(path, allowAboveRoot) {
res.charCodeAt(res.length - 1) !== CHAR_DOT ||
res.charCodeAt(res.length - 2) !== CHAR_DOT) {
if (res.length > 2) {
- const lastSlashIndex = res.lastIndexOf('\\');
+ const lastSlashIndex = res.lastIndexOf(separator);
if (lastSlashIndex !== res.length - 1) {
if (lastSlashIndex === -1) {
res = '';
lastSegmentLength = 0;
} else {
res = res.slice(0, lastSlashIndex);
- lastSegmentLength = res.length - 1 - res.lastIndexOf('\\');
+ lastSegmentLength = res.length - 1 - res.lastIndexOf(separator);
}
lastSlash = i;
dots = 0;
@@ -95,82 +95,14 @@ function normalizeStringWin32(path, allowAboveRoot) {
}
if (allowAboveRoot) {
if (res.length > 0)
- res += '\\..';
+ res += `${separator}..`;
else
res = '..';
lastSegmentLength = 2;
}
} else {
if (res.length > 0)
- res += '\\' + path.slice(lastSlash + 1, i);
- else
- res = path.slice(lastSlash + 1, i);
- lastSegmentLength = i - lastSlash - 1;
- }
- lastSlash = i;
- dots = 0;
- } else if (code === CHAR_DOT && dots !== -1) {
- ++dots;
- } else {
- dots = -1;
- }
- }
- return res;
-}
-
-// Resolves . and .. elements in a path with directory names
-function normalizeStringPosix(path, allowAboveRoot) {
- var res = '';
- var lastSegmentLength = 0;
- var lastSlash = -1;
- var dots = 0;
- var code;
- for (var i = 0; i <= path.length; ++i) {
- if (i < path.length)
- code = path.charCodeAt(i);
- else if (code === CHAR_FORWARD_SLASH)
- break;
- else
- code = CHAR_FORWARD_SLASH;
- if (code === CHAR_FORWARD_SLASH) {
- if (lastSlash === i - 1 || dots === 1) {
- // NOOP
- } else if (lastSlash !== i - 1 && dots === 2) {
- if (res.length < 2 || lastSegmentLength !== 2 ||
- res.charCodeAt(res.length - 1) !== CHAR_DOT ||
- res.charCodeAt(res.length - 2) !== CHAR_DOT) {
- if (res.length > 2) {
- const lastSlashIndex = res.lastIndexOf('/');
- if (lastSlashIndex !== res.length - 1) {
- if (lastSlashIndex === -1) {
- res = '';
- lastSegmentLength = 0;
- } else {
- res = res.slice(0, lastSlashIndex);
- lastSegmentLength = res.length - 1 - res.lastIndexOf('/');
- }
- lastSlash = i;
- dots = 0;
- continue;
- }
- } else if (res.length === 2 || res.length === 1) {
- res = '';
- lastSegmentLength = 0;
- lastSlash = i;
- dots = 0;
- continue;
- }
- }
- if (allowAboveRoot) {
- if (res.length > 0)
- res += '/..';
- else
- res = '..';
- lastSegmentLength = 2;
- }
- } else {
- if (res.length > 0)
- res += '/' + path.slice(lastSlash + 1, i);
+ res += separator + path.slice(lastSlash + 1, i);
else
res = path.slice(lastSlash + 1, i);
lastSegmentLength = i - lastSlash - 1;
@@ -340,7 +272,7 @@ const win32 = {
// fails)
// Normalize the tail path
- resolvedTail = normalizeStringWin32(resolvedTail, !resolvedAbsolute);
+ resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\');
return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) ||
'.';
@@ -432,7 +364,7 @@ const win32 = {
var tail;
if (rootEnd < len)
- tail = normalizeStringWin32(path.slice(rootEnd), !isAbsolute);
+ tail = normalizeString(path.slice(rootEnd), !isAbsolute, '\\');
else
tail = '';
if (tail.length === 0 && !isAbsolute)
@@ -1164,7 +1096,7 @@ const posix = {
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
- resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/');
if (resolvedAbsolute) {
if (resolvedPath.length > 0)
@@ -1190,7 +1122,7 @@ const posix = {
path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;
// Normalize the path
- path = normalizeStringPosix(path, !isAbsolute);
+ path = normalizeString(path, !isAbsolute, '/');
if (path.length === 0 && !isAbsolute)
path = '.';
diff --git a/lib/repl.js b/lib/repl.js
index 2078c5dcedaf20..5779e849f06017 100644
--- a/lib/repl.js
+++ b/lib/repl.js
@@ -79,7 +79,7 @@ const kBufferedCommandSymbol = Symbol('bufferedCommand');
const kContextId = Symbol('contextId');
try {
- // hack for require.resolve("./relative") to work properly.
+ // Hack for require.resolve("./relative") to work properly.
module.filename = path.resolve('repl');
} catch (e) {
// path.resolve('repl') fails when the current working directory has been
@@ -89,7 +89,7 @@ try {
module.filename = path.resolve(dirname, 'repl');
}
-// hack for repl require to work properly with node_modules folders
+// Hack for repl require to work properly with node_modules folders
module.paths = Module._nodeModulePaths(module.filename);
// If obj.hasOwnProperty has been overridden, then calling
@@ -99,14 +99,12 @@ function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
-
// Can overridden with custom print functions, such as `probe` or `eyes.js`.
// This is the default "writer" value if none is passed in the REPL options.
exports.writer = util.inspect;
exports._builtinLibs = internalModule.builtinLibs;
-
function REPLServer(prompt,
stream,
eval_,
@@ -149,7 +147,6 @@ function REPLServer(prompt,
var self = this;
self._domain = dom || domain.create();
-
self.useGlobal = !!useGlobal;
self.ignoreUndefined = !!ignoreUndefined;
self.replMode = replMode || exports.REPL_MODE_SLOPPY;
@@ -162,7 +159,7 @@ function REPLServer(prompt,
// Context id for use with the inspector protocol.
self[kContextId] = undefined;
- // just for backwards compat, see github.com/joyent/node/pull/7127
+ // Just for backwards compat, see github.com/joyent/node/pull/7127
self.rli = this;
const savedRegExMatches = ['', '', '', '', '', '', '', '', '', ''];
@@ -187,8 +184,7 @@ function REPLServer(prompt,
wrappedCmd = true;
}
- // first, create the Script object to check the syntax
-
+ // First, create the Script object to check the syntax
if (code === '\n')
return cb(null);
@@ -207,13 +203,13 @@ function REPLServer(prompt,
} catch (e) {
debug('parse error %j', code, e);
if (wrappedCmd) {
+ // Unwrap and try again
wrappedCmd = false;
- // unwrap and try again
code = input;
wrappedErr = e;
continue;
}
- // preserve original error for wrapped command
+ // Preserve original error for wrapped command
const error = wrappedErr || e;
if (isRecoverableError(error, code))
err = new Recoverable(error);
@@ -321,18 +317,13 @@ function REPLServer(prompt,
if (!input && !output) {
// legacy API, passing a 'stream'/'socket' option
if (!stream) {
- // use stdin and stdout as the default streams if none were given
+ // Use stdin and stdout as the default streams if none were given
stream = process;
}
- if (stream.stdin && stream.stdout) {
- // We're given custom object with 2 streams, or the `process` object
- input = stream.stdin;
- output = stream.stdout;
- } else {
- // We're given a duplex readable/writable Stream, like a `net.Socket`
- input = stream;
- output = stream;
- }
+ // We're given a duplex readable/writable Stream, like a `net.Socket`
+ // or a custom object with 2 streams, or the `process` object
+ input = stream.stdin || stream;
+ output = stream.stdout || stream;
}
self.inputStream = input;
@@ -371,7 +362,7 @@ function REPLServer(prompt,
this.commands = Object.create(null);
defineDefaultCommands(this);
- // figure out which "writer" function to use
+ // Figure out which "writer" function to use
self.writer = options.writer || exports.writer;
if (options.useColors === undefined) {
@@ -387,14 +378,14 @@ function REPLServer(prompt,
}
function filterInternalStackFrames(error, structuredStack) {
- // search from the bottom of the call stack to
+ // Search from the bottom of the call stack to
// find the first frame with a null function name
if (typeof structuredStack !== 'object')
return structuredStack;
const idx = structuredStack.reverse().findIndex(
(frame) => frame.getFunctionName() === null);
- // if found, get rid of it and everything below it
+ // If found, get rid of it and everything below it
structuredStack = structuredStack.splice(idx + 1);
return structuredStack;
}
@@ -571,7 +562,7 @@ function REPLServer(prompt,
return;
}
- // editor mode
+ // Editor mode
if (key.ctrl && !key.shift) {
switch (key.name) {
case 'd': // End editor mode
@@ -591,7 +582,7 @@ function REPLServer(prompt,
case 'down': // Override next history item
break;
case 'tab':
- // prevent double tab behavior
+ // Prevent double tab behavior
self._previousKey = null;
ttyWrite(d, key);
break;
@@ -667,7 +658,7 @@ REPLServer.prototype.createContext = function() {
Object.defineProperty(context, 'console', {
configurable: true,
enumerable: true,
- get: () => _console
+ value: _console
});
var names = Object.getOwnPropertyNames(global);
@@ -861,10 +852,8 @@ function complete(line, callback) {
}
var completions;
-
- // list of completion lists, one for each inheritance "level"
+ // List of completion lists, one for each inheritance "level"
var completionGroups = [];
-
var completeOn, i, group, c;
// REPL commands (e.g. ".break").
@@ -1041,19 +1030,16 @@ function complete(line, callback) {
break;
}
}
- } catch (e) {
- //console.log("completion error walking prototype chain:" + e);
- }
+ } catch (e) {}
}
if (memberGroups.length) {
for (i = 0; i < memberGroups.length; i++) {
- completionGroups.push(memberGroups[i].map(function(member) {
- return expr + '.' + member;
- }));
+ completionGroups.push(
+ memberGroups[i].map((member) => `${expr}.${member}`));
}
if (filter) {
- filter = expr + '.' + filter;
+ filter = `${expr}.${filter}`;
}
}
@@ -1074,9 +1060,8 @@ function complete(line, callback) {
if (completionGroups.length && filter) {
var newCompletionGroups = [];
for (i = 0; i < completionGroups.length; i++) {
- group = completionGroups[i].filter(function(elem) {
- return elem.indexOf(filter) === 0;
- });
+ group = completionGroups[i]
+ .filter((elem) => elem.indexOf(filter) === 0);
if (group.length) {
newCompletionGroups.push(group);
}
@@ -1085,7 +1070,7 @@ function complete(line, callback) {
}
if (completionGroups.length) {
- var uniq = {}; // unique completions across all groups
+ var uniq = {}; // Unique completions across all groups
completions = [];
// Completion group 0 is the "closest"
// (least far up the inheritance chain)
@@ -1100,7 +1085,7 @@ function complete(line, callback) {
uniq[c] = true;
}
}
- completions.push(''); // separator btwn groups
+ completions.push(''); // Separator btwn groups
}
while (completions.length && completions[completions.length - 1] === '') {
completions.pop();
@@ -1167,7 +1152,7 @@ function _memory(cmd) {
self.lines = self.lines || [];
self.lines.level = self.lines.level || [];
- // save the line so I can do magic later
+ // Save the line so I can do magic later
if (cmd) {
// TODO should I tab the level?
const len = self.lines.level.length ? self.lines.level.length - 1 : 0;
@@ -1181,7 +1166,7 @@ function _memory(cmd) {
// Because I can not tell the difference between a } that
// closes an object literal and a } that closes a function
if (cmd) {
- // going down is { and ( e.g. function() {
+ // Going down is { and ( e.g. function() {
// going up is } and )
var dw = cmd.match(/{|\(/g);
var up = cmd.match(/}|\)/g);
@@ -1192,8 +1177,8 @@ function _memory(cmd) {
if (depth) {
(function workIt() {
if (depth > 0) {
- // going... down.
- // push the line#, depth count, and if the line is a function.
+ // Going... down.
+ // Push the line#, depth count, and if the line is a function.
// Since JS only has functional scope I only need to remove
// "function() {" lines, clearly this will not work for
// "function()
@@ -1205,16 +1190,16 @@ function _memory(cmd) {
isFunction: /\bfunction\b/.test(cmd)
});
} else if (depth < 0) {
- // going... up.
+ // Going... up.
var curr = self.lines.level.pop();
if (curr) {
var tmp = curr.depth + depth;
if (tmp < 0) {
- //more to go, recurse
+ // More to go, recurse
depth += curr.depth;
workIt();
} else if (tmp > 0) {
- //remove and push back
+ // Remove and push back
curr.depth += depth;
self.lines.level.push(curr);
}
@@ -1375,14 +1360,15 @@ function isRecoverableError(e, code) {
if (e && e.name === 'SyntaxError') {
var message = e.message;
if (message === 'Unterminated template literal' ||
- message === 'Missing } in template expression') {
+ message === 'Unexpected end of input') {
return true;
}
- if (message.startsWith('Unexpected end of input') ||
- message.startsWith('missing ) after argument list') ||
- message.startsWith('Unexpected token'))
- return true;
+ if (message === 'missing ) after argument list') {
+ const frames = e.stack.split(/\r?\n/);
+ const pos = frames.findIndex((f) => f.match(/^\s*\^+$/));
+ return pos > 0 && frames[pos - 1].length === frames[pos].length;
+ }
if (message === 'Invalid or unexpected token')
return isCodeRecoverable(code);
@@ -1405,55 +1391,33 @@ function isCodeRecoverable(code) {
if (previous === '\\' && (stringLiteral || isRegExpLiteral)) {
current = null;
- continue;
- }
-
- if (stringLiteral) {
+ } else if (stringLiteral) {
if (stringLiteral === current) {
stringLiteral = null;
}
- continue;
- } else {
- if (isRegExpLiteral && current === '/') {
- isRegExpLiteral = false;
- continue;
- }
-
- if (isBlockComment && previous === '*' && current === '/') {
- isBlockComment = false;
- continue;
- }
-
- if (isSingleComment && current === '\n') {
- isSingleComment = false;
- continue;
- }
-
- if (isBlockComment || isRegExpLiteral || isSingleComment) continue;
-
+ } else if (isRegExpLiteral && current === '/') {
+ isRegExpLiteral = false;
+ } else if (isBlockComment && previous === '*' && current === '/') {
+ isBlockComment = false;
+ } else if (isSingleComment && current === '\n') {
+ isSingleComment = false;
+ } else if (!isBlockComment && !isRegExpLiteral && !isSingleComment) {
if (current === '/' && previous === '/') {
isSingleComment = true;
- continue;
- }
-
- if (previous === '/') {
+ } else if (previous === '/') {
if (current === '*') {
isBlockComment = true;
- } else if (
// Distinguish between a division operator and the start of a regex
// by examining the non-whitespace character that precedes the /
- [null, '(', '[', '{', '}', ';'].includes(prevTokenChar)
- ) {
+ } else if ([null, '(', '[', '{', '}', ';'].includes(prevTokenChar)) {
isRegExpLiteral = true;
}
- continue;
+ } else {
+ if (current.trim()) prevTokenChar = current;
+ if (current === '\'' || current === '"') {
+ stringLiteral = current;
+ }
}
-
- if (current.trim()) prevTokenChar = current;
- }
-
- if (current === '\'' || current === '"') {
- stringLiteral = current;
}
}
diff --git a/lib/timers.js b/lib/timers.js
index 46cd770fc643bd..c82d6cfdbb11e9 100644
--- a/lib/timers.js
+++ b/lib/timers.js
@@ -314,24 +314,24 @@ function tryOnTimeout(timer, list) {
}
}
- if (!threw) return;
-
- // Postpone all later list events to next tick. We need to do this
- // so that the events are called in the order they were created.
- const lists = list._unrefed === true ? unrefedLists : refedLists;
- for (var key in lists) {
- if (key > list.msecs) {
- lists[key].nextTick = true;
+ if (threw) {
+ // Postpone all later list events to next tick. We need to do this
+ // so that the events are called in the order they were created.
+ const lists = list._unrefed === true ? unrefedLists : refedLists;
+ for (var key in lists) {
+ if (key > list.msecs) {
+ lists[key].nextTick = true;
+ }
}
+ // We need to continue processing after domain error handling
+ // is complete, but not by using whatever domain was left over
+ // when the timeout threw its exception.
+ const domain = process.domain;
+ process.domain = null;
+ // If we threw, we need to process the rest of the list in nextTick.
+ process.nextTick(listOnTimeoutNT, list);
+ process.domain = domain;
}
- // We need to continue processing after domain error handling
- // is complete, but not by using whatever domain was left over
- // when the timeout threw its exception.
- const domain = process.domain;
- process.domain = null;
- // If we threw, we need to process the rest of the list in nextTick.
- process.nextTick(listOnTimeoutNT, list);
- process.domain = domain;
}
}
diff --git a/lib/tty.js b/lib/tty.js
index 29440d6d96e3d5..12d0836cde5db5 100644
--- a/lib/tty.js
+++ b/lib/tty.js
@@ -26,12 +26,19 @@ const net = require('net');
const { TTY, isTTY } = process.binding('tty_wrap');
const errors = require('internal/errors');
const readline = require('readline');
+const { release } = require('os');
+
+const OSRelease = release().split('.');
+
+const COLORS_2 = 1;
+const COLORS_16 = 4;
+const COLORS_256 = 8;
+const COLORS_16m = 24;
function isatty(fd) {
return Number.isInteger(fd) && fd >= 0 && isTTY(fd);
}
-
function ReadStream(fd, options) {
if (!(this instanceof ReadStream))
return new ReadStream(fd, options);
@@ -58,7 +65,6 @@ ReadStream.prototype.setRawMode = function(flag) {
this.isRaw = flag;
};
-
function WriteStream(fd) {
if (!(this instanceof WriteStream))
return new WriteStream(fd);
@@ -78,8 +84,8 @@ function WriteStream(fd) {
// Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671
this._handle.setBlocking(true);
- var winSize = new Array(2);
- var err = this._handle.getWindowSize(winSize);
+ const winSize = new Array(2);
+ const err = this._handle.getWindowSize(winSize);
if (!err) {
this.columns = winSize[0];
this.rows = winSize[1];
@@ -87,21 +93,83 @@ function WriteStream(fd) {
}
inherits(WriteStream, net.Socket);
-
WriteStream.prototype.isTTY = true;
+WriteStream.prototype.getColorDepth = function(env = process.env) {
+ if (env.NODE_DISABLE_COLORS || env.TERM === 'dumb' && !env.COLORTERM) {
+ return COLORS_2;
+ }
+
+ if (process.platform === 'win32') {
+ // Windows 10 build 10586 is the first Windows release that supports 256
+ // colors. Windows 10 build 14931 is the first release that supports
+ // 16m/TrueColor.
+ if (+OSRelease[0] >= 10) {
+ const build = +OSRelease[2];
+ if (build >= 14931)
+ return COLORS_16m;
+ if (build >= 10586)
+ return COLORS_256;
+ }
+
+ return COLORS_16;
+ }
+
+ if (env.TMUX) {
+ return COLORS_256;
+ }
+
+ if (env.CI) {
+ if ('TRAVIS' in env || 'CIRCLECI' in env || 'APPVEYOR' in env ||
+ 'GITLAB_CI' in env || env.CI_NAME === 'codeship') {
+ return COLORS_256;
+ }
+ return COLORS_2;
+ }
+
+ if ('TEAMCITY_VERSION' in env) {
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ?
+ COLORS_16 : COLORS_2;
+ }
+
+ switch (env.TERM_PROGRAM) {
+ case 'iTerm.app':
+ if (!env.TERM_PROGRAM_VERSION ||
+ /^[0-2]\./.test(env.TERM_PROGRAM_VERSION)) {
+ return COLORS_256;
+ }
+ return COLORS_16m;
+ case 'HyperTerm':
+ case 'Hyper':
+ case 'MacTerm':
+ return COLORS_16m;
+ case 'Apple_Terminal':
+ return COLORS_256;
+ }
+
+ if (env.TERM) {
+ if (/^xterm-256/.test(env.TERM))
+ return COLORS_256;
+ if (/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(env.TERM))
+ return COLORS_16;
+ }
+
+ if (env.COLORTERM)
+ return COLORS_16;
+
+ return COLORS_2;
+};
WriteStream.prototype._refreshSize = function() {
- var oldCols = this.columns;
- var oldRows = this.rows;
- var winSize = new Array(2);
- var err = this._handle.getWindowSize(winSize);
+ const oldCols = this.columns;
+ const oldRows = this.rows;
+ const winSize = new Array(2);
+ const err = this._handle.getWindowSize(winSize);
if (err) {
this.emit('error', errors.errnoException(err, 'getWindowSize'));
return;
}
- var newCols = winSize[0];
- var newRows = winSize[1];
+ const [newCols, newRows] = winSize;
if (oldCols !== newCols || oldRows !== newRows) {
this.columns = newCols;
this.rows = newRows;
@@ -109,8 +177,7 @@ WriteStream.prototype._refreshSize = function() {
}
};
-
-// backwards-compat
+// Backwards-compat
WriteStream.prototype.cursorTo = function(x, y) {
readline.cursorTo(this, x, y);
};
@@ -127,5 +194,4 @@ WriteStream.prototype.getWindowSize = function() {
return [this.columns, this.rows];
};
-
module.exports = { isatty, ReadStream, WriteStream };
diff --git a/lib/url.js b/lib/url.js
index ab4b2b4647edd2..df9d917a479aba 100644
--- a/lib/url.js
+++ b/lib/url.js
@@ -92,6 +92,43 @@ const slashedProtocol = {
'file:': true
};
const querystring = require('querystring');
+const {
+ CHAR_SPACE,
+ CHAR_TAB,
+ CHAR_CARRIAGE_RETURN,
+ CHAR_LINE_FEED,
+ CHAR_FORM_FEED,
+ CHAR_NO_BREAK_SPACE,
+ CHAR_ZERO_WIDTH_NOBREAK_SPACE,
+ CHAR_HASH,
+ CHAR_FORWARD_SLASH,
+ CHAR_LEFT_SQUARE_BRACKET,
+ CHAR_RIGHT_SQUARE_BRACKET,
+ CHAR_LEFT_ANGLE_BRACKET,
+ CHAR_RIGHT_ANGLE_BRACKET,
+ CHAR_LEFT_CURLY_BRACKET,
+ CHAR_RIGHT_CURLY_BRACKET,
+ CHAR_QUESTION_MARK,
+ CHAR_LOWERCASE_A,
+ CHAR_LOWERCASE_Z,
+ CHAR_UPPERCASE_A,
+ CHAR_UPPERCASE_Z,
+ CHAR_DOT,
+ CHAR_0,
+ CHAR_9,
+ CHAR_HYPHEN_MINUS,
+ CHAR_PLUS,
+ CHAR_UNDERSCORE,
+ CHAR_DOUBLE_QUOTE,
+ CHAR_SINGLE_QUOTE,
+ CHAR_PERCENT,
+ CHAR_SEMICOLON,
+ CHAR_BACKWARD_SLASH,
+ CHAR_CIRCUMFLEX_ACCENT,
+ CHAR_GRAVE_ACCENT,
+ CHAR_VERTICAL_LINE,
+ CHAR_AT,
+} = require('internal/constants');
function urlParse(url, parseQueryString, slashesDenoteHost) {
if (url instanceof Url) return url;
@@ -119,13 +156,13 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
const code = url.charCodeAt(i);
// Find first and last non-whitespace characters for trimming
- const isWs = code === 32/* */ ||
- code === 9/*\t*/ ||
- code === 13/*\r*/ ||
- code === 10/*\n*/ ||
- code === 12/*\f*/ ||
- code === 160/*\u00A0*/ ||
- code === 65279/*\uFEFF*/;
+ const isWs = code === CHAR_SPACE ||
+ code === CHAR_TAB ||
+ code === CHAR_CARRIAGE_RETURN ||
+ code === CHAR_LINE_FEED ||
+ code === CHAR_FORM_FEED ||
+ code === CHAR_NO_BREAK_SPACE ||
+ code === CHAR_ZERO_WIDTH_NOBREAK_SPACE;
if (start === -1) {
if (isWs)
continue;
@@ -143,20 +180,20 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
// Only convert backslashes while we haven't seen a split character
if (!split) {
switch (code) {
- case 35: // '#'
+ case CHAR_HASH:
hasHash = true;
// Fall through
- case 63: // '?'
+ case CHAR_QUESTION_MARK:
split = true;
break;
- case 92: // '\\'
+ case CHAR_BACKWARD_SLASH:
if (i - lastPos > 0)
rest += url.slice(lastPos, i);
rest += '/';
lastPos = i + 1;
break;
}
- } else if (!hasHash && code === 35/*#*/) {
+ } else if (!hasHash && code === CHAR_HASH) {
hasHash = true;
}
}
@@ -218,8 +255,8 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
// resolution will treat //foo/bar as host=foo,path=bar because that's
// how the browser resolves relative URLs.
if (slashesDenoteHost || proto || hostPattern.test(rest)) {
- var slashes = rest.charCodeAt(0) === 47/*/*/ &&
- rest.charCodeAt(1) === 47/*/*/;
+ var slashes = rest.charCodeAt(0) === CHAR_FORWARD_SLASH &&
+ rest.charCodeAt(1) === CHAR_FORWARD_SLASH;
if (slashes && !(proto && hostlessProtocol[proto])) {
rest = rest.slice(2);
this.slashes = true;
@@ -249,35 +286,35 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
var nonHost = -1;
for (i = 0; i < rest.length; ++i) {
switch (rest.charCodeAt(i)) {
- case 9: // '\t'
- case 10: // '\n'
- case 13: // '\r'
- case 32: // ' '
- case 34: // '"'
- case 37: // '%'
- case 39: // '\''
- case 59: // ';'
- case 60: // '<'
- case 62: // '>'
- case 92: // '\\'
- case 94: // '^'
- case 96: // '`'
- case 123: // '{'
- case 124: // '|'
- case 125: // '}'
+ case CHAR_TAB:
+ case CHAR_LINE_FEED:
+ case CHAR_CARRIAGE_RETURN:
+ case CHAR_SPACE:
+ case CHAR_DOUBLE_QUOTE:
+ case CHAR_PERCENT:
+ case CHAR_SINGLE_QUOTE:
+ case CHAR_SEMICOLON:
+ case CHAR_LEFT_ANGLE_BRACKET:
+ case CHAR_RIGHT_ANGLE_BRACKET:
+ case CHAR_BACKWARD_SLASH:
+ case CHAR_CIRCUMFLEX_ACCENT:
+ case CHAR_GRAVE_ACCENT:
+ case CHAR_LEFT_CURLY_BRACKET:
+ case CHAR_VERTICAL_LINE:
+ case CHAR_RIGHT_CURLY_BRACKET:
// Characters that are never ever allowed in a hostname from RFC 2396
if (nonHost === -1)
nonHost = i;
break;
- case 35: // '#'
- case 47: // '/'
- case 63: // '?'
+ case CHAR_HASH:
+ case CHAR_FORWARD_SLASH:
+ case CHAR_QUESTION_MARK:
// Find the first instance of any host-ending characters
if (nonHost === -1)
nonHost = i;
hostEnd = i;
break;
- case 64: // '@'
+ case CHAR_AT:
// At this point, either we have an explicit point where the
// auth portion cannot go past, or the last @ char is the decider.
atSign = i;
@@ -312,8 +349,8 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
// if hostname begins with [ and ends with ]
// assume that it's an IPv6 address.
- var ipv6Hostname = hostname.charCodeAt(0) === 91/*[*/ &&
- hostname.charCodeAt(hostname.length - 1) === 93/*]*/;
+ var ipv6Hostname = hostname.charCodeAt(0) === CHAR_LEFT_SQUARE_BRACKET &&
+ hostname.charCodeAt(hostname.length - 1) === CHAR_RIGHT_SQUARE_BRACKET;
// validate a little.
if (!ipv6Hostname) {
@@ -367,11 +404,11 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
var hashIdx = -1;
for (i = 0; i < rest.length; ++i) {
const code = rest.charCodeAt(i);
- if (code === 35/*#*/) {
+ if (code === CHAR_HASH) {
this.hash = rest.slice(i);
hashIdx = i;
break;
- } else if (code === 63/*?*/ && questionIdx === -1) {
+ } else if (code === CHAR_QUESTION_MARK && questionIdx === -1) {
questionIdx = i;
}
}
@@ -422,13 +459,13 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
function validateHostname(self, rest, hostname) {
for (var i = 0; i < hostname.length; ++i) {
const code = hostname.charCodeAt(i);
- const isValid = (code >= 97/*a*/ && code <= 122/*z*/) ||
- code === 46/*.*/ ||
- (code >= 65/*A*/ && code <= 90/*Z*/) ||
- (code >= 48/*0*/ && code <= 57/*9*/) ||
- code === 45/*-*/ ||
- code === 43/*+*/ ||
- code === 95/*_*/ ||
+ const isValid = (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z) ||
+ code === CHAR_DOT ||
+ (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||
+ (code >= CHAR_0 && code <= CHAR_9) ||
+ code === CHAR_HYPHEN_MINUS ||
+ code === CHAR_PLUS ||
+ code === CHAR_UNDERSCORE ||
code > 127;
// Invalid host character
@@ -542,13 +579,13 @@ Url.prototype.format = function format() {
var lastPos = 0;
for (var i = 0; i < pathname.length; ++i) {
switch (pathname.charCodeAt(i)) {
- case 35: // '#'
+ case CHAR_HASH:
if (i - lastPos > 0)
newPathname += pathname.slice(lastPos, i);
newPathname += '%23';
lastPos = i + 1;
break;
- case 63: // '?'
+ case CHAR_QUESTION_MARK:
if (i - lastPos > 0)
newPathname += pathname.slice(lastPos, i);
newPathname += '%3F';
@@ -567,7 +604,7 @@ Url.prototype.format = function format() {
// unless they had them to begin with.
if (this.slashes || slashedProtocol[protocol]) {
if (this.slashes || host) {
- if (pathname && pathname.charCodeAt(0) !== 47/*/*/)
+ if (pathname && pathname.charCodeAt(0) !== CHAR_FORWARD_SLASH)
pathname = '/' + pathname;
host = '//' + host;
} else if (protocol.length >= 4 &&
@@ -581,8 +618,10 @@ Url.prototype.format = function format() {
search = search.replace(/#/g, '%23');
- if (hash && hash.charCodeAt(0) !== 35/*#*/) hash = '#' + hash;
- if (search && search.charCodeAt(0) !== 63/*?*/) search = '?' + search;
+ if (hash && hash.charCodeAt(0) !== CHAR_HASH)
+ hash = '#' + hash;
+ if (search && search.charCodeAt(0) !== CHAR_QUESTION_MARK)
+ search = '?' + search;
return protocol + host + pathname + search + hash;
};
diff --git a/lib/util.js b/lib/util.js
index cd6321cfe5270e..70fd1a05564389 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -68,7 +68,8 @@ const inspectDefaultOptions = Object.seal({
customInspect: true,
showProxy: false,
maxArrayLength: 100,
- breakLength: 60
+ breakLength: 60,
+ compact: true
});
const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
@@ -86,6 +87,10 @@ const strEscapeSequencesReplacer = /[\x00-\x1f\x27\x5c]/g;
const keyStrRegExp = /^[a-zA-Z_][a-zA-Z_0-9]*$/;
const numberRegExp = /^(0|[1-9][0-9]*)$/;
+const readableRegExps = {};
+
+const MIN_LINE_LENGTH = 16;
+
// Escaped special characters. Use empty strings to fill up unused entries.
const meta = [
'\\u0000', '\\u0001', '\\u0002', '\\u0003', '\\u0004',
@@ -257,14 +262,14 @@ function debuglog(set) {
}
/**
- * Echos the value of a value. Tries to print the value out
+ * Echos the value of any input. Tries to print the value out
* in the best way possible given the different types.
*
- * @param {Object} obj The object to print out.
+ * @param {any} value The value to print out.
* @param {Object} opts Optional options object that alters the output.
*/
-/* Legacy: obj, showHidden, depth, colors*/
-function inspect(obj, opts) {
+/* Legacy: value, showHidden, depth, colors*/
+function inspect(value, opts) {
// Default options
const ctx = {
seen: [],
@@ -276,7 +281,8 @@ function inspect(obj, opts) {
showProxy: inspectDefaultOptions.showProxy,
maxArrayLength: inspectDefaultOptions.maxArrayLength,
breakLength: inspectDefaultOptions.breakLength,
- indentationLvl: 0
+ indentationLvl: 0,
+ compact: inspectDefaultOptions.compact
};
// Legacy...
if (arguments.length > 2) {
@@ -298,7 +304,7 @@ function inspect(obj, opts) {
}
if (ctx.colors) ctx.stylize = stylizeWithColor;
if (ctx.maxArrayLength === null) ctx.maxArrayLength = Infinity;
- return formatValue(ctx, obj, ctx.depth);
+ return formatValue(ctx, value, ctx.depth);
}
inspect.custom = customInspectSymbol;
@@ -374,7 +380,7 @@ function ensureDebugIsInitialized() {
function formatValue(ctx, value, recurseTimes, ln) {
// Primitive types cannot have properties
if (typeof value !== 'object' && typeof value !== 'function') {
- return formatPrimitive(ctx.stylize, value);
+ return formatPrimitive(ctx.stylize, value, ctx);
}
if (value === null) {
return ctx.stylize('null', 'null');
@@ -481,10 +487,10 @@ function formatValue(ctx, value, recurseTimes, ln) {
} catch (e) { /* ignore */ }
if (typeof raw === 'string') {
- const formatted = formatPrimitive(stylizeNoColor, raw);
+ const formatted = formatPrimitive(stylizeNoColor, raw, ctx);
if (keyLength === raw.length)
return ctx.stylize(`[String: ${formatted}]`, 'string');
- base = ` [String: ${formatted}]`;
+ base = `[String: ${formatted}]`;
// For boxed Strings, we have to remove the 0-n indexed entries,
// since they just noisy up the output and are redundant
// Make boxed primitive Strings look like such
@@ -505,12 +511,12 @@ function formatValue(ctx, value, recurseTimes, ln) {
const name = `${constructor.name}${value.name ? `: ${value.name}` : ''}`;
if (keyLength === 0)
return ctx.stylize(`[${name}]`, 'special');
- base = ` [${name}]`;
+ base = `[${name}]`;
} else if (isRegExp(value)) {
// Make RegExps say that they are RegExps
if (keyLength === 0 || recurseTimes < 0)
return ctx.stylize(regExpToString.call(value), 'regexp');
- base = ` ${regExpToString.call(value)}`;
+ base = `${regExpToString.call(value)}`;
} else if (isDate(value)) {
if (keyLength === 0) {
if (Number.isNaN(value.getTime()))
@@ -518,12 +524,12 @@ function formatValue(ctx, value, recurseTimes, ln) {
return ctx.stylize(dateToISOString.call(value), 'date');
}
// Make dates with properties first say the date
- base = ` ${dateToISOString.call(value)}`;
+ base = `${dateToISOString.call(value)}`;
} else if (isError(value)) {
// Make error with message first say the error
if (keyLength === 0)
return formatError(value);
- base = ` ${formatError(value)}`;
+ base = `${formatError(value)}`;
} else if (isAnyArrayBuffer(value)) {
// Fast path for ArrayBuffer and SharedArrayBuffer.
// Can't do the same for DataView because it has a non-primitive
@@ -553,13 +559,13 @@ function formatValue(ctx, value, recurseTimes, ln) {
const formatted = formatPrimitive(stylizeNoColor, raw);
if (keyLength === 0)
return ctx.stylize(`[Number: ${formatted}]`, 'number');
- base = ` [Number: ${formatted}]`;
+ base = `[Number: ${formatted}]`;
} else if (typeof raw === 'boolean') {
// Make boxed primitive Booleans look like such
const formatted = formatPrimitive(stylizeNoColor, raw);
if (keyLength === 0)
return ctx.stylize(`[Boolean: ${formatted}]`, 'boolean');
- base = ` [Boolean: ${formatted}]`;
+ base = `[Boolean: ${formatted}]`;
} else if (typeof raw === 'symbol') {
const formatted = formatPrimitive(stylizeNoColor, raw);
return ctx.stylize(`[Symbol: ${formatted}]`, 'symbol');
@@ -603,9 +609,42 @@ function formatNumber(fn, value) {
return fn(`${value}`, 'number');
}
-function formatPrimitive(fn, value) {
- if (typeof value === 'string')
+function formatPrimitive(fn, value, ctx) {
+ if (typeof value === 'string') {
+ if (ctx.compact === false &&
+ value.length > MIN_LINE_LENGTH &&
+ ctx.indentationLvl + value.length > ctx.breakLength) {
+ // eslint-disable-next-line max-len
+ const minLineLength = Math.max(ctx.breakLength - ctx.indentationLvl, MIN_LINE_LENGTH);
+ // eslint-disable-next-line max-len
+ const averageLineLength = Math.ceil(value.length / Math.ceil(value.length / minLineLength));
+ const divisor = Math.max(averageLineLength, MIN_LINE_LENGTH);
+ var res = '';
+ if (readableRegExps[divisor] === undefined) {
+ // Build a new RegExp that naturally breaks text into multiple lines.
+ //
+ // Rules
+ // 1. Greedy match all text up the max line length that ends with a
+ // whitespace or the end of the string.
+ // 2. If none matches, non-greedy match any text up to a whitespace or
+ // the end of the string.
+ //
+ // eslint-disable-next-line max-len, no-unescaped-regexp-dot
+ readableRegExps[divisor] = new RegExp(`(.|\\n){1,${divisor}}(\\s|$)|(\\n|.)+?(\\s|$)`, 'gm');
+ }
+ const indent = ' '.repeat(ctx.indentationLvl);
+ const matches = value.match(readableRegExps[divisor]);
+ if (matches.length > 1) {
+ res += `${fn(strEscape(matches[0]), 'string')} +\n`;
+ for (var i = 1; i < matches.length - 1; i++) {
+ res += `${indent} ${fn(strEscape(matches[i]), 'string')} +\n`;
+ }
+ res += `${indent} ${fn(strEscape(matches[i]), 'string')}`;
+ return res;
+ }
+ }
return fn(strEscape(value), 'string');
+ }
if (typeof value === 'number')
return formatNumber(fn, value);
if (typeof value === 'boolean')
@@ -806,7 +845,7 @@ function formatProperty(ctx, value, recurseTimes, key, array) {
const desc = Object.getOwnPropertyDescriptor(value, key) ||
{ value: value[key], enumerable: true };
if (desc.value !== undefined) {
- const diff = array === 0 ? 3 : 2;
+ const diff = array !== 0 || ctx.compact === false ? 2 : 3;
ctx.indentationLvl += diff;
str = formatValue(ctx, desc.value, recurseTimes, array === 0);
ctx.indentationLvl -= diff;
@@ -839,9 +878,19 @@ function formatProperty(ctx, value, recurseTimes, key, array) {
function reduceToSingleString(ctx, output, base, braces, addLn) {
const breakLength = ctx.breakLength;
+ var i = 0;
+ if (ctx.compact === false) {
+ const indentation = ' '.repeat(ctx.indentationLvl);
+ var res = `${base ? `${base} ` : ''}${braces[0]}\n${indentation} `;
+ for (; i < output.length - 1; i++) {
+ res += `${output[i]},\n${indentation} `;
+ }
+ res += `${output[i]}\n${indentation}${braces[1]}`;
+ return res;
+ }
if (output.length * 2 <= breakLength) {
var length = 0;
- for (var i = 0; i < output.length && length <= breakLength; i++) {
+ for (; i < output.length && length <= breakLength; i++) {
if (ctx.colors) {
length += removeColors(output[i]).length + 1;
} else {
@@ -849,7 +898,8 @@ function reduceToSingleString(ctx, output, base, braces, addLn) {
}
}
if (length <= breakLength)
- return `${braces[0]}${base} ${join(output, ', ')} ${braces[1]}`;
+ return `${braces[0]}${base ? ` ${base}` : ''} ${join(output, ', ')} ` +
+ braces[1];
}
// If the opening "brace" is too large, like in the case of "Set {",
// we need to force the first item to be on the next line or the
@@ -857,7 +907,7 @@ function reduceToSingleString(ctx, output, base, braces, addLn) {
const indentation = ' '.repeat(ctx.indentationLvl);
const extraLn = addLn === true ? `\n${indentation}` : '';
const ln = base === '' && braces[0].length === 1 ?
- ' ' : `${base}\n${indentation} `;
+ ' ' : `${base ? ` ${base}` : base}\n${indentation} `;
const str = join(output, `,\n${indentation} `);
return `${extraLn}${braces[0]}${ln}${str} ${braces[1]}`;
}
diff --git a/node.gyp b/node.gyp
index d85f6a491a9eea..1ab7b207e21339 100644
--- a/node.gyp
+++ b/node.gyp
@@ -142,6 +142,7 @@
'lib/internal/vm/Module.js',
'lib/internal/streams/lazy_transform.js',
'lib/internal/streams/BufferList.js',
+ 'lib/internal/streams/duplex_base.js',
'lib/internal/streams/legacy.js',
'lib/internal/streams/destroy.js',
'lib/internal/wrap_js_stream.js',
@@ -193,6 +194,9 @@
'sources': [
'src/node_main.cc'
],
+ 'includes': [
+ 'node.gypi'
+ ],
'include_dirs': [
'src',
'deps/v8/include',
@@ -210,9 +214,6 @@
}],
[ 'node_intermediate_lib_type=="static_library" and '
'node_shared=="false"', {
- 'includes': [
- 'node.gypi'
- ],
'xcode_settings': {
'OTHER_LDFLAGS': [
'-Wl,-force_load,<(PRODUCT_DIR)/<(STATIC_LIB_PREFIX)'
@@ -454,22 +455,8 @@
],
}],
],
- 'defines!': [
- 'NODE_PLATFORM="win"',
- ],
- 'defines': [
- 'FD_SETSIZE=1024',
- # we need to use node's preferred "win32" rather than gyp's preferred "win"
- 'NODE_PLATFORM="win32"',
- # Stop from defining macros that conflict with
- # std::min() and std::max(). We don't use (much)
- # but we still inherit it from uv.h.
- 'NOMINMAX',
- '_UNICODE=1',
- ],
'libraries': [ '-lpsapi.lib' ]
}, { # POSIX
- 'defines': [ '__POSIX__' ],
'sources': [ 'src/backtrace_posix.cc' ],
}],
[ 'node_use_etw=="true"', {
diff --git a/node.gypi b/node.gypi
index 852cc18eee7495..ac043dac2423ca 100644
--- a/node.gypi
+++ b/node.gypi
@@ -37,6 +37,24 @@
'NODE_SHARED_MODE',
],
}],
+ [ 'OS=="win"', {
+ 'defines!': [
+ 'NODE_PLATFORM="win"',
+ ],
+ 'defines': [
+ 'FD_SETSIZE=1024',
+ # we need to use node's preferred "win32" rather than gyp's preferred "win"
+ 'NODE_PLATFORM="win32"',
+ # Stop from defining macros that conflict with
+ # std::min() and std::max(). We don't use (much)
+ # but we still inherit it from uv.h.
+ 'NOMINMAX',
+ '_UNICODE=1',
+ ],
+ }, { # POSIX
+ 'defines': [ '__POSIX__' ],
+ }],
+
[ 'node_enable_d8=="true"', {
'dependencies': [ 'deps/v8/src/d8.gyp:d8' ],
}],
diff --git a/src/aliased_buffer.h b/src/aliased_buffer.h
index b99b01f5d94ca2..8b103f4949030c 100644
--- a/src/aliased_buffer.h
+++ b/src/aliased_buffer.h
@@ -141,6 +141,22 @@ class AliasedBuffer {
return aliased_buffer_->GetValue(index_);
}
+ template
+ inline Reference& operator+=(const T& val) {
+ const T current = aliased_buffer_->GetValue(index_);
+ aliased_buffer_->SetValue(index_, current + val);
+ return *this;
+ }
+
+ inline Reference& operator+=(const Reference& val) {
+ return this->operator+=(static_cast(val));
+ }
+
+ template
+ inline Reference& operator-=(const T& val) {
+ return this->operator+=(-val);
+ }
+
private:
AliasedBuffer* aliased_buffer_;
size_t index_;
diff --git a/src/async_wrap-inl.h b/src/async_wrap-inl.h
index cc6377d82a0fee..21b1f9cee9f0e8 100644
--- a/src/async_wrap-inl.h
+++ b/src/async_wrap-inl.h
@@ -64,6 +64,13 @@ inline v8::MaybeLocal AsyncWrap::MakeCallback(
return MakeCallback(cb_v.As(), argc, argv);
}
+
+// Defined here to avoid a circular dependency with env-inl.h.
+inline Environment::AsyncHooks::DefaultTriggerAsyncIdScope
+ ::DefaultTriggerAsyncIdScope(AsyncWrap* async_wrap)
+ : DefaultTriggerAsyncIdScope(async_wrap->env(),
+ async_wrap->get_async_id()) {}
+
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
diff --git a/src/async_wrap.cc b/src/async_wrap.cc
index cd9f26d7782d46..f85c8c7be6692f 100644
--- a/src/async_wrap.cc
+++ b/src/async_wrap.cc
@@ -23,13 +23,10 @@
#include "env-inl.h"
#include "util-inl.h"
-#include "uv.h"
#include "v8.h"
#include "v8-profiler.h"
-using v8::Array;
using v8::Context;
-using v8::Float64Array;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -48,7 +45,6 @@ using v8::PropertyCallbackInfo;
using v8::RetainedObjectInfo;
using v8::String;
using v8::Symbol;
-using v8::TryCatch;
using v8::Undefined;
using v8::Value;
@@ -166,19 +162,25 @@ static void DestroyAsyncIdsCallback(void* arg) {
}
-void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
+void Emit(Environment* env, double async_id, AsyncHooks::Fields type,
+ Local fn) {
AsyncHooks* async_hooks = env->async_hooks();
- if (async_hooks->fields()[AsyncHooks::kPromiseResolve] == 0)
+ if (async_hooks->fields()[type] == 0)
return;
Local async_id_value = Number::New(env->isolate(), async_id);
- Local fn = env->async_hooks_promise_resolve_function();
FatalTryCatch try_catch(env);
USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
}
+void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
+ Emit(env, async_id, AsyncHooks::kPromiseResolve,
+ env->async_hooks_promise_resolve_function());
+}
+
+
void AsyncWrap::EmitTraceEventBefore() {
switch (provider_type()) {
#define V(PROVIDER) \
@@ -195,15 +197,8 @@ void AsyncWrap::EmitTraceEventBefore() {
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
- AsyncHooks* async_hooks = env->async_hooks();
-
- if (async_hooks->fields()[AsyncHooks::kBefore] == 0)
- return;
-
- Local async_id_value = Number::New(env->isolate(), async_id);
- Local fn = env->async_hooks_before_function();
- FatalTryCatch try_catch(env);
- USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
+ Emit(env, async_id, AsyncHooks::kBefore,
+ env->async_hooks_before_function());
}
@@ -223,23 +218,16 @@ void AsyncWrap::EmitTraceEventAfter() {
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
- AsyncHooks* async_hooks = env->async_hooks();
-
- if (async_hooks->fields()[AsyncHooks::kAfter] == 0)
- return;
-
// If the user's callback failed then the after() hooks will be called at the
// end of _fatalException().
- Local async_id_value = Number::New(env->isolate(), async_id);
- Local fn = env->async_hooks_after_function();
- FatalTryCatch try_catch(env);
- USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
+ Emit(env, async_id, AsyncHooks::kAfter,
+ env->async_hooks_after_function());
}
class PromiseWrap : public AsyncWrap {
public:
PromiseWrap(Environment* env, Local